Skip to content

Commit

Permalink
fix(@schematics/angular): do not add unnecessary dependency on `@angu…
Browse files Browse the repository at this point in the history
…lar/ssr` during migration

Prior to this change the Universal migration ran and added `@angular/ssr` even the workspace did not depend on `@nguniversal/` packages.

Closes #26083

(cherry picked from commit c07cbd5)
  • Loading branch information
alan-agius4 committed Oct 23, 2023
1 parent dbdc7b2 commit 1759446
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import { DirEntry, Rule, chain } from '@angular-devkit/schematics';
import { addDependency } from '../../utility';
import { removePackageJsonDependency } from '../../utility/dependencies';
import { getPackageJsonDependency, removePackageJsonDependency } from '../../utility/dependencies';
import { latestVersions } from '../../utility/latest-versions';
import { allTargetOptions, getWorkspace } from '../../utility/workspace';
import { Builders, ProjectType } from '../../utility/workspace-models';
Expand Down Expand Up @@ -36,6 +36,8 @@ function* visit(directory: DirEntry): IterableIterator<[fileName: string, conten
}
}

const UNIVERSAL_PACKAGES = ['@nguniversal/common', '@nguniversal/express-engine'];

/**
* Regexp to match Universal packages.
* @nguniversal/common/engine
Expand All @@ -45,53 +47,61 @@ function* visit(directory: DirEntry): IterableIterator<[fileName: string, conten
const NGUNIVERSAL_PACKAGE_REGEXP = /@nguniversal\/(common(\/engine)?|express-engine)/g;

export default function (): Rule {
return chain([
async (tree) => {
// Replace server file.
const workspace = await getWorkspace(tree);
for (const [, project] of workspace.projects) {
if (project.extensions.projectType !== ProjectType.Application) {
continue;
}
return async (tree) => {
const hasUniversalDeps = UNIVERSAL_PACKAGES.some((d) => getPackageJsonDependency(tree, d));
if (!hasUniversalDeps) {
return;
}

const serverMainFiles = new Map<string /** Main Path */, string /** Output Path */>();
for (const [, target] of project.targets) {
if (target.builder !== Builders.Server) {
return chain([
async (tree) => {
// Replace server file.
const workspace = await getWorkspace(tree);
for (const [, project] of workspace.projects) {
if (project.extensions.projectType !== ProjectType.Application) {
continue;
}

const outputPath = project.targets.get('build')?.options?.outputPath;
const serverMainFiles = new Map<string /** Main Path */, string /** Output Path */>();
for (const [, target] of project.targets) {
if (target.builder !== Builders.Server) {
continue;
}

const outputPath = project.targets.get('build')?.options?.outputPath;

for (const [, { main }] of allTargetOptions(target, false)) {
if (
typeof main === 'string' &&
typeof outputPath === 'string' &&
tree.readText(main).includes('ngExpressEngine')
) {
serverMainFiles.set(main, outputPath);
for (const [, { main }] of allTargetOptions(target, false)) {
if (
typeof main === 'string' &&
typeof outputPath === 'string' &&
tree.readText(main).includes('ngExpressEngine')
) {
serverMainFiles.set(main, outputPath);
}
}
}
}

// Replace server file
for (const [path, outputPath] of serverMainFiles.entries()) {
tree.rename(path, path + '.bak');
tree.create(path, getServerFileContents(outputPath));
// Replace server file
for (const [path, outputPath] of serverMainFiles.entries()) {
tree.rename(path, path + '.bak');
tree.create(path, getServerFileContents(outputPath));
}
}
}

// Replace all import specifiers in all files.
for (const file of visit(tree.root)) {
const [path, content] = file;
tree.overwrite(path, content.replaceAll(NGUNIVERSAL_PACKAGE_REGEXP, '@angular/ssr'));
}
// Replace all import specifiers in all files.
for (const file of visit(tree.root)) {
const [path, content] = file;
tree.overwrite(path, content.replaceAll(NGUNIVERSAL_PACKAGE_REGEXP, '@angular/ssr'));
}

// Remove universal packages from deps.
removePackageJsonDependency(tree, '@nguniversal/express-engine');
removePackageJsonDependency(tree, '@nguniversal/common');
},
addDependency('@angular/ssr', latestVersions.AngularSSR),
]);
// Remove universal packages from deps.
for (const name of UNIVERSAL_PACKAGES) {
removePackageJsonDependency(tree, name);
}
},
addDependency('@angular/ssr', latestVersions.AngularSSR),
]);
};
}

function getServerFileContents(outputPath: string): string {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,25 @@ if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
expect(dependencies['@angular/ssr']).toBeDefined();
});

it(`should not add '@angular/ssr' when there is no dependency on '@nguniversal'`, async () => {
tree.overwrite(
'/package.json',
JSON.stringify(
{
dependencies: {
'@angular/common': '0.0.0',
},
},
undefined,
2,
),
);

const newTree = await schematicRunner.runSchematic(schematicName, {}, tree);
const { dependencies } = JSON.parse(newTree.readContent('/package.json'));
expect(dependencies['@angular/ssr']).toBeUndefined();
});

it(`should replace imports from '@nguniversal/common' to '@angular/ssr'`, async () => {
tree.create(
'file.ts',
Expand Down

0 comments on commit 1759446

Please sign in to comment.