Skip to content

Commit 87464b4

Browse files
MeAkibalan-agius4
authored andcommitted
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 508d6a2 commit 87464b4

4 files changed

Lines changed: 43 additions & 6 deletions

File tree

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,5 +89,21 @@ describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => {
8989
});
9090
});
9191
}
92+
93+
it('uses a provided file with a single quote in its path', async () => {
94+
await harness.writeFile('src/main.ts', 'console.log("TEST");');
95+
await harness.writeFile(`src/dev's polyfills/polyfills.js`, `console.log('main');`);
96+
97+
harness.useTarget('build', {
98+
...BASE_OPTIONS,
99+
polyfills: [`src/dev's polyfills/polyfills.js`],
100+
});
101+
102+
const { result } = await harness.executeOnce();
103+
104+
expect(result?.success).toBe(true);
105+
106+
harness.expectFile('dist/browser/polyfills.js').content.toContain(`console.log("main")`);
107+
});
92108
});
93109
});

‎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: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -364,8 +364,8 @@ export function createServerMainCodeBundleOptions(
364364
`export { ɵresetCompiledComponents } from '@angular/core';`,
365365

366366
// Re-export all symbols including default export from 'main.server.ts'
367-
`export { default } from '${mainServerEntryPointJsImport}';`,
368-
`export * from '${mainServerEntryPointJsImport}';`,
367+
`export { default } from ${JSON.stringify(mainServerEntryPointJsImport)};`,
368+
`export * from ${JSON.stringify(mainServerEntryPointJsImport)};`,
369369
];
370370

371371
return {
@@ -496,8 +496,8 @@ export function createSsrEntryCodeBundleOptions(
496496
`import '${ssrInjectManifestNamespace}';`,
497497

498498
// Re-export all symbols including default export
499-
`import * as server from '${serverEntryPointJsImport}';`,
500-
`export * from '${serverEntryPointJsImport}';`,
499+
`import * as server from ${JSON.stringify(serverEntryPointJsImport)};`,
500+
`export * from ${JSON.stringify(serverEntryPointJsImport)};`,
501501
// The below is needed to avoid
502502
// `Import "default" will always be undefined because there is no matching export` warning when no default is present.
503503
`const defaultExportName = 'default';`,
@@ -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)