244 lines
6.7 KiB
TypeScript
244 lines
6.7 KiB
TypeScript
import {
|
|
addProjectConfiguration,
|
|
convertNxGenerator,
|
|
formatFiles,
|
|
generateFiles,
|
|
getWorkspaceLayout,
|
|
joinPathFragments,
|
|
names,
|
|
NxJsonProjectConfiguration,
|
|
offsetFromRoot,
|
|
ProjectConfiguration,
|
|
readWorkspaceConfiguration,
|
|
TargetConfiguration,
|
|
Tree,
|
|
updateWorkspaceConfiguration,
|
|
} from '@nrwl/devkit';
|
|
|
|
import { join } from 'path';
|
|
|
|
import { webInitGenerator } from '../init/init';
|
|
import { cypressProjectGenerator } from '@nrwl/cypress';
|
|
import { Linter, lintProjectGenerator } from '@nrwl/linter';
|
|
import { jestProjectGenerator } from '@nrwl/jest';
|
|
|
|
import { WebBuildBuilderOptions } from '../../builders/build/build.impl';
|
|
import { Schema } from './schema';
|
|
|
|
interface NormalizedSchema extends Schema {
|
|
projectName: string;
|
|
appProjectRoot: string;
|
|
e2eProjectName: string;
|
|
e2eProjectRoot: string;
|
|
parsedTags: string[];
|
|
}
|
|
|
|
function createApplicationFiles(tree: Tree, options: NormalizedSchema) {
|
|
generateFiles(tree, join(__dirname, './files/app'), options.appProjectRoot, {
|
|
...options,
|
|
...names(options.name),
|
|
tmpl: '',
|
|
offsetFromRoot: offsetFromRoot(options.appProjectRoot),
|
|
});
|
|
if (options.unitTestRunner === 'none') {
|
|
tree.delete(join(options.appProjectRoot, './src/app/app.element.spec.ts'));
|
|
}
|
|
}
|
|
|
|
function addBuildTarget(
|
|
project: ProjectConfiguration,
|
|
options: NormalizedSchema
|
|
): ProjectConfiguration {
|
|
const buildOptions: WebBuildBuilderOptions = {
|
|
outputPath: joinPathFragments('dist', options.appProjectRoot),
|
|
index: joinPathFragments(options.appProjectRoot, 'src/index.html'),
|
|
main: joinPathFragments(options.appProjectRoot, 'src/main.ts'),
|
|
polyfills: joinPathFragments(options.appProjectRoot, 'src/polyfills.ts'),
|
|
tsConfig: joinPathFragments(options.appProjectRoot, 'tsconfig.app.json'),
|
|
assets: [
|
|
joinPathFragments(options.appProjectRoot, 'src/favicon.ico'),
|
|
joinPathFragments(options.appProjectRoot, 'src/assets'),
|
|
],
|
|
styles: [
|
|
joinPathFragments(options.appProjectRoot, `src/styles.${options.style}`),
|
|
],
|
|
scripts: [],
|
|
};
|
|
const productionBuildOptions: Partial<WebBuildBuilderOptions> = {
|
|
fileReplacements: [
|
|
{
|
|
replace: joinPathFragments(
|
|
options.appProjectRoot,
|
|
`src/environments/environment.ts`
|
|
),
|
|
with: joinPathFragments(
|
|
options.appProjectRoot,
|
|
`src/environments/environment.prod.ts`
|
|
),
|
|
},
|
|
],
|
|
optimization: true,
|
|
outputHashing: 'all',
|
|
sourceMap: false,
|
|
extractCss: true,
|
|
namedChunks: false,
|
|
extractLicenses: true,
|
|
vendorChunk: false,
|
|
budgets: [
|
|
{
|
|
type: 'initial',
|
|
maximumWarning: '2mb',
|
|
maximumError: '5mb',
|
|
},
|
|
],
|
|
};
|
|
|
|
return {
|
|
...project,
|
|
targets: {
|
|
...project.targets,
|
|
build: {
|
|
executor: '@nrwl/web:build',
|
|
outputs: ['{options.outputPath}'],
|
|
options: buildOptions,
|
|
configurations: {
|
|
production: productionBuildOptions,
|
|
},
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
function addServeTarget(
|
|
project: ProjectConfiguration,
|
|
options: NormalizedSchema
|
|
) {
|
|
const serveTarget: TargetConfiguration = {
|
|
executor: '@nrwl/web:dev-server',
|
|
options: {
|
|
buildTarget: `${options.projectName}:build`,
|
|
},
|
|
configurations: {
|
|
production: {
|
|
buildTarget: `${options.projectName}:build:production`,
|
|
},
|
|
},
|
|
};
|
|
|
|
return {
|
|
...project,
|
|
targets: {
|
|
...project.targets,
|
|
serve: serveTarget,
|
|
},
|
|
};
|
|
}
|
|
|
|
function addProject(tree: Tree, options: NormalizedSchema) {
|
|
const targets: Record<string, TargetConfiguration> = {};
|
|
let project: ProjectConfiguration & NxJsonProjectConfiguration = {
|
|
projectType: 'application',
|
|
root: options.appProjectRoot,
|
|
sourceRoot: joinPathFragments(options.appProjectRoot, 'src'),
|
|
tags: options.parsedTags,
|
|
targets,
|
|
};
|
|
|
|
project = addBuildTarget(project, options);
|
|
project = addServeTarget(project, options);
|
|
|
|
addProjectConfiguration(tree, options.projectName, project);
|
|
|
|
const workspace = readWorkspaceConfiguration(tree);
|
|
|
|
if (!workspace.defaultProject) {
|
|
workspace.defaultProject = options.projectName;
|
|
|
|
updateWorkspaceConfiguration(tree, workspace);
|
|
}
|
|
}
|
|
|
|
export async function applicationGenerator(host: Tree, schema: Schema) {
|
|
const options = normalizeOptions(host, schema);
|
|
|
|
let installTask = await webInitGenerator(host, {
|
|
...options,
|
|
skipFormat: true,
|
|
});
|
|
|
|
createApplicationFiles(host, options);
|
|
addProject(host, options);
|
|
|
|
const lintInstallTask = await lintProjectGenerator(host, {
|
|
linter: options.linter,
|
|
project: options.projectName,
|
|
tsConfigPaths: [
|
|
joinPathFragments(options.appProjectRoot, 'tsconfig.app.json'),
|
|
],
|
|
eslintFilePatterns: [`${options.appProjectRoot}/**/*.ts`],
|
|
skipFormat: true,
|
|
});
|
|
installTask = lintInstallTask || installTask;
|
|
|
|
if (options.e2eTestRunner === 'cypress') {
|
|
const cypressInstallTask = await cypressProjectGenerator(host, {
|
|
...options,
|
|
name: options.name + '-e2e',
|
|
directory: options.directory,
|
|
project: options.projectName,
|
|
});
|
|
installTask = cypressInstallTask || installTask;
|
|
}
|
|
if (options.unitTestRunner === 'jest') {
|
|
const jestInstallTask = await jestProjectGenerator(host, {
|
|
project: options.projectName,
|
|
skipSerializers: true,
|
|
setupFile: 'web-components',
|
|
babelJest: options.babelJest,
|
|
});
|
|
installTask = jestInstallTask || installTask;
|
|
}
|
|
|
|
if (!schema.skipFormat) {
|
|
await formatFiles(host);
|
|
}
|
|
return installTask;
|
|
}
|
|
|
|
function normalizeOptions(host: Tree, options: Schema): NormalizedSchema {
|
|
const appDirectory = options.directory
|
|
? `${names(options.directory).fileName}/${names(options.name).fileName}`
|
|
: names(options.name).fileName;
|
|
|
|
const { appsDir, npmScope: defaultPrefix } = getWorkspaceLayout(host);
|
|
|
|
const appProjectName = appDirectory.replace(new RegExp('/', 'g'), '-');
|
|
const e2eProjectName = `${appProjectName}-e2e`;
|
|
|
|
const appProjectRoot = `${appsDir}/${appDirectory}`;
|
|
const e2eProjectRoot = `${appsDir}/${appDirectory}-e2e`;
|
|
|
|
const parsedTags = options.tags
|
|
? options.tags.split(',').map((s) => s.trim())
|
|
: [];
|
|
|
|
options.style = options.style || 'css';
|
|
options.linter = options.linter || Linter.EsLint;
|
|
options.unitTestRunner = options.unitTestRunner || 'jest';
|
|
options.e2eTestRunner = options.e2eTestRunner || 'cypress';
|
|
|
|
return {
|
|
...options,
|
|
prefix: options.prefix ? options.prefix : defaultPrefix,
|
|
name: names(options.name).fileName,
|
|
projectName: appProjectName,
|
|
appProjectRoot,
|
|
e2eProjectRoot,
|
|
e2eProjectName,
|
|
parsedTags,
|
|
};
|
|
}
|
|
|
|
export default applicationGenerator;
|
|
export const applicationSchematic = convertNxGenerator(applicationGenerator);
|