mirror of
https://github.com/angular/angular-cli.git
synced 2025-05-21 05:52:41 +08:00
fix(@angular/cli): stabilize webpack module identifiers
This provides increased viability for long-term caching by limiting the changes to the content of output files due to webpack module identifier changes. Close #4733
This commit is contained in:
parent
c99a7168d5
commit
26d1e41eb8
@ -69,6 +69,7 @@ export const getProdConfig = function (wco: WebpackConfigOptions) {
|
|||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
'process.env.NODE_ENV': JSON.stringify('production')
|
'process.env.NODE_ENV': JSON.stringify('production')
|
||||||
}),
|
}),
|
||||||
|
new (<any>webpack).HashedModuleIdsPlugin(),
|
||||||
new webpack.optimize.UglifyJsPlugin(<any>{
|
new webpack.optimize.UglifyJsPlugin(<any>{
|
||||||
mangle: { screw_ie8: true },
|
mangle: { screw_ie8: true },
|
||||||
compress: { screw_ie8: true, warnings: buildOptions.verbose },
|
compress: { screw_ie8: true, warnings: buildOptions.verbose },
|
||||||
|
@ -175,6 +175,9 @@ class JsonWebpackSerializer {
|
|||||||
case webpack.NoEmitOnErrorsPlugin:
|
case webpack.NoEmitOnErrorsPlugin:
|
||||||
this._addImport('webpack', 'NoEmitOnErrorsPlugin');
|
this._addImport('webpack', 'NoEmitOnErrorsPlugin');
|
||||||
break;
|
break;
|
||||||
|
case (<any>webpack).HashedModuleIdsPlugin:
|
||||||
|
this._addImport('webpack', 'HashedModuleIdsPlugin');
|
||||||
|
break;
|
||||||
case webpack.optimize.UglifyJsPlugin:
|
case webpack.optimize.UglifyJsPlugin:
|
||||||
this._addImport('webpack.optimize', 'UglifyJsPlugin');
|
this._addImport('webpack.optimize', 'UglifyJsPlugin');
|
||||||
break;
|
break;
|
||||||
|
@ -5,52 +5,92 @@ import {ng} from '../../utils/process';
|
|||||||
import {writeFile} from '../../utils/fs';
|
import {writeFile} from '../../utils/fs';
|
||||||
import {addImportToModule} from '../../utils/ast';
|
import {addImportToModule} from '../../utils/ast';
|
||||||
|
|
||||||
|
const OUTPUT_RE = /(main|polyfills|vendor|inline|styles|\d+)\.[a-z0-9]+\.(chunk|bundle)\.(js|css)$/;
|
||||||
|
|
||||||
|
function generateFileHashMap(): Map<string, string> {
|
||||||
|
const hashes = new Map<string, string>();
|
||||||
|
|
||||||
|
fs.readdirSync('./dist')
|
||||||
|
.forEach(name => {
|
||||||
|
if (!name.match(OUTPUT_RE)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [module, hash] = name.split('.');
|
||||||
|
hashes.set(module, hash);
|
||||||
|
});
|
||||||
|
|
||||||
|
return hashes;
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateHashes(
|
||||||
|
oldHashes: Map<string, string>,
|
||||||
|
newHashes: Map<string, string>,
|
||||||
|
shouldChange: Array<string>): void {
|
||||||
|
|
||||||
|
console.log(' Validating hashes...');
|
||||||
|
console.log(` Old hashes: ${JSON.stringify([...oldHashes])}`);
|
||||||
|
console.log(` New hashes: ${JSON.stringify([...newHashes])}`);
|
||||||
|
|
||||||
|
oldHashes.forEach((hash, module) => {
|
||||||
|
if (hash == newHashes.get(module)) {
|
||||||
|
if (shouldChange.includes(module)) {
|
||||||
|
throw new Error(`Module "${module}" did not change hash (${hash})...`);
|
||||||
|
}
|
||||||
|
} else if (!shouldChange.includes(module)) {
|
||||||
|
throw new Error(`Module "${module}" changed hash (${hash})...`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export default function() {
|
export default function() {
|
||||||
const oldHashes: {[module: string]: string} = {};
|
let oldHashes: Map<string, string>;
|
||||||
const newHashes: {[module: string]: string} = {};
|
let newHashes: Map<string, string>;
|
||||||
// First, collect the hashes.
|
// First, collect the hashes.
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
.then(() => ng('generate', 'module', 'lazy', '--routing'))
|
.then(() => ng('generate', 'module', 'lazy', '--routing'))
|
||||||
.then(() => addImportToModule('src/app/app.module.ts', oneLine`
|
.then(() => addImportToModule('src/app/app.module.ts', oneLine`
|
||||||
RouterModule.forRoot([{ path: "lazy", loadChildren: "./lazy/lazy.module#LazyModule" }])
|
RouterModule.forRoot([{ path: "lazy", loadChildren: "./lazy/lazy.module#LazyModule" }])
|
||||||
`, '@angular/router'))
|
`, '@angular/router'))
|
||||||
|
.then(() => addImportToModule(
|
||||||
|
'src/app/app.module.ts', 'ReactiveFormsModule', '@angular/forms'))
|
||||||
.then(() => ng('build', '--prod'))
|
.then(() => ng('build', '--prod'))
|
||||||
.then(() => {
|
.then(() => {
|
||||||
fs.readdirSync('./dist')
|
oldHashes = generateFileHashMap();
|
||||||
.forEach(name => {
|
|
||||||
if (!name.match(/(main|inline|styles|\d+)\.[a-z0-9]+\.bundle\.(js|css)/)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const [module, hash] = name.split('.');
|
|
||||||
oldHashes[module] = hash;
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
.then(() => writeFile('src/app/app.component.css', 'h1 { margin: 5px; }'))
|
|
||||||
.then(() => writeFile('src/styles.css', 'body { background: red; }'))
|
|
||||||
.then(() => ng('build', '--prod'))
|
.then(() => ng('build', '--prod'))
|
||||||
.then(() => {
|
.then(() => {
|
||||||
fs.readdirSync('./dist')
|
newHashes = generateFileHashMap();
|
||||||
.forEach(name => {
|
|
||||||
if (!name.match(/(main|inline|styles|\d+)\.[a-z0-9]+\.bundle\.(js|css)/)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const [module, hash] = name.split('.');
|
|
||||||
newHashes[module] = hash;
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
console.log(' Validating hashes...');
|
validateHashes(oldHashes, newHashes, []);
|
||||||
console.log(` Old hashes: ${JSON.stringify(oldHashes)}`);
|
oldHashes = newHashes;
|
||||||
console.log(` New hashes: ${JSON.stringify(newHashes)}`);
|
})
|
||||||
|
.then(() => writeFile('src/styles.css', 'body { background: blue; }'))
|
||||||
Object.keys(oldHashes)
|
.then(() => ng('build', '--prod'))
|
||||||
.forEach(module => {
|
.then(() => {
|
||||||
if (oldHashes[module] == newHashes[module]) {
|
newHashes = generateFileHashMap();
|
||||||
throw new Error(`Module "${module}" did not change hash (${oldHashes[module]})...`);
|
})
|
||||||
}
|
.then(() => {
|
||||||
});
|
validateHashes(oldHashes, newHashes, ['styles']);
|
||||||
|
oldHashes = newHashes;
|
||||||
|
})
|
||||||
|
.then(() => writeFile('src/app/app.component.css', 'h1 { margin: 10px; }'))
|
||||||
|
.then(() => ng('build', '--prod'))
|
||||||
|
.then(() => {
|
||||||
|
newHashes = generateFileHashMap();
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
validateHashes(oldHashes, newHashes, ['inline', 'main']);
|
||||||
|
oldHashes = newHashes;
|
||||||
|
})
|
||||||
|
.then(() => addImportToModule(
|
||||||
|
'src/app/lazy/lazy.module.ts', 'ReactiveFormsModule', '@angular/forms'))
|
||||||
|
.then(() => ng('build', '--prod'))
|
||||||
|
.then(() => {
|
||||||
|
newHashes = generateFileHashMap();
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
validateHashes(oldHashes, newHashes, ['inline', '0']);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user