diff --git a/packages/angular_devkit/build_angular/src/utils/server-rendering/esm-in-memory-file-loader.ts b/packages/angular_devkit/build_angular/src/utils/server-rendering/esm-in-memory-file-loader.ts index fc253c6d3477..c6f2e89db82b 100644 --- a/packages/angular_devkit/build_angular/src/utils/server-rendering/esm-in-memory-file-loader.ts +++ b/packages/angular_devkit/build_angular/src/utils/server-rendering/esm-in-memory-file-loader.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import { join } from 'node:path'; +import { join, relative } from 'node:path'; +import { pathToFileURL } from 'node:url'; import { workerData } from 'node:worker_threads'; import { fileURLToPath } from 'url'; import { JavaScriptTransformer } from '../../tools/esbuild/javascript-transformer'; @@ -23,7 +24,7 @@ const { outputFiles, workspaceRoot } = workerData as { const TRANSFORMED_FILES: Record = {}; const CHUNKS_REGEXP = /file:\/\/\/(main\.server|chunk-\w+)\.mjs/; -const WORKSPACE_ROOT_FILE = new URL(join(workspaceRoot, 'index.mjs'), 'file:').href; +const WORKSPACE_ROOT_FILE = pathToFileURL(join(workspaceRoot, 'index.mjs')).href; const JAVASCRIPT_TRANSFORMER = new JavaScriptTransformer( // Always enable JIT linking to support applications built with and without AOT. @@ -44,7 +45,9 @@ export function resolve( return { format: 'module', shortCircuit: true, - url: new URL(normalizedSpecifier, 'file:').href, + // File URLs need to absolute. In Windows these also need to include the drive. + // The `/` will be resolved to the drive letter. + url: pathToFileURL('/' + normalizedSpecifier).href, }; } } @@ -60,8 +63,8 @@ export function resolve( export async function load(url: string, context: { format?: string | null }, nextLoad: Function) { if (isFileProtocol(url)) { const filePath = fileURLToPath(url); - let source = - outputFiles[filePath.slice(1)] /* Remove leading slash */ ?? TRANSFORMED_FILES[filePath]; + // Remove '/' or drive letter for Windows that was added in the above 'resolve'. + let source = outputFiles[relative('/', filePath)] ?? TRANSFORMED_FILES[filePath]; if (source === undefined) { source = TRANSFORMED_FILES[filePath] = Buffer.from( diff --git a/packages/angular_devkit/build_angular/src/utils/server-rendering/prerender.ts b/packages/angular_devkit/build_angular/src/utils/server-rendering/prerender.ts index d03d4821fd72..0d3ffeb18210 100644 --- a/packages/angular_devkit/build_angular/src/utils/server-rendering/prerender.ts +++ b/packages/angular_devkit/build_angular/src/utils/server-rendering/prerender.ts @@ -8,7 +8,8 @@ import { OutputFile } from 'esbuild'; import { readFile } from 'node:fs/promises'; -import { extname, posix } from 'node:path'; +import { extname, join, posix } from 'node:path'; +import { pathToFileURL } from 'node:url'; import Piscina from 'piscina'; import type { RenderResult, ServerContext } from './render-page'; import type { WorkerData } from './render-worker'; @@ -61,7 +62,7 @@ export async function prerenderPages( execArgv: [ '--no-warnings', // Suppress `ExperimentalWarning: Custom ESM Loaders is an experimental feature...`. '--loader', - require.resolve('./esm-in-memory-file-loader.js'), + pathToFileURL(join(__dirname, 'esm-in-memory-file-loader.js')).href, // Loader cannot be an absolute path on Windows. ], });