@nx/angular
Version:
379 lines (378 loc) • 17.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AppMigrator = void 0;
const devkit_1 = require("@nx/devkit");
const js_1 = require("@nx/js");
const path_1 = require("path");
const utilities_1 = require("../../utilities");
const builders_1 = require("../builders");
const e2e_migrator_1 = require("./e2e.migrator");
const project_migrator_1 = require("./project.migrator");
const supportedTargets = {
build: {
builders: [
'@angular/build:application',
'@angular-devkit/build-angular:application',
'@angular-devkit/build-angular:browser',
'@angular-devkit/build-angular:browser-esbuild',
],
},
e2e: {
acceptMultipleDefinitions: true,
builders: [
'@angular-devkit/build-angular:protractor',
'@cypress/schematic:cypress',
],
},
i18n: {
builders: [
'@angular/build:extract-i18n',
'@angular-devkit/build-angular:extract-i18n',
],
},
prerender: {
builders: [
'@nguniversal/builders:prerender',
'@angular-devkit/build-angular:prerender',
],
},
serve: {
builders: [
'@angular/build:dev-server',
'@angular-devkit/build-angular:dev-server',
],
},
server: { builders: ['@angular-devkit/build-angular:server'] },
serveSsr: {
builders: [
'@nguniversal/builders:ssr-dev-server',
'@angular-devkit/build-angular:ssr-dev-server',
],
},
};
// TODO(leo): this will replace `supportedTargets` once the full refactor is done.
const supportedBuilderMigrators = [
builders_1.AngularBuildUnitTestMigrator,
builders_1.AngularDevkitKarmaMigrator,
builders_1.AngularEslintLintMigrator,
];
class AppMigrator extends project_migrator_1.ProjectMigrator {
constructor(tree, options, project, logger) {
super(tree, options, supportedTargets, project, 'apps', logger, supportedBuilderMigrators);
const eslintBuilderMigrator = this.builderMigrators[supportedBuilderMigrators.indexOf(builders_1.AngularEslintLintMigrator)];
this.e2eMigrator = new e2e_migrator_1.E2eMigrator(tree, options, project, eslintBuilderMigrator.targets.size
? Object.keys(eslintBuilderMigrator.targets)[0]
: undefined);
}
async migrate() {
await super.migrate();
if (this.skipMigration === true) {
return;
}
this.updateProjectConfiguration();
await this.e2eMigrator.migrate();
this.moveProjectFiles();
this.updateProjectConfigurationTargets();
for (const builderMigrator of this.builderMigrators ?? []) {
await builderMigrator.migrate();
}
this.updateTsConfigs();
this.setCacheableOperations();
}
validate() {
const errors = [
...(super.validate() ?? []),
...(this.e2eMigrator.validate() ?? []),
];
for (const builderMigrator of this.builderMigrators) {
errors.push(...(builderMigrator.validate() ?? []));
}
return errors.length ? errors : null;
}
moveProjectFiles() {
// project is self-contained and can be safely moved
if (this.project.oldRoot !== '') {
this.moveDir(this.project.oldRoot, this.project.newRoot);
return;
}
// we need to pick what to move because the project is in the workspace root
// it is not required to have a browserslist
this.moveProjectRootFile('browserslist', false);
this.moveProjectRootFile('.browserslistrc', false);
if (this.targetNames.build) {
this.moveFilePathsFromTargetToProjectRoot(this.projectConfig.targets[this.targetNames.build], ['tsConfig', 'webWorkerTsConfig', 'ngswConfigPath']);
}
if (this.targetNames.server) {
this.moveFilePathsFromTargetToProjectRoot(this.projectConfig.targets[this.targetNames.server], ['tsConfig']);
}
this.moveDir(this.project.oldSourceRoot, this.project.newSourceRoot);
}
setCacheableOperations() {
const toCache = [];
if (this.targetNames.build &&
!this.shouldSkipTargetTypeMigration('build')) {
toCache.push(this.targetNames.build);
}
if (this.targetNames.e2e && !this.shouldSkipTargetTypeMigration('e2e')) {
toCache.push(this.targetNames.e2e);
}
if (toCache.length) {
this.updateCacheableOperations(toCache);
}
}
updateProjectConfiguration() {
(0, utilities_1.convertToNxProject)(this.tree, this.project.name);
this.moveFile((0, devkit_1.joinPathFragments)(this.project.oldRoot, 'project.json'), (0, devkit_1.joinPathFragments)(this.project.newRoot, 'project.json'));
this.projectConfig.root = this.project.newRoot;
this.projectConfig.sourceRoot = this.project.newSourceRoot;
(0, devkit_1.updateProjectConfiguration)(this.tree, this.project.name, {
...this.projectConfig,
});
}
updateProjectConfigurationTargets() {
if (!this.projectConfig.targets ||
!Object.keys(this.projectConfig.targets).length) {
this.logger.warn('The project does not have any targets configured. Skipping updating targets.');
return;
}
this.updateBuildTargetConfiguration();
this.updateServerTargetConfiguration();
this.updatePrerenderTargetConfiguration();
this.updateServeSsrTargetConfiguration();
(0, devkit_1.updateProjectConfiguration)(this.tree, this.project.name, {
...this.projectConfig,
});
}
updateTsConfigs() {
const rootTsConfigFile = (0, js_1.getRootTsConfigPathInTree)(this.tree);
const projectOffsetFromRoot = (0, devkit_1.offsetFromRoot)(this.projectConfig.root);
this.updateTsConfigFileUsedByBuildTarget(rootTsConfigFile, projectOffsetFromRoot);
this.updateTsConfigFileUsedByServerTarget(projectOffsetFromRoot);
}
convertBuildOptions(buildOptions, target, updateOutputs = true) {
const { executor } = target;
const isApplicationBuilder = executor === '@angular/build:application' ||
executor === '@angular-devkit/build-angular:application';
if (updateOutputs) {
if (buildOptions.outputPath) {
if (isApplicationBuilder) {
if (typeof buildOptions.outputPath === 'string') {
buildOptions.outputPath = (0, devkit_1.joinPathFragments)('dist', this.project.newRoot);
}
else if (buildOptions.outputPath.base) {
buildOptions.outputPath.base = (0, devkit_1.joinPathFragments)('dist', this.project.newRoot);
}
}
else {
buildOptions.outputPath = (0, devkit_1.joinPathFragments)('dist', this.project.newRoot, this.targetNames.server ? 'browser' : '');
}
}
else if (isApplicationBuilder) {
buildOptions.outputPath = (0, devkit_1.joinPathFragments)('dist', this.projectName);
}
if (typeof buildOptions.outputPath === 'string') {
target.outputs = ['{options.outputPath}'];
}
else if (buildOptions.outputPath?.base) {
target.outputs = ['{options.outputPath.base}'];
}
}
if (buildOptions.index) {
if (typeof buildOptions.index === 'string') {
buildOptions.index = this.convertAsset(buildOptions.index);
}
else {
buildOptions.index.input =
buildOptions.index.input &&
this.convertAsset(buildOptions.index.input);
}
}
buildOptions.main =
buildOptions.main && this.convertAsset(buildOptions.main);
buildOptions.browser =
buildOptions.browser && this.convertAsset(buildOptions.browser);
buildOptions.server =
buildOptions.server && this.convertAsset(buildOptions.server);
buildOptions.polyfills =
buildOptions.polyfills &&
(Array.isArray(buildOptions.polyfills)
? buildOptions.polyfills.map((asset) => this.convertSourceRootPath(asset))
: this.convertSourceRootPath(buildOptions.polyfills));
buildOptions.tsConfig =
buildOptions.tsConfig &&
(0, devkit_1.joinPathFragments)(this.project.newRoot, (0, path_1.basename)(buildOptions.tsConfig));
buildOptions.assets =
buildOptions.assets &&
buildOptions.assets.map((asset) => this.convertAsset(asset));
buildOptions.styles =
buildOptions.styles &&
buildOptions.styles.map((style) => this.convertAsset(style));
buildOptions.scripts =
buildOptions.scripts &&
buildOptions.scripts.map((script) => this.convertAsset(script));
buildOptions.fileReplacements =
buildOptions.fileReplacements &&
buildOptions.fileReplacements.map((replacement) => ({
replace: this.convertAsset(replacement.replace),
with: this.convertAsset(replacement.with),
}));
buildOptions.serviceWorker =
buildOptions.serviceWorker &&
typeof buildOptions.serviceWorker === 'string' &&
this.convertAsset(buildOptions.serviceWorker);
buildOptions.ngswConfigPath =
buildOptions.ngswConfigPath &&
this.convertAsset(buildOptions.ngswConfigPath);
if (buildOptions.prerender?.routesFile) {
buildOptions.prerender.routesFile = this.convertAsset(buildOptions.prerender.routesFile);
}
buildOptions.ssr =
buildOptions.ssr &&
typeof buildOptions.ssr === 'string' &&
this.convertAsset(buildOptions.ssr);
}
convertServerOptions(serverOptions) {
serverOptions.outputPath =
serverOptions.outputPath &&
(0, devkit_1.joinPathFragments)('dist', this.project.newRoot, 'server');
serverOptions.main =
serverOptions.main && this.convertPath(serverOptions.main);
serverOptions.tsConfig =
serverOptions.tsConfig &&
(0, devkit_1.joinPathFragments)(this.project.newRoot, (0, path_1.basename)(serverOptions.tsConfig));
serverOptions.fileReplacements =
serverOptions.fileReplacements &&
serverOptions.fileReplacements.map((replacement) => ({
replace: this.convertAsset(replacement.replace),
with: this.convertAsset(replacement.with),
}));
}
updateBuildTargetConfiguration() {
if (!this.targetNames.build) {
this.logger.warn('There is no build target in the project configuration. Skipping updating the build target configuration.');
return;
}
if (this.shouldSkipTargetTypeMigration('build')) {
return;
}
const buildTarget = this.projectConfig.targets[this.targetNames.build];
if (!buildTarget.options &&
(!buildTarget.configurations ||
!Object.keys(buildTarget.configurations).length)) {
this.logger.warn(`The target "${this.targetNames.build}" is not specifying any options or configurations. Skipping updating the target configuration.`);
return;
}
const buildDevTsConfig = buildTarget.options?.tsConfig ??
buildTarget.configurations?.development?.tsConfig;
if (!buildDevTsConfig) {
this.logger.warn(`The "${this.targetNames.build}" target does not have the "tsConfig" option configured. Skipping updating the tsConfig file.`);
}
else {
const newBuildDevTsConfig = this.convertPath(buildDevTsConfig);
if (!this.tree.exists(newBuildDevTsConfig)) {
this.logger.warn(`The tsConfig file "${buildDevTsConfig}" specified in the "${this.targetNames.build}" target could not be found. Skipping updating the tsConfig file.`);
}
}
this.convertBuildOptions(buildTarget.options ?? {}, buildTarget);
Object.values(buildTarget.configurations ?? {}).forEach((config) => this.convertBuildOptions(config, buildTarget, false));
}
updatePrerenderTargetConfiguration() {
if (!this.targetNames.prerender ||
this.shouldSkipTargetTypeMigration('prerender')) {
return;
}
const prerenderTarget = this.projectConfig.targets[this.targetNames.prerender];
if (!prerenderTarget.options) {
this.logger.warn(`The target "${this.targetNames.prerender}" is not specifying any options. Skipping updating the target configuration.`);
return;
}
prerenderTarget.options.routesFile =
prerenderTarget.options.routesFile &&
this.convertPath(prerenderTarget.options.routesFile);
}
updateServerTargetConfiguration() {
if (!this.targetNames.server ||
this.shouldSkipTargetTypeMigration('server')) {
return;
}
const serverTarget = this.projectConfig.targets[this.targetNames.server];
if (!serverTarget.options &&
(!serverTarget.configurations ||
!Object.keys(serverTarget.configurations).length)) {
this.logger.warn(`The target "${this.targetNames.server}" is not specifying any options or configurations. Skipping updating the target configuration.`);
return;
}
const serverDevTsConfig = serverTarget.options?.tsConfig ??
serverTarget.configurations?.development?.tsConfig;
if (!serverDevTsConfig) {
this.logger.warn(`The "${this.targetNames.server}" target does not have the "tsConfig" option configured. Skipping updating the tsConfig file.`);
}
else {
const newServerDevTsConfig = this.convertPath(serverDevTsConfig);
if (!this.tree.exists(newServerDevTsConfig)) {
this.logger.warn(`The tsConfig file "${serverDevTsConfig}" specified in the "${this.targetNames.server}" target could not be found. Skipping updating the tsConfig file.`);
}
}
this.convertServerOptions(serverTarget.options ?? {});
Object.values(serverTarget.configurations ?? {}).forEach((config) => this.convertServerOptions(config));
}
updateServeSsrTargetConfiguration() {
if (!this.targetNames.serveSsr ||
this.shouldSkipTargetTypeMigration('serveSsr')) {
return;
}
const ssrTarget = this.targetNames.serveSsr ?? this.targetNames['serve-ssr'];
const serveSsrTarget = this.projectConfig.targets[ssrTarget];
if (!serveSsrTarget.options &&
(!serveSsrTarget.configurations ||
!Object.keys(serveSsrTarget.configurations).length)) {
this.logger.warn(`The target "${ssrTarget}" is not specifying any options or configurations. Skipping updating the target configuration.`);
return;
}
['sslKey', 'sslCert', 'proxyConfig'].forEach((option) => {
if (serveSsrTarget.options) {
serveSsrTarget.options[option] =
serveSsrTarget.options[option] &&
this.convertPath(serveSsrTarget.options[option]);
}
for (const configuration of Object.values(serveSsrTarget.configurations ?? {})) {
serveSsrTarget.configurations[configuration][option] =
serveSsrTarget.configurations[configuration][option] &&
this.convertPath(serveSsrTarget.configurations[configuration][option]);
}
});
}
updateTsConfigFileUsedByBuildTarget(rootTsConfigFile, projectOffsetFromRoot) {
if (!this.targetNames.build ||
this.shouldSkipTargetTypeMigration('build')) {
return;
}
const tsConfigPath = this.projectConfig.targets[this.targetNames.build].options?.tsConfig ??
this.projectConfig.targets[this.targetNames.build].configurations
?.development?.tsConfig;
if (!tsConfigPath || !this.tree.exists(tsConfigPath)) {
// we already logged a warning for these cases, so just return
return;
}
this.updateTsConfigFile(tsConfigPath, rootTsConfigFile, projectOffsetFromRoot);
}
updateTsConfigFileUsedByServerTarget(projectOffsetFromRoot) {
if (!this.targetNames.server ||
this.shouldSkipTargetTypeMigration('server')) {
return;
}
const tsConfigPath = this.projectConfig.targets[this.targetNames.server].options?.tsConfig ??
this.projectConfig.targets[this.targetNames.server].configurations
?.development?.tsConfig;
if (!tsConfigPath || !this.tree.exists(tsConfigPath)) {
// we already logged a warning for these cases, so just return
return;
}
(0, devkit_1.updateJson)(this.tree, tsConfigPath, (json) => {
json.compilerOptions = json.compilerOptions ?? {};
json.compilerOptions.outDir = `${projectOffsetFromRoot}dist/out-tsc`;
return json;
});
}
}
exports.AppMigrator = AppMigrator;