Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions packages/angular/build/src/builders/application/chunk-optimizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,21 @@ export async function optimizeChunks(

return result;
},
augmentChunkHash(chunk: { moduleIds: string[] }) {
if (!sourcemap) {
return;
}

let hash = '';
for (const id of chunk.moduleIds) {
const mapHash = maps[id]?.hash;
if (mapHash) {
hash += mapHash;
}
}

return hash || undefined;
},
},
];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { createHash } from 'node:crypto';
import { readdirSync, readFileSync } from 'node:fs';
import { join } from 'node:path';
import { buildApplication } from '../../index';
import { OutputHashing } from '../../schema';
import {
APPLICATION_BUILDER_INFO,
BASE_OPTIONS,
Expand Down Expand Up @@ -254,5 +255,82 @@ describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => {
/const scripts = \[\[(?:'[^']+', "module", false, false, "sha384-[^"]+", "anonymous"(?:, )?)+\]\];/,
);
});

it(`updates optimized chunk filename when source map changes cause debugId to change`, async () => {
await harness.writeFiles({
'src/app/shared-label.ts': `
export interface LabelInput {
text: string;
}
export function formatLabel(input: LabelInput): string {
return 'SHARED_LABEL:' + input.text;
}
`,
'src/app/lazy-a.ts': `
import { formatLabel } from './shared-label';
export const a = formatLabel({ text: 'a' });
`,
'src/app/lazy-b.ts': `
import { formatLabel } from './shared-label';
export const b = formatLabel({ text: 'b' });
`,
'src/app/lazy-c.ts': `
export const c = 'c';
`,
'src/main.ts': `
console.log(
import('./app/lazy-a'),
import('./app/lazy-b'),
import('./app/lazy-c'),
);
`,
});

harness.useTarget('build', {
...BASE_OPTIONS,
optimization: true,
outputHashing: OutputHashing.All,
sourceMap: { scripts: true },
subresourceIntegrity: true,
});

const firstBuild = await harness.executeOnce();
expect(firstBuild.result?.success).toBeTrue();

const distDir = workspacePath('dist/browser');
const findSharedChunk = () => {
const files = readdirSync(distDir).filter((f) => f.endsWith('.js'));
for (const file of files) {
const content = readFileSync(join(distDir, file), 'utf-8');
if (content.includes('SHARED_LABEL:')) {
return { file, content };
}
}
throw new Error('Shared label chunk not found');
};

const chunk1 = findSharedChunk();

// Make a type-only change that shifts line numbers in the source map without changing emitted JS code.
await harness.writeFile(
'src/app/shared-label.ts',
`
export interface LabelInput {
text: string;
extra?: number;
}
export function formatLabel(input: LabelInput): string {
return 'SHARED_LABEL:' + input.text;
}
`,
);

const secondBuild = await harness.executeOnce();
expect(secondBuild.result?.success).toBeTrue();

const chunk2 = findSharedChunk();
expect(chunk2.content).not.toBe(chunk1.content);
expect(chunk2.file).not.toBe(chunk1.file);
});
});
});
10 changes: 9 additions & 1 deletion packages/angular/build/src/tools/esbuild/bundler-files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ export function createOutputFile(
set contents(value: Uint8Array) {
cachedContents = value;
cachedText = null;
cachedHash = null;
},
get text(): string {
cachedText ??= new TextDecoder('utf-8').decode(this.contents);
Expand Down Expand Up @@ -134,6 +135,7 @@ export function createOutputFile(
set contents(value: Uint8Array) {
cachedContents = value;
cachedText = null;
cachedHash = null;
},
path,
type,
Expand All @@ -160,6 +162,7 @@ export function createOutputFile(
export function convertOutputFile(file: OutputFile, type: BuildOutputFileType): BuildOutputFile {
let { contents: cachedContents } = file;
let cachedText: string | null = null;
let cachedHash: string | null = file.hash;
Comment thread
alan-agius4 marked this conversation as resolved.

return {
get contents(): Uint8Array {
Expand All @@ -168,8 +171,13 @@ export function convertOutputFile(file: OutputFile, type: BuildOutputFileType):
set contents(value: Uint8Array) {
cachedContents = value;
cachedText = null;
cachedHash = null;
},
get hash(): string {
cachedHash ??= calculateHash(cachedContents);

return cachedHash;
},
hash: file.hash,
path: file.path,
type,
get size(): number {
Expand Down
Loading