Skip to content

Commit eac9e99

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
1 parent 6937a3e commit eac9e99

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
}
@@ -116,7 +122,10 @@ export class BundleActionCache {
116122
return null;
117123
}
118124

119-
const result: ProcessBundleResult = { name: action.name };
125+
const result: ProcessBundleResult = {
126+
name: action.name,
127+
integrity: this.generateIntegrityValue(action.code),
128+
};
120129

121130
let cacheEntry = entries[CacheKey.OriginalCode];
122131
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)