Skip to content

Commit 648aff9

Browse files
committed
fix(@angular/build): use component file path in inline stylesheet diagnostic locations
Rewrite internal angular:styles/component:<lang>;<hash>;<filename> virtual URIs in inline component stylesheet error, warning, and note locations to the component's file path, and ensure the component file path is added to watchFiles on error. (cherry picked from commit 8c14983)
1 parent 3aa7e93 commit 648aff9

2 files changed

Lines changed: 104 additions & 6 deletions

File tree

‎packages/angular/build/src/tools/esbuild/angular/component-stylesheets.ts‎

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -176,13 +176,24 @@ export class ComponentStylesheetBundler {
176176
);
177177
});
178178

179+
const result = await bundlerContext.bundle();
180+
if (result.errors || result.warnings.length > 0) {
181+
if (this.incremental && result.errors) {
182+
bundlerContext.watchFiles.add(
183+
path.isAbsolute(filename) ? filename : path.join(this.options.workspaceRoot, filename),
184+
);
185+
}
186+
for (const message of [...(result.errors ?? []), ...result.warnings]) {
187+
for (const item of [message, ...(message.notes ?? [])]) {
188+
if (item.location?.file?.startsWith('angular:styles/component:')) {
189+
item.location.file = filename;
190+
}
191+
}
192+
}
193+
}
194+
179195
// Extract the result of the bundling from the output files
180-
return this.extractResult(
181-
await bundlerContext.bundle(),
182-
bundlerContext.watchFiles,
183-
!!externalId,
184-
false,
185-
);
196+
return this.extractResult(result, bundlerContext.watchFiles, !!externalId, false);
186197
}
187198

188199
/**
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.dev/license
7+
*/
8+
9+
import assert from 'node:assert';
10+
import { mkdtemp, rm } from 'node:fs/promises';
11+
import { join } from 'node:path';
12+
import { initializeHash } from '../../../utils/hash';
13+
import { ComponentStylesheetBundler } from './component-stylesheets';
14+
15+
describe('ComponentStylesheetBundler', () => {
16+
let tempRoot: string;
17+
18+
beforeAll(async () => {
19+
await initializeHash();
20+
const baseTmpDir = process.env['TEST_TMPDIR'];
21+
assert(baseTmpDir, 'TEST_TMPDIR is not set');
22+
tempRoot = await mkdtemp(join(baseTmpDir, 'angular-cli-component-stylesheets-'));
23+
});
24+
25+
afterAll(async () => {
26+
await rm(tempRoot, { force: true, recursive: true });
27+
});
28+
29+
it('uses the component filename instead of angular:styles/component virtual URI in bundleInline error locations', async () => {
30+
const bundler = new ComponentStylesheetBundler(
31+
{
32+
workspaceRoot: tempRoot,
33+
optimization: false,
34+
inlineFonts: false,
35+
sourcemap: false,
36+
outputNames: { bundles: '[name]', media: 'media/[name]' },
37+
target: ['es2022'],
38+
cacheOptions: { enabled: false, path: '', basePath: tempRoot },
39+
},
40+
'css',
41+
true,
42+
);
43+
44+
const componentFile = join(tempRoot, 'src', 'lib', 'lib.component.ts');
45+
46+
try {
47+
const result = await bundler.bundleInline(
48+
'.icon { background: url("./missing.png"); }',
49+
componentFile,
50+
);
51+
52+
assert(result.errors, 'Expected bundleInline to report a resolution error');
53+
expect(result.errors.length).toBeGreaterThan(0);
54+
expect(result.errors[0].location?.file).toBe(componentFile);
55+
expect(result.referencedFiles).toContain(componentFile);
56+
} finally {
57+
await bundler.dispose();
58+
}
59+
});
60+
61+
it('uses the component filename instead of angular:styles/component virtual URI in bundleInline warning locations', async () => {
62+
const bundler = new ComponentStylesheetBundler(
63+
{
64+
workspaceRoot: tempRoot,
65+
optimization: false,
66+
inlineFonts: false,
67+
sourcemap: false,
68+
outputNames: { bundles: '[name]', media: 'media/[name]' },
69+
target: ['es2022'],
70+
cacheOptions: { enabled: false, path: '', basePath: tempRoot },
71+
},
72+
'css',
73+
false,
74+
);
75+
76+
const componentFile = join(tempRoot, 'src', 'lib', 'lib.component.ts');
77+
78+
try {
79+
const result = await bundler.bundleInline('.box { color: red', componentFile);
80+
81+
expect(result.warnings.length).toBeGreaterThan(0);
82+
expect(result.warnings[0].location?.file).toBe(componentFile);
83+
} finally {
84+
await bundler.dispose();
85+
}
86+
});
87+
});

0 commit comments

Comments
 (0)