Skip to content

Commit bcca0d7

Browse files
filipesilvahansl
authored andcommitted
feat(@angular/cli): name lazy chunks
Before: ``` $ ng build --no-progress Hash: ff03df269349b817eef4 Time: 11202ms chunk {0} 0.chunk.js, 0.chunk.js.map 1.61 kB {1} {3} [rendered] chunk {1} 1.chunk.js, 1.chunk.js.map 1.46 kB {0} {3} [rendered] chunk {2} polyfills.bundle.js, polyfills.bundle.js.map (polyfills) 160 kB {6} [initial] [rendered] chunk {3} main.bundle.js, main.bundle.js.map (main) 6.38 kB {5} [initial] [rendered] chunk {4} styles.bundle.js, styles.bundle.js.map (styles) 10.5 kB {6} [initial] [rendered] chunk {5} vendor.bundle.js, vendor.bundle.js.map (vendor) 2.16 MB [initial] [rendered] chunk {6} inline.bundle.js, inline.bundle.js.map (inline) 0 bytes [entry] [rendered] ``` After: ``` $ ng build --no-progress Hash: 2bc12a89f40f3b4818b5 Time: 9613ms chunk {feature.module} feature.module.chunk.js, feature.module.chunk.js.map 1.46 kB {lazy.module} {main} [rendered] chunk {inline} inline.bundle.js, inline.bundle.js.map (inline) 0 bytes [entry] [rendered] chunk {lazy.module} lazy.module.chunk.js, lazy.module.chunk.js.map 1.61 kB {feature.module} {main} [rendered] chunk {main} main.bundle.js, main.bundle.js.map (main) 6.38 kB {vendor} [initial] [rendered] chunk {polyfills} polyfills.bundle.js, polyfills.bundle.js.map (polyfills) 160 kB {inline} [initial] [rendered] chunk {styles} styles.bundle.js, styles.bundle.js.map (styles) 10.5 kB {inline} [initial] [rendered] chunk {vendor} vendor.bundle.js, vendor.bundle.js.map (vendor) 2.16 MB [initial] [rendered] ``` Fix #6700
1 parent 27f5d35 commit bcca0d7

File tree

9 files changed

+82
-12
lines changed

9 files changed

+82
-12
lines changed

packages/@angular/cli/models/webpack-configs/common.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as webpack from 'webpack';
22
import * as path from 'path';
33
import { GlobCopyWebpackPlugin } from '../../plugins/glob-copy-webpack-plugin';
4+
import { NamedLazyChunksWebpackPlugin } from '../../plugins/named-lazy-chunks-webpack-plugin';
45
import { extraEntryParser, getOutputHashFormat } from './utils';
56
import { WebpackConfigOptions } from '../webpack-config';
67

@@ -109,7 +110,8 @@ export function getCommonConfig(wco: WebpackConfigOptions) {
109110
].concat(extraRules)
110111
},
111112
plugins: [
112-
new webpack.NoEmitOnErrorsPlugin()
113+
new webpack.NoEmitOnErrorsPlugin(),
114+
new NamedLazyChunksWebpackPlugin(),
113115
].concat(extraPlugins),
114116
node: {
115117
fs: 'empty',

packages/@angular/cli/models/webpack-configs/production.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ export const getProdConfig = function (wco: WebpackConfigOptions) {
9797
new webpack.EnvironmentPlugin({
9898
'NODE_ENV': 'production'
9999
}),
100-
new (<any>webpack).HashedModuleIdsPlugin(),
100+
new webpack.HashedModuleIdsPlugin(),
101101
new webpack.optimize.UglifyJsPlugin(<any>{
102102
mangle: { screw_ie8: true },
103103
compress: { screw_ie8: true, warnings: buildOptions.verbose },
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import * as webpack from 'webpack';
2+
3+
4+
// This just extends webpack.NamedChunksPlugin to prevent name collisions.
5+
export class NamedLazyChunksWebpackPlugin extends webpack.NamedChunksPlugin {
6+
constructor() {
7+
// Append a dot and number if the name already exists.
8+
const nameMap = new Map<string, boolean>();
9+
function getUniqueName(baseName: string) {
10+
let name = baseName;
11+
let num = 0;
12+
while (nameMap.has(name)) {
13+
name = `${baseName}.${num++}`;
14+
}
15+
nameMap.set(name, true);
16+
return name;
17+
}
18+
19+
const nameResolver = (chunk: any) => {
20+
// Entry chunks have a name already, use it.
21+
if (chunk.name) {
22+
return chunk.name;
23+
}
24+
25+
// Try to figure out if it's a lazy loaded route.
26+
if (chunk.blocks
27+
&& chunk.blocks.length > 0
28+
&& chunk.blocks[0].dependencies
29+
&& chunk.blocks[0].dependencies.length > 0
30+
&& chunk.blocks[0].dependencies[0].lazyRouteChunkName
31+
) {
32+
// lazyRouteChunkName was added by @ngtools/webpack.
33+
return getUniqueName(chunk.blocks[0].dependencies[0].lazyRouteChunkName);
34+
}
35+
36+
return null;
37+
};
38+
39+
super(nameResolver);
40+
}
41+
}

packages/@angular/cli/plugins/webpack.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,7 @@ module.exports = {
66
GlobCopyWebpackPlugin: require('../plugins/glob-copy-webpack-plugin').GlobCopyWebpackPlugin,
77
SuppressExtractedTextChunksWebpackPlugin:
88
require('../plugins/suppress-entry-chunks-webpack-plugin')
9-
.SuppressExtractedTextChunksWebpackPlugin
9+
.SuppressExtractedTextChunksWebpackPlugin,
10+
NamedLazyChunksWebpackPlugin:
11+
require('../plugins/named-lazy-chunks-webpack-plugin').NamedLazyChunksWebpackPlugin
1012
};

packages/@angular/cli/tasks/eject.ts

+1
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ class JsonWebpackSerializer {
175175
this._addImport('webpack.optimize', 'UglifyJsPlugin');
176176
break;
177177
case angularCliPlugins.BaseHrefWebpackPlugin:
178+
case angularCliPlugins.NamedLazyChunksWebpackPlugin:
178179
case angularCliPlugins.SuppressExtractedTextChunksWebpackPlugin:
179180
this._addImport('@angular/cli/plugins/webpack', plugin.constructor.name);
180181
break;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import * as webpack from 'webpack';
2+
3+
declare module 'webpack' {
4+
export class NamedChunksPlugin {
5+
constructor(nameResolver: (chunk: any) => string | null);
6+
}
7+
export class HashedModuleIdsPlugin {
8+
constructor();
9+
}
10+
}

packages/@ngtools/webpack/src/plugin.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,11 @@ export class AotPlugin implements Tapable {
310310
.map((key) => {
311311
const value = this._lazyRoutes[key];
312312
if (value !== null) {
313-
return new ContextElementDependency(value, key);
313+
const dep = new ContextElementDependency(value, key);
314+
// lazyRouteChunkName is used by webpack.NamedChunksPlugin to give the
315+
// lazy loaded chunk a name.
316+
dep.lazyRouteChunkName = path.basename(key, '.ts');
317+
return dep;
314318
} else {
315319
return null;
316320
}

tests/e2e/tests/misc/lazy-module.ts

+13-3
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,27 @@ export default function() {
1212
.then(() => ng('build'))
1313
.then(() => oldNumberOfFiles = readdirSync('dist').length)
1414
.then(() => ng('generate', 'module', 'lazy', '--routing'))
15+
.then(() => ng('generate', 'module', 'too/lazy', '--routing'))
1516
.then(() => addImportToModule('src/app/app.module.ts', oneLine`
1617
RouterModule.forRoot([{ path: "lazy", loadChildren: "app/lazy/lazy.module#LazyModule" }]),
17-
RouterModule.forRoot([{ path: "lazy1", loadChildren: "./lazy/lazy.module#LazyModule" }])
18+
RouterModule.forRoot([{ path: "lazy1", loadChildren: "./lazy/lazy.module#LazyModule" }]),
19+
RouterModule.forRoot([{ path: "lazy2", loadChildren: "./too/lazy/lazy.module#LazyModule" }])
1820
`, '@angular/router'))
1921
.then(() => ng('build'))
20-
.then(() => readdirSync('dist').length)
21-
.then(currentNumberOfDistFiles => {
22+
.then(() => readdirSync('dist'))
23+
.then((distFiles) => {
24+
const currentNumberOfDistFiles = distFiles.length;
2225
if (oldNumberOfFiles >= currentNumberOfDistFiles) {
2326
throw new Error('A bundle for the lazy module was not created.');
2427
}
2528
oldNumberOfFiles = currentNumberOfDistFiles;
29+
30+
if (!distFiles.includes('lazy.module.chunk.js')){
31+
throw new Error('The bundle for the lazy module did not have a name.');
32+
}
33+
if (!distFiles.includes('lazy.module.0.chunk.js')){
34+
throw new Error('The bundle for the lazy module did not use a unique name.');
35+
}
2636
})
2737
// verify System.import still works
2838
.then(() => writeFile('src/app/lazy-file.ts', ''))

yarn.lock

+5-5
Original file line numberDiff line numberDiff line change
@@ -4355,16 +4355,16 @@ right-align@^0.1.1:
43554355
dependencies:
43564356
align-text "^0.1.1"
43574357

4358-
rimraf@2, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.6.1:
4358+
rimraf@2, rimraf@^2.2.8, rimraf@~2.2.6:
4359+
version "2.2.8"
4360+
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582"
4361+
4362+
rimraf@^2.5.1, rimraf@^2.6.1:
43594363
version "2.6.1"
43604364
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d"
43614365
dependencies:
43624366
glob "^7.0.5"
43634367

4364-
rimraf@~2.2.6:
4365-
version "2.2.8"
4366-
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582"
4367-
43684368
ripemd160@^2.0.0, ripemd160@^2.0.1:
43694369
version "2.0.1"
43704370
resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7"

0 commit comments

Comments
 (0)