Skip to content

Commit 0b3cf8a

Browse files
committed
fix(@angular/build): support quotes in styles and polyfills paths
The application builder generated the global styles and polyfills entry modules by wrapping each configured path in single quotes without escaping. A path containing a single quote, such as `src/dev's theme/theme.css`, produced an invalid import and the build failed with "Could not resolve" or a syntax error. Generate the import specifiers with `JSON.stringify` so that such paths are quoted correctly.
1 parent 9469dcd commit 0b3cf8a

4 files changed

Lines changed: 38 additions & 2 deletions

File tree

‎packages/angular/build/src/builders/application/tests/options/polyfills_spec.ts‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,21 @@ describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => {
6161
harness.expectFile('dist/browser/polyfills.js').content.toContain(`console.log("main")`);
6262
});
6363

64+
it('uses a provided file with a single quote in its path', async () => {
65+
await harness.writeFile(`src/dev's polyfills/polyfills.js`, `console.log('main');`);
66+
67+
harness.useTarget('build', {
68+
...BASE_OPTIONS,
69+
polyfills: [`src/dev's polyfills/polyfills.js`],
70+
});
71+
72+
const { result } = await harness.executeOnce();
73+
74+
expect(result?.success).toBe(true);
75+
76+
harness.expectFile('dist/browser/polyfills.js').content.toContain(`console.log("main")`);
77+
});
78+
6479
it('fails and shows an error when file does not exist', async () => {
6580
harness.useTarget('build', {
6681
...BASE_OPTIONS,

‎packages/angular/build/src/builders/application/tests/options/styles_spec.ts‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,23 @@ describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => {
6262
.content.toContain('<link rel="stylesheet" href="styles.css">');
6363
});
6464

65+
it('processes a style with a single quote in its path', async () => {
66+
await harness.writeFile(`src/dev's theme/test-style-a.css`, '.test-a {color: red}');
67+
68+
harness.useTarget('build', {
69+
...BASE_OPTIONS,
70+
styles: [`src/dev's theme/test-style-a.css`],
71+
});
72+
73+
const { result } = await harness.executeOnce();
74+
75+
expect(result?.success).toBe(true);
76+
77+
harness
78+
.expectFile('dist/browser/styles.css')
79+
.content.toMatch(/\.test-a {\s*color: red;?\s*}/);
80+
});
81+
6582
it('processes multiple styles into a single output', async () => {
6683
await harness.writeFiles({
6784
'src/test-style-a.css': '.test-a {color: red}',

‎packages/angular/build/src/tools/esbuild/application-code-bundle.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -740,7 +740,9 @@ function getEsBuildCommonPolyfillsOptions(
740740
}
741741

742742
// Generate module contents with an import statement per defined polyfill
743-
let contents = polyfillPaths.map((file) => `import '${toPosixPath(file)}';`).join('\n');
743+
let contents = polyfillPaths
744+
.map((file) => `import ${JSON.stringify(toPosixPath(file))};`)
745+
.join('\n');
744746

745747
// The below should be done after loading `$localize` as otherwise the locale will be overridden.
746748
if (i18nOptions.shouldInline) {

‎packages/angular/build/src/tools/esbuild/global-styles.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,9 @@ export function createGlobalStylesBundleOptions(
9292
assert(files, `global style name should always be found [${args.path}]`);
9393

9494
return {
95-
contents: files.map((file) => `@import '${toPosixPath(file)}';`).join('\n'),
95+
contents: files
96+
.map((file) => `@import ${JSON.stringify(toPosixPath(file))};`)
97+
.join('\n'),
9698
loader: 'css',
9799
resolveDir: workspaceRoot,
98100
};

0 commit comments

Comments
 (0)