Skip to content

Commit 6f4fef5

Browse files
alan-agius4Keen Yee Liau
authored and
Keen Yee Liau
committed
fix(@angular-devkit/build-angular): add externalDependencies to server builders
Certain node packages depend on native bindings which cannot be bundled, with this fix we add a way to exclude these from being processed by the bundler. Closes: #16348
1 parent 009b783 commit 6f4fef5

File tree

5 files changed

+80
-9
lines changed

5 files changed

+80
-9
lines changed

packages/angular/cli/lib/config/schema.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1889,6 +1889,14 @@
18891889
}
18901890
]
18911891
},
1892+
"externalDependencies": {
1893+
"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.",
1894+
"type": "array",
1895+
"items": {
1896+
"type": "string"
1897+
},
1898+
"default": []
1899+
},
18921900
"statsJson": {
18931901
"type": "boolean",
18941902
"description": "Generates a 'stats.json' file which can be analyzed using tools such as 'webpack-bundle-analyzer'.",

packages/angular_devkit/build_angular/src/angular-cli-files/models/build-options.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
import { logging } from '@angular-devkit/core';
1212
import { ParsedConfiguration } from '@angular/compiler-cli';
13-
import { ScriptTarget } from 'typescript';
1413
import {
1514
AssetPatternClass,
1615
Budget,
@@ -49,6 +48,7 @@ export interface BuildOptions {
4948
i18nMissingTranslation?: I18NMissingTranslation;
5049
extractCss?: boolean;
5150
bundleDependencies?: boolean;
51+
externalDependencies?: string[];
5252
watch?: boolean;
5353
outputHashing?: string;
5454
poll?: number;

packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/server.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,15 @@ import { getSourceMapDevTool } from './utils';
1515
* @param wco Options which are include the build options and app config
1616
*/
1717
export function getServerConfig(wco: WebpackConfigOptions): Configuration {
18-
const extraPlugins = [];
19-
if (wco.buildOptions.sourceMap) {
20-
const { scripts, styles, hidden } = wco.buildOptions.sourceMap;
18+
const {
19+
sourceMap,
20+
bundleDependencies,
21+
externalDependencies = [],
22+
} = wco.buildOptions;
2123

24+
const extraPlugins = [];
25+
if (sourceMap) {
26+
const { scripts, styles, hidden } = sourceMap;
2227
extraPlugins.push(getSourceMapDevTool(scripts || false, styles || false, hidden || false));
2328
}
2429

@@ -39,13 +44,17 @@ export function getServerConfig(wco: WebpackConfigOptions): Configuration {
3944
node: false,
4045
};
4146

42-
if (!wco.buildOptions.bundleDependencies) {
47+
if (bundleDependencies) {
48+
config.externals = [...externalDependencies];
49+
} else {
4350
config.externals = [
44-
/^@angular/,
51+
...externalDependencies,
4552
(context: string, request: string, callback: (error?: null, result?: string) => void) => {
4653
// Absolute & Relative paths are not externals
47-
if (/^\.{0,2}\//.test(request) || isAbsolute(request)) {
48-
return callback();
54+
if (request.startsWith('./') || isAbsolute(request)) {
55+
callback();
56+
57+
return;
4958
}
5059

5160
try {

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@
218218
"x-deprecated": "Since version 9. This option has no effect on server platform."
219219
},
220220
"bundleDependencies": {
221-
"description": "Available on server platform only. Which external dependencies to bundle into the module. By default, all of node_modules will be bundled.",
221+
"description": "Which external dependencies to bundle into the bundle. By default, all of node_modules will be bundled.",
222222
"default": true,
223223
"oneOf": [
224224
{
@@ -233,6 +233,14 @@
233233
}
234234
]
235235
},
236+
"externalDependencies": {
237+
"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.",
238+
"type": "array",
239+
"items": {
240+
"type": "string"
241+
},
242+
"default": []
243+
},
236244
"statsJson": {
237245
"type": "boolean",
238246
"description": "Generates a 'stats.json' file which can be analyzed using tools such as 'webpack-bundle-analyzer'.",
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. 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 { Architect } from '@angular-devkit/architect';
10+
import { join, normalize, virtualFs } from '@angular-devkit/core';
11+
import { ServerBuilderOutput } from '../../src';
12+
import { createArchitect, host } from '../utils';
13+
14+
15+
describe('Server Builder external dependencies', () => {
16+
const target = { project: 'app', target: 'server' };
17+
let architect: Architect;
18+
19+
beforeEach(async () => {
20+
await host.initialize().toPromise();
21+
architect = (await createArchitect(host.root())).architect;
22+
});
23+
afterEach(async () => host.restore().toPromise());
24+
25+
const outputPath = normalize('dist-server');
26+
27+
it('should not bundle an given external dependency', async () => {
28+
const overrides = {
29+
bundleDependencies: true,
30+
externalDependencies: [
31+
'@angular/core',
32+
],
33+
};
34+
35+
const run = await architect.scheduleTarget(target, overrides);
36+
const output = await run.result as ServerBuilderOutput;
37+
expect(output.success).toBe(true);
38+
39+
const fileName = join(outputPath, 'main.js');
40+
const content = virtualFs.fileBufferToString(host.scopedSync().read(normalize(fileName)));
41+
expect(content).toContain('require("@angular/core")');
42+
expect(content).not.toContain('require("@angular/common")');
43+
44+
await run.stop();
45+
});
46+
});

0 commit comments

Comments
 (0)