Skip to content

Commit 8f4786e

Browse files
committed
fix(@angular-devkit/build-angular): normalize asset source locations in Vite-based development server
The Vite-based development server uses an allow list to permit access to configured assets. This list is checked internally to Vite by using its normalized path form. To ensure that assets provided by the build are checked correctly on all platforms, the asset list is now normalized with Vite's path normalization prior to being used.
1 parent b10d2a7 commit 8f4786e

File tree

2 files changed

+39
-1
lines changed
  • packages/angular_devkit/build_angular/src/builders/dev-server
  • tests/legacy-cli/e2e/tests/commands/serve

2 files changed

+39
-1
lines changed

packages/angular_devkit/build_angular/src/builders/dev-server/vite-server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ export async function* serveWithVite(
191191
assetFiles.clear();
192192
if (result.assetFiles) {
193193
for (const asset of result.assetFiles) {
194-
assetFiles.set('/' + normalizePath(asset.destination), asset.source);
194+
assetFiles.set('/' + normalizePath(asset.destination), normalizePath(asset.source));
195195
}
196196
}
197197

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { mkdir, rm, writeFile } from 'node:fs/promises';
2+
import assert from 'assert';
3+
import { ngServe, updateJsonFile } from '../../../utils/project';
4+
import { randomUUID } from 'node:crypto';
5+
6+
export default async function () {
7+
const outsideDirectoryName = `../outside-${randomUUID()}`;
8+
9+
await updateJsonFile('angular.json', (json) => {
10+
json.projects['test-project'].architect.build.options.assets = [
11+
'src/favicon.ico',
12+
'src/assets',
13+
// Ensure assets located outside the workspace root work with the dev server
14+
{ 'input': outsideDirectoryName, 'glob': '**/*', 'output': './outside' },
15+
];
16+
});
17+
18+
await mkdir(outsideDirectoryName);
19+
try {
20+
await writeFile(`${outsideDirectoryName}/some-asset.xyz`, 'XYZ');
21+
22+
const port = await ngServe();
23+
24+
let response = await fetch(`http://localhost:${port}/favicon.ico`);
25+
assert.strictEqual(response.status, 200);
26+
27+
response = await fetch(`http://localhost:${port}/outside/some-asset.xyz`);
28+
assert.strictEqual(response.status, 200);
29+
assert.strictEqual(await response.text(), 'XYZ');
30+
31+
// A non-existent file is assumed to be a potential route and will fallback to index.html
32+
response = await fetch(`http://localhost:${port}/does-not-exist.png`);
33+
assert.strictEqual(response.status, 200);
34+
assert.match(await response.text(), /<html/);
35+
} finally {
36+
await rm(outsideDirectoryName, { force: true, recursive: true });
37+
}
38+
}

0 commit comments

Comments
 (0)