@pnp/generator-spfx
Version:
This Yeoman generator helps organisations to improve their development workflow with the SharePoint Framework. It extends the functionalities of the @microsoft/generator-sharepoint based on best pattern and practices. This generator extends the capabiliti
285 lines (205 loc) • 8.8 kB
JavaScript
;
// Base Yeoman generator
const Generator = require('yeoman-generator');
// filesystem
const fs = require('fs');
const path = require('path');
const glob = require('glob');
const paramCase = require('param-case').paramCase;
// importing utilities
const util = require('../../lib/util.js');
const readmeInfo = {
libraryName: '', // Placeholder for project name
techStack: 'This project uses [Angular Elements](https://angular.io/guide/elements).'
};
module.exports = class extends Generator {
constructor(args, opts) {
super(args, opts);
}
// Initialisation geenerator
initializing() {
}
// Prompt for user input for Custom Generator
prompting() {
}
// adds additonal editor support in this case CSS Comb
configuring() {
}
//use to update warning size
_updateAngularJSON() {
if (fs.existsSync(this.destinationPath('angular.json'))) {
let angularConfig;
try {
angularConfig = JSON.parse(fs.readFileSync(
this.destinationPath('angular.json')
));
} catch (error) {
throw error;
}
}
}
// adds dependencies to the package.json
_addPackageDependencies() {
if (fs.existsSync(this.destinationPath('package.json'))) {
// request the spfx default package file
let spfxConfig;
try {
spfxConfig = JSON.parse(fs.readFileSync(
this.destinationPath('package.json')
));
} catch (error) {
throw error;
}
let solutionName = this.options.solutionName;
const spfxSolutionPath = this.destinationPath(`../${solutionName}-spfx`);
spfxConfig.dependencies[paramCase(solutionName)] = `file:../${solutionName}`;
fs.writeFileSync(
path.join(spfxSolutionPath, 'package.json'),
JSON.stringify(spfxConfig, null, 2));
}
}
writing() {}
install() {
this._addPackageDependencies();
const manifest = util.getComponentManifest(this);
if (!manifest) {
return;
}
const angularSolutionName = this.options['solutionName'];
const angularCliOptionsRaw = this.options['angularCliOptions'].split(' ');
const angularSolutionPath = this.destinationPath(`../${angularSolutionName}`);
let angularCliOptions = [];
angularCliOptions.push('new');
angularCliOptions.push(angularSolutionName);
angularCliOptions.push(...angularCliOptionsRaw);
// ORIGINAL: this.spawnCommandSync(`ng new ${angularSolutionName} ${angularCliOptions}`, angularCliOptions, {cwd: path.dirname(angularSolutionPath)});
this.spawnCommandSync('ng', angularCliOptions, {
cwd: path.dirname(angularSolutionPath)
});
const ngVersion = require('@angular/cli/package.json');
const generateComponentOptions = [];
generateComponentOptions.push('generate');
generateComponentOptions.push('component');
generateComponentOptions.push(manifest.componentClassName);
generateComponentOptions.push('--viewEncapsulation=Emulated');
/** Entry Components are Deprecated in Angular 9 */
if(ngVersion.version && parseFloat(ngVersion.version) < 9){
generateComponentOptions.push('--entry-component=true');
}
// ORIGINAME this.spawnCommandSync(`ng generate component ${manifest.componentClassName} -v Native --entry-component`, [], {cwd: angularSolutionPath});
this.spawnCommandSync('ng', generateComponentOptions, {
cwd: angularSolutionPath
});
// Move Angular 8 back to ES5
if (ngVersion.version !== undefined &&
ngVersion.version.startsWith("8")) {
const tsconfig = JSON.parse(
fs.readFileSync(
path.join(angularSolutionPath, 'tsconfig.json'), 'utf-8')
);
// Set compiler options to ES5
tsconfig.compilerOptions.target = "es5";
// Save changed tsconfig
fs.writeFileSync(
path.join(angularSolutionPath, 'tsconfig.json'),
JSON.stringify(tsconfig, null, 2)
)
}
//read 'angular.json'
const angularJSON = JSON.parse(
fs.readFileSync(
path.join(angularSolutionPath, 'angular.json'), 'utf-8')
);
const projectName = angularJSON.defaultProject;
const budgets = angularJSON.projects[projectName].architect.build.configurations.production.budgets;
const initialBudgets = budgets.find(f => f.type === "initial");
//Set initial budgets warning and error
if (initialBudgets) {
initialBudgets.maximumWarning = '2mb';
initialBudgets.maximumError = '5mb';
}
// Save changed angular.json
fs.writeFileSync(
path.join(angularSolutionPath, 'angular.json'),
JSON.stringify(angularJSON, null, 2));
const pkg = JSON.parse(
fs.readFileSync(
path.join(angularSolutionPath, 'package.json'), 'utf-8')
);
//added --optimization=false to solve the issue of over minification of angular element bundle
pkg.scripts['bundle'] = 'ng build --output-hashing none --optimization=false --single-bundle --source-map';
pkg.dependencies['concat'] = '^1.0.3';
pkg.dependencies['@webcomponents/custom-elements'] = '^1.2.0';
pkg.dependencies['@webcomponents/webcomponentsjs'] = '^2.1.2';
pkg.devDependencies['typescript'] = '~4.4.2';
fs.writeFileSync(
path.join(angularSolutionPath, 'package.json'),
JSON.stringify(pkg, null, 2));
const ejsInject = {
angularSolutionName: angularSolutionName,
angularSolutionNameKebabCase: paramCase(angularSolutionName),
componentClassName: manifest.componentClassName,
componentClassNameKebabCase: paramCase(manifest.componentClassName),
ngVersion: ngVersion.version
};
util.deployTemplatesToPath(this, ejsInject, this.templatePath('./angular'), angularSolutionPath);
fs.appendFileSync(
path.join(angularSolutionPath, 'src/polyfills.ts'),
`import '@webcomponents/custom-elements/src/native-shim';\r\n`
);
const files = glob.sync(path.join(angularSolutionPath, 'src/app/app.component.*'));
for (let file of files) {
fs.unlinkSync(file);
}
// Unlink style sheet from component
const componentStyleSheet = manifest.componentMainFile.replace('.ts', '.module.scss');
if (fs.existsSync(componentStyleSheet)) {
fs.unlinkSync(manifest.componentMainFile.replace('.ts', '.module.scss'));
}
// Update add templates
util.deployTemplates(this, ejsInject);
// finally run install
if (!this.options.SpfxOptions['testrun']) {
const polyfills = this.fs.read(
this.templatePath('angular/src/polyfills.ts'),
'utf-8');
fs.writeFileSync(
path.join(angularSolutionPath, 'src/polyfills.ts'),
polyfills
)
const browserslist = this.fs.read(
this.templatePath('angular/src/browserslist'),
'utf-8');
fs.writeFileSync(
path.join(angularSolutionPath, 'src/browserslist'),
browserslist
)
this.spawnCommandSync('ng', ['add', '@angular/elements'], {
cwd: angularSolutionPath
});
this.spawnCommandSync('ng', ['add', 'ngx-build-plus'], {
cwd: angularSolutionPath
});
this.spawnCommandSync('npm', ['install'], {
cwd: angularSolutionPath
});
this.spawnCommandSync('npm', ['run', 'bundle'], {
cwd: angularSolutionPath
});
this.spawnCommand('npm', ['install'], {
cwd: angularSolutionPath + '-spfx'
})
// this.spawnCommand('npm', ['install', `../${angularSolutionName}`], {
// cwd: angularSolutionPath + '-spfx'
// })
}
// Updated Readme info
util.updateReadmeFile(this, readmeInfo);
// run SPFx install
util.runInstall(this);
}
// Run installer normally time to say goodbye
// If yarn is installed yarn will be used
end() {
}
}