Skip to content

Commit 45f7c1a

Browse files
committed
fix(@angular-devkit/build-angular): serve assets from the provided serve-path
When the `serve-path` option is used assets are now correctly servered from this location. Closes #26509
1 parent 43f22f4 commit 45f7c1a

File tree

2 files changed

+33
-8
lines changed

2 files changed

+33
-8
lines changed

packages/angular_devkit/build_angular/src/builders/dev-server/tests/options/serve-path_spec.ts

+20-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ describeServeBuilder(
1818
(harness, setupTarget, isViteRun) => {
1919
describe('option: "servePath"', () => {
2020
beforeEach(async () => {
21-
setupTarget(harness);
21+
setupTarget(harness, {
22+
assets: ['src/assets'],
23+
});
2224

2325
// Application code is not needed for these tests
2426
await harness.writeFile('src/main.ts', 'console.log("foo");');
@@ -96,6 +98,23 @@ describeServeBuilder(
9698
expect(result?.success).toBeTrue();
9799
expect(await response?.text()).toContain('<title>');
98100
});
101+
102+
it('serves assets at specified path when option is used', async () => {
103+
await harness.writeFile('src/assets/test.txt', 'hello world!');
104+
105+
harness.useTarget('serve', {
106+
...BASE_OPTIONS,
107+
servePath: '/test',
108+
});
109+
110+
const { result, response } = await executeOnceAndFetch(harness, '/test/assets/test.txt', {
111+
// fallback processing requires an accept header
112+
request: { headers: { accept: 'text/html' } },
113+
});
114+
115+
expect(result?.success).toBeTrue();
116+
expect(await response?.text()).toContain('hello world');
117+
});
99118
});
100119
},
101120
);

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

+13-7
Original file line numberDiff line numberDiff line change
@@ -591,7 +591,12 @@ export async function setupServer(
591591
if (assetSourcePath !== undefined) {
592592
// The encoding needs to match what happens in the vite static middleware.
593593
// ref: https://github.com/vitejs/vite/blob/d4f13bd81468961c8c926438e815ab6b1c82735e/packages/vite/src/node/server/middlewares/static.ts#L163
594-
req.url = `/@fs/${encodeURI(assetSourcePath)}`;
594+
let { servePath = '' } = serverOptions;
595+
if (servePath) {
596+
servePath = addLeadingSlash(servePath);
597+
}
598+
599+
req.url = `${serverOptions.servePath}/@fs/${encodeURI(assetSourcePath)}`;
595600
next();
596601

597602
return;
@@ -801,19 +806,20 @@ async function loadViteClientCode(file: string) {
801806
return contents;
802807
}
803808

804-
function pathnameWithoutServePath(url: string, serverOptions: NormalizedDevServerOptions): string {
809+
function pathnameWithoutServePath(url: string, { servePath }: NormalizedDevServerOptions): string {
805810
const parsedUrl = new URL(url, 'http://localhost');
806811
let pathname = decodeURIComponent(parsedUrl.pathname);
807-
if (serverOptions.servePath && pathname.startsWith(serverOptions.servePath)) {
808-
pathname = pathname.slice(serverOptions.servePath.length);
809-
if (pathname[0] !== '/') {
810-
pathname = '/' + pathname;
811-
}
812+
if (servePath && pathname.startsWith(servePath)) {
813+
pathname = addLeadingSlash(pathname.slice(servePath.length));
812814
}
813815

814816
return pathname;
815817
}
816818

819+
function addLeadingSlash(value: string): string {
820+
return value.charAt(0) === '/' ? value : '/' + value;
821+
}
822+
817823
type ViteEsBuildPlugin = NonNullable<
818824
NonNullable<DepOptimizationConfig['esbuildOptions']>['plugins']
819825
>[0];

0 commit comments

Comments
 (0)