Skip to content

Commit 8c14983

Browse files
authored
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.
1 parent f9325ab commit 8c14983

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)