diff --git a/packages/angular/build/src/tools/vite/plugins/angular-memory-plugin.ts b/packages/angular/build/src/tools/vite/plugins/angular-memory-plugin.ts index dc83f131f299..92fd7ac7df54 100644 --- a/packages/angular/build/src/tools/vite/plugins/angular-memory-plugin.ts +++ b/packages/angular/build/src/tools/vite/plugins/angular-memory-plugin.ts @@ -8,7 +8,7 @@ import assert from 'node:assert'; import { readFile } from 'node:fs/promises'; -import { dirname, join, relative } from 'node:path'; +import { basename, dirname, join, relative } from 'node:path'; import type { Plugin } from 'vite'; import { loadEsmModule } from '../../../utils/load-esm'; import { AngularMemoryOutputFiles } from '../utils'; @@ -51,6 +51,18 @@ export async function createAngularMemoryPlugin( // Remove query if present const [importerFile] = importer.split('?', 1); source = '/' + join(dirname(relative(virtualProjectRoot, importerFile)), source); + } else if ( + !ssr && + source[0] === '/' && + importer.endsWith('index.html') && + normalizePath(importer).startsWith(virtualProjectRoot) + ) { + // This is only needed when using SSR and `angularSsrMiddleware` (old style) to correctly resolve + // .js files when using lazy-loading. + // Remove query if present + const [importerFile] = importer.split('?', 1); + source = + '/' + join(dirname(relative(virtualProjectRoot, importerFile)), basename(source)); } } diff --git a/tests/legacy-cli/e2e/tests/vite/ssr-no-server-entry-sub-path.ts b/tests/legacy-cli/e2e/tests/vite/ssr-no-server-entry-sub-path.ts new file mode 100644 index 000000000000..a55f48d0b39f --- /dev/null +++ b/tests/legacy-cli/e2e/tests/vite/ssr-no-server-entry-sub-path.ts @@ -0,0 +1,53 @@ +import assert from 'node:assert'; +import { + execAndWaitForOutputToMatch, + ng, + silentNg, + waitForAnyProcessOutputToMatch, +} from '../../utils/process'; +import { installWorkspacePackages, uninstallPackage } from '../../utils/packages'; +import { useSha } from '../../utils/project'; +import { getGlobalVariable } from '../../utils/env'; +import { findFreePort } from '../../utils/network'; +import { writeFile } from '../../utils/fs'; + +export default async function () { + assert( + getGlobalVariable('argv')['esbuild'], + 'This test should not be called in the Webpack suite.', + ); + + // Forcibly remove in case another test doesn't clean itself up. + await uninstallPackage('@angular/ssr'); + await ng('add', '@angular/ssr', '--no-server-routing', '--skip-confirmation', '--skip-install'); + await useSha(); + await installWorkspacePackages(); + + await silentNg('generate', 'component', 'home'); + await writeFile( + 'src/app/app.routes.ts', + ` + import { Routes } from '@angular/router'; + import {HomeComponent} from './home/home.component'; + + export const routes: Routes = [{ + path: 'sub/home', + component: HomeComponent + }]; + `, + ); + + const port = await findFreePort(); + await execAndWaitForOutputToMatch('ng', ['serve', '--port', `${port}`], /complete/, { + NO_COLOR: 'true', + }); + + const [, response] = await Promise.all([ + assert.rejects( + waitForAnyProcessOutputToMatch(/Pre-transform error: Failed to load url/, 8_000), + ), + fetch(`http://localhost:${port}/sub/home`), + ]); + + assert(response.ok, `Expected 'response.ok' to be 'true'.`); +}