Skip to content

Commit

Permalink
fix(@angular-devkit/build-angular): return 404 for assets that are no…
Browse files Browse the repository at this point in the history
…t found

This commit updates the vite dev-server to return 404 for assets and files that are not found.

Closes #26917

(cherry picked from commit 8216b11)
  • Loading branch information
alan-agius4 committed Jan 24, 2024
1 parent e880531 commit 3deb0d4
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 5 deletions.
Expand Up @@ -41,6 +41,21 @@ describeServeBuilder(executeDevServer, DEV_SERVER_BUILDER_INFO, (harness, setupT

setupTarget(harness, {
assets: ['src/extra.ts'],
});

harness.useTarget('serve', {
...BASE_OPTIONS,
});

const { result, response } = await executeOnceAndFetch(harness, 'extra.ts');

expect(result?.success).toBeTrue();
expect(await response?.text()).toContain(javascriptFileContent);
});

it('should return 404 for non existing assets', async () => {
setupTarget(harness, {
assets: ['src/extra.js'],
optimization: {
scripts: true,
},
Expand All @@ -50,10 +65,10 @@ describeServeBuilder(executeDevServer, DEV_SERVER_BUILDER_INFO, (harness, setupT
...BASE_OPTIONS,
});

const { result, response } = await executeOnceAndFetch(harness, 'extra.ts');
const { result, response } = await executeOnceAndFetch(harness, 'extra.js');

expect(result?.success).toBeTrue();
expect(await response?.text()).toContain(javascriptFileContent);
expect(await response?.status).toBe(404);
});
});
});
Expand Up @@ -462,7 +462,7 @@ export async function setupServer(
publicDir: false,
esbuild: false,
mode: 'development',
appType: 'spa',
appType: 'mpa',
css: {
devSourcemap: true,
},
Expand Down
Expand Up @@ -90,6 +90,7 @@ export function createAngularMemoryPlugin(options: AngularMemoryPluginOptions):
map: mapContents && Buffer.from(mapContents).toString('utf-8'),
};
},
// eslint-disable-next-line max-lines-per-function
configureServer(server) {
const originalssrTransform = server.ssrTransform;
server.ssrTransform = async (code, map, url, originalCode) => {
Expand Down Expand Up @@ -169,6 +170,8 @@ export function createAngularMemoryPlugin(options: AngularMemoryPluginOptions):
// Returning a function, installs middleware after the main transform middleware but
// before the built-in HTML middleware
return () => {
server.middlewares.use(angularHtmlFallbackMiddleware);

function angularSSRMiddleware(
req: Connect.IncomingMessage,
res: ServerResponse,
Expand All @@ -180,8 +183,8 @@ export function createAngularMemoryPlugin(options: AngularMemoryPluginOptions):
// Skip if path is not defined.
!url ||
// Skip if path is like a file.
// NOTE: We use a regexp to mitigate against matching requests like: /browse/pl.0ef59752c0cd457dbf1391f08cbd936f
/^\.[a-z]{2,4}$/i.test(extname(url.split('?')[0]))
// NOTE: We use a mime type lookup to mitigate against matching requests like: /browse/pl.0ef59752c0cd457dbf1391f08cbd936f
lookupMimeTypeFromRequest(url)
) {
next();

Expand Down Expand Up @@ -306,3 +309,34 @@ function pathnameWithoutBasePath(url: string, basePath: string): string {
? pathname.slice(basePath.length - 1)
: pathname;
}

function angularHtmlFallbackMiddleware(
req: Connect.IncomingMessage,
res: ServerResponse,
next: Connect.NextFunction,
): void {
// Similar to how it is handled in vite
// https://github.com/vitejs/vite/blob/main/packages/vite/src/node/server/middlewares/htmlFallback.ts#L15C19-L15C45
if (
(req.method === 'GET' || req.method === 'HEAD') &&
(!req.url || !lookupMimeTypeFromRequest(req.url)) &&
(!req.headers.accept ||
req.headers.accept.includes('text/html') ||
req.headers.accept.includes('text/*') ||
req.headers.accept.includes('*/*'))
) {
req.url = '/index.html';
}

next();
}

function lookupMimeTypeFromRequest(url: string): string | undefined {
const extension = extname(url.split('?')[0]);

if (extension === '.ico') {
return 'image/x-icon';
}

return extension && lookupMimeType(extension);
}

0 comments on commit 3deb0d4

Please sign in to comment.