Skip to content

Commit 9c13fce

Browse files
alan-agius4clydin
authored andcommitted
feat(@angular-devkit/build-angular): remove bundleDependencies from server builder
This commit removes the usages of `bundleDependencies` which does not correctly work as webpack will use `require` to import ESM module since we configure the server bundle to be outputted in CJS. Migrating fully to ESM is also currently not viable due to the lack of support from Domino. Even if full ESM was possible, using this option would have resulted in a runtime overhead as Angular libraries would be linked during runtime instead of compile time. BREAKING CHANGE: The server builder `bundleDependencies` option has been removed. This option was used pre Ivy. Currently, using this option is unlikely to produce working server bundles. The `externalDependencies` option can be used instead to exclude specific node_module packages from the final bundle. Closes #23905
1 parent 4ead45c commit 9c13fce

File tree

10 files changed

+121
-111
lines changed

10 files changed

+121
-111
lines changed

goldens/public-api/angular_devkit/build_angular/index.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,6 @@ export interface ProtractorBuilderOptions {
244244

245245
// @public (undocumented)
246246
export interface ServerBuilderOptions {
247-
bundleDependencies?: boolean;
248247
deleteOutputPath?: boolean;
249248
// @deprecated
250249
deployUrl?: string;

packages/angular_devkit/build_angular/src/builders/server/schema.json

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -181,11 +181,6 @@
181181
"description": "Use file name for lazy loaded chunks.",
182182
"default": false
183183
},
184-
"bundleDependencies": {
185-
"description": "Which external dependencies to bundle into the bundle. By default, all of node_modules will be bundled.",
186-
"default": true,
187-
"type": "boolean"
188-
},
189184
"externalDependencies": {
190185
"description": "Exclude the listed external dependencies from being bundled into the bundle. Instead, the created bundle relies on these dependencies to be available during runtime.",
191186
"type": "array",

packages/angular_devkit/build_angular/src/utils/build-options.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ export interface BuildOptions {
4141
progress?: boolean;
4242
localize?: Localize;
4343
i18nMissingTranslation?: I18NTranslation;
44-
bundleDependencies?: boolean;
4544
externalDependencies?: string[];
4645
watch?: boolean;
4746
outputHashing?: OutputHashing;

packages/angular_devkit/build_angular/src/webpack/configs/common.ts

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import { AngularWebpackLoaderPath } from '@ngtools/webpack';
1010
import CopyWebpackPlugin from 'copy-webpack-plugin';
1111
import * as path from 'path';
12-
import { ScriptTarget } from 'typescript';
1312
import {
1413
Compiler,
1514
Configuration,
@@ -37,7 +36,6 @@ import { createIvyPlugin } from '../plugins/typescript';
3736
import { WatchFilesLogsPlugin } from '../plugins/watch-files-logs-plugin';
3837
import {
3938
assetPatterns,
40-
externalizePackages,
4139
getCacheSettings,
4240
getInstrumentationExcludedPaths,
4341
getOutputHashFormat,
@@ -74,7 +72,6 @@ export async function getCommonConfig(wco: WebpackConfigOptions): Promise<Config
7472
webWorkerTsConfig,
7573
externalDependencies = [],
7674
allowedCommonJsDependencies,
77-
bundleDependencies,
7875
} = buildOptions;
7976

8077
const isPlatformServer = buildOptions.platform === 'server';
@@ -273,13 +270,6 @@ export async function getCommonConfig(wco: WebpackConfigOptions): Promise<Config
273270
extraMinimizers.push(new TransferSizePlugin());
274271
}
275272

276-
const externals: Configuration['externals'] = [...externalDependencies];
277-
if (isPlatformServer && !bundleDependencies) {
278-
externals.push(({ context, request }, callback) =>
279-
externalizePackages(context ?? wco.projectRoot, request, callback),
280-
);
281-
}
282-
283273
let crossOriginLoading: NonNullable<Configuration['output']>['crossOriginLoading'] = false;
284274
if (subresourceIntegrity && crossOrigin === 'none') {
285275
crossOriginLoading = 'anonymous';
@@ -307,7 +297,7 @@ export async function getCommonConfig(wco: WebpackConfigOptions): Promise<Config
307297
},
308298
context: root,
309299
entry: entryPoints,
310-
externals,
300+
externals: externalDependencies,
311301
output: {
312302
uniqueName: projectName,
313303
hashFunction: 'xxhash64', // todo: remove in webpack 6. This is part of `futureDefaults`.

packages/angular_devkit/build_angular/src/webpack/utils/helpers.ts

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -252,31 +252,6 @@ export function assetPatterns(root: string, assets: AssetPatternClass[]) {
252252
});
253253
}
254254

255-
export function externalizePackages(
256-
context: string,
257-
request: string | undefined,
258-
callback: (error?: Error, result?: string) => void,
259-
): void {
260-
if (!request) {
261-
return;
262-
}
263-
264-
// Absolute & Relative paths are not externals
265-
if (request.startsWith('.') || path.isAbsolute(request)) {
266-
callback();
267-
268-
return;
269-
}
270-
271-
try {
272-
require.resolve(request, { paths: [context] });
273-
callback(undefined, request);
274-
} catch {
275-
// Node couldn't find it, so it must be user-aliased
276-
callback();
277-
}
278-
}
279-
280255
export function getStatsOptions(verbose = false): WebpackStatsOptions {
281256
const webpackOutputOptions: WebpackStatsOptions = {
282257
all: false, // Fallback value for stats options when an option is not defined. It has precedence over local webpack defaults.

packages/schematics/angular/migrations/migration-collection.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@
1414
"version": "15.0.0",
1515
"factory": "./update-15/update-typescript-target",
1616
"description": "Update TypeScript compiler `target` and set `useDefineForClassFields`. These changes are for IDE purposes as TypeScript compiler options `target` and `useDefineForClassFields` are set to `ES2022` and `false` respectively by the Angular CLI. To control ECMA version and features use the Browerslist configuration."
17+
},
18+
"update-workspace-config": {
19+
"version": "15.0.0",
20+
"factory": "./update-15/update-workspace-config",
21+
"description": "Remove options from 'angular.json' that are no longer supported by the official builders."
1722
}
1823
}
1924
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import { Rule } from '@angular-devkit/schematics';
10+
import { allTargetOptions, updateWorkspace } from '../../utility/workspace';
11+
import { Builders } from '../../utility/workspace-models';
12+
13+
export default function (): Rule {
14+
return updateWorkspace((workspace) => {
15+
for (const project of workspace.projects.values()) {
16+
for (const target of project.targets.values()) {
17+
if (target.builder !== Builders.Server) {
18+
continue;
19+
}
20+
21+
for (const [, options] of allTargetOptions(target)) {
22+
delete options.bundleDependencies;
23+
}
24+
}
25+
}
26+
});
27+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import { JsonObject } from '@angular-devkit/core';
10+
import { EmptyTree } from '@angular-devkit/schematics';
11+
import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';
12+
import {
13+
BuilderTarget,
14+
Builders,
15+
ProjectType,
16+
WorkspaceSchema,
17+
} from '../../utility/workspace-models';
18+
19+
function getServerTarget(tree: UnitTestTree): BuilderTarget<Builders.Server, JsonObject> {
20+
const target = (tree.readJson('/angular.json') as unknown as WorkspaceSchema).projects.app
21+
.architect?.server;
22+
23+
return target as unknown as BuilderTarget<Builders.Server, JsonObject>;
24+
}
25+
26+
function createWorkSpaceConfig(tree: UnitTestTree) {
27+
const angularConfig: WorkspaceSchema = {
28+
version: 1,
29+
projects: {
30+
app: {
31+
root: '',
32+
sourceRoot: 'src',
33+
projectType: ProjectType.Application,
34+
prefix: 'app',
35+
architect: {
36+
server: {
37+
builder: Builders.Server,
38+
options: {
39+
main: './server.ts',
40+
bundleDependencies: false,
41+
sourceMaps: true,
42+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
43+
} as any,
44+
configurations: {
45+
one: {
46+
aot: true,
47+
},
48+
two: {
49+
bundleDependencies: true,
50+
aot: true,
51+
},
52+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
53+
} as any,
54+
},
55+
},
56+
},
57+
},
58+
};
59+
60+
tree.create('/angular.json', JSON.stringify(angularConfig, undefined, 2));
61+
}
62+
63+
const schematicName = 'update-workspace-config';
64+
65+
describe(`Migration to update 'angular.json'. ${schematicName}`, () => {
66+
const schematicRunner = new SchematicTestRunner(
67+
'migrations',
68+
require.resolve('../migration-collection.json'),
69+
);
70+
71+
let tree: UnitTestTree;
72+
beforeEach(() => {
73+
tree = new UnitTestTree(new EmptyTree());
74+
createWorkSpaceConfig(tree);
75+
});
76+
77+
it(`should remove 'bundleDependencies'`, async () => {
78+
const newTree = await schematicRunner.runSchematicAsync(schematicName, {}, tree).toPromise();
79+
const { options, configurations } = getServerTarget(newTree);
80+
81+
expect(options.bundleDependencies).toBeUndefined();
82+
expect(configurations).toBeDefined();
83+
expect(configurations?.one.bundleDependencies).toBeUndefined();
84+
expect(configurations?.two.bundleDependencies).toBeUndefined();
85+
});
86+
});

tests/legacy-cli/e2e/tests/build/platform-server.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ export default async function () {
5959
/<p.*>Here are some links to help you get started:<\/p>/,
6060
);
6161

62-
// works with optimization and bundleDependencies enabled
63-
await ng('run', 'test-project:server', '--optimization', '--bundle-dependencies');
62+
// works with optimization
63+
await ng('run', 'test-project:server', '--optimization');
6464
await exec(normalize('node'), 'dist/test-project/server/main.js');
6565
await expectFileToMatch(
6666
'dist/test-project/server/index.html',

tests/legacy-cli/e2e/tests/misc/universal-bundle-dependencies.ts

Lines changed: 0 additions & 66 deletions
This file was deleted.

0 commit comments

Comments
 (0)