Skip to content

Commit 1494f20

Browse files
clydinalan-agius4
authored andcommitted
fix(@angular-devkit/build-angular): ensure correct SRI values with differential loading
Previously, the cached integrity values for a subsequent differential loading build would not be properly integrated. This resulted in builds with incorrect integrity values after an initial build. The cached differential loading builds will now use the correct integrity values on subsequent builds. Closes #18254 (cherry picked from commit eac9e99)
1 parent e60cfff commit 1494f20

File tree

2 files changed

+88
-6
lines changed

2 files changed

+88
-6
lines changed

packages/angular_devkit/build_angular/src/utils/action-cache.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,21 @@ export class BundleActionCache {
3333
}
3434
}
3535

36-
generateBaseCacheKey(content: string): string {
37-
// Create base cache key with elements:
38-
// * package version - different build-angular versions cause different final outputs
39-
// * code length/hash - ensure cached version matches the same input code
36+
generateIntegrityValue(content: string): string {
4037
const algorithm = this.integrityAlgorithm || 'sha1';
4138
const codeHash = createHash(algorithm)
4239
.update(content)
4340
.digest('base64');
44-
let baseCacheKey = `${packageVersion}|${content.length}|${algorithm}-${codeHash}`;
41+
42+
return `${algorithm}-${codeHash}`;
43+
}
44+
45+
generateBaseCacheKey(content: string): string {
46+
// Create base cache key with elements:
47+
// * package version - different build-angular versions cause different final outputs
48+
// * code length/hash - ensure cached version matches the same input code
49+
const integrity = this.generateIntegrityValue(content);
50+
let baseCacheKey = `${packageVersion}|${content.length}|${integrity}`;
4551
if (!allowMangle) {
4652
baseCacheKey += '|MD';
4753
}
@@ -115,7 +121,10 @@ export class BundleActionCache {
115121
return null;
116122
}
117123

118-
const result: ProcessBundleResult = { name: action.name };
124+
const result: ProcessBundleResult = {
125+
name: action.name,
126+
integrity: this.generateIntegrityValue(action.code),
127+
};
119128

120129
let cacheEntry = entries[CacheKey.OriginalCode];
121130
if (cacheEntry) {
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { createHash } from 'crypto';
2+
import {
3+
appendToFile,
4+
expectFileToMatch,
5+
prependToFile,
6+
readFile,
7+
replaceInFile,
8+
writeFile,
9+
} from '../../utils/fs';
10+
import { ng } from '../../utils/process';
11+
12+
export default async function () {
13+
// Enable Differential loading
14+
await replaceInFile('.browserslistrc', 'not IE 11', 'IE 11');
15+
16+
const appRoutingModulePath = 'src/app/app-routing.module.ts';
17+
18+
// Add app routing.
19+
// This is done automatically on a new app with --routing.
20+
await writeFile(
21+
appRoutingModulePath,
22+
`
23+
import { NgModule } from '@angular/core';
24+
import { Routes, RouterModule } from '@angular/router';
25+
26+
const routes: Routes = [];
27+
28+
@NgModule({
29+
imports: [RouterModule.forRoot(routes)],
30+
exports: [RouterModule]
31+
})
32+
export class AppRoutingModule { }
33+
`,
34+
);
35+
await prependToFile(
36+
'src/app/app.module.ts',
37+
`import { AppRoutingModule } from './app-routing.module';`,
38+
);
39+
await replaceInFile('src/app/app.module.ts', `imports: [`, `imports: [ AppRoutingModule,`);
40+
await appendToFile('src/app/app.component.html', '<router-outlet></router-outlet>');
41+
42+
await ng('generate', 'module', 'lazy', '--module=app.module', '--route', 'lazy');
43+
44+
await ng(
45+
'build',
46+
'--prod',
47+
'--subresource-integrity',
48+
'--output-hashing=none',
49+
'--output-path=dist/first',
50+
);
51+
52+
// Second build used to ensure cached files use correct integrity values
53+
await ng(
54+
'build',
55+
'--prod',
56+
'--subresource-integrity',
57+
'--output-hashing=none',
58+
'--output-path=dist/second',
59+
);
60+
61+
const codeHashES5 = createHash('sha384')
62+
.update(await readFile('dist/first/5-es5.js'))
63+
.digest('base64');
64+
const codeHashES2015 = createHash('sha384')
65+
.update(await readFile('dist/first/5-es2015.js'))
66+
.digest('base64');
67+
68+
await expectFileToMatch('dist/first/runtime-es5.js', 'sha384-' + codeHashES5);
69+
await expectFileToMatch('dist/first/runtime-es2015.js', 'sha384-' + codeHashES2015);
70+
71+
await expectFileToMatch('dist/second/runtime-es5.js', 'sha384-' + codeHashES5);
72+
await expectFileToMatch('dist/second/runtime-es2015.js', 'sha384-' + codeHashES2015);
73+
}

0 commit comments

Comments
 (0)