Skip to content

Commit

Permalink
perf(@angular-devkit/build-angular): patch fetch to load assets fro…
Browse files Browse the repository at this point in the history
…m memory

This commit refactors the assets SSG asset loading from memory to use a patched version of `fetch` instead of spawning a separate server.
  • Loading branch information
alan-agius4 committed Oct 27, 2023
1 parent 6fbe520 commit 474768c
Show file tree
Hide file tree
Showing 11 changed files with 169 additions and 194 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@
"ts-node": "^10.9.1",
"tslib": "2.6.2",
"typescript": "5.2.2",
"undici": "5.27.0",
"verdaccio": "5.27.0",
"verdaccio-auth-memory": "^10.0.0",
"vite": "4.5.0",
Expand Down
1 change: 1 addition & 0 deletions packages/angular_devkit/build_angular/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ ts_library(
"@npm//tree-kill",
"@npm//tslib",
"@npm//typescript",
"@npm//undici",
"@npm//vite",
"@npm//webpack",
"@npm//webpack-dev-middleware",
Expand Down
1 change: 1 addition & 0 deletions packages/angular_devkit/build_angular/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
"text-table": "0.2.0",
"tree-kill": "1.2.2",
"tslib": "2.6.2",
"undici": "5.27.0",
"vite": "4.5.0",
"webpack": "5.89.0",
"webpack-dev-middleware": "6.1.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ async function extract(): Promise<string[]> {
);

const routes: string[] = [];
for await (const { route, success } of extractRoutes(bootstrapAppFnOrModule, document, '')) {
for await (const { route, success } of extractRoutes(bootstrapAppFnOrModule, document)) {
if (success) {
routes.push(route);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,11 @@ async function* getRoutesFromRouterConfig(
export async function* extractRoutes(
bootstrapAppFnOrModule: (() => Promise<ApplicationRef>) | Type<unknown>,
document: string,
url: string,
): AsyncIterableIterator<RouterResult> {
const platformRef = createPlatformFactory(platformCore, 'server', [
{
provide: INITIAL_CONFIG,
useValue: { document, url },
useValue: { document, url: '' },
},
{
provide: ɵConsole,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

import { lookup as lookupMimeType } from 'mrmime';
import { readFile } from 'node:fs/promises';
import { extname } from 'node:path';
import { workerData } from 'node:worker_threads';
import { Response, fetch } from 'undici';

/**
* This is passed as workerData when setting up the worker via the `piscina` package.
*/
const { assetFiles } = workerData as {
assetFiles: Record</** Destination */ string, /** Source */ string>;
};

const assetsCache: Map<string, { headers: undefined | Record<string, string>; content: Buffer }> =
new Map();

export function patchFetchToLoadInMemoryAssets(): void {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const global = globalThis as unknown as { fetch: typeof fetch };
const originalFetch = global.fetch;
const updatedFetch: typeof fetch = async (input, init) => {
let url: URL;
if (input instanceof URL) {
url = input;
} else if (typeof input === 'string') {
url = new URL(input, 'resolve://');
} else if (typeof input === 'object' && 'url' in input) {
url = new URL(input.url, 'resolve://');
} else {
return originalFetch(input, init);
}

const { pathname } = url;

const cachedAsset = assetsCache.get(pathname);
if (cachedAsset) {
const { content, headers } = cachedAsset;

return new Response(content, {
headers,
});
}

if (assetFiles[pathname]) {
const extension = extname(pathname);
const mimeType = lookupMimeType(extension);
const content = await readFile(assetFiles[pathname]);
const headers = mimeType
? {
'Content-Type': mimeType,
}
: undefined;

assetsCache.set(pathname, { headers, content });

return new Response(content, {
headers,
});
}

return originalFetch(input, init);
};

global.fetch = updatedFetch;
}

This file was deleted.

Loading

0 comments on commit 474768c

Please sign in to comment.