@angular/build: lazy routes get no SSR modulepreload hints when the app's tsconfig is not at the workspace root (ɵentryName relative to basePath, chunk map relative to workspace root)
Maintainer thường phản hồi trong vòng 1 ngày
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức phù hợp với người mới
- 25/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- typescript
- Lĩnh vực
- build-system
Hướng nghiên cứu
The mismatch sits between packages/angular/build/src/tools/angular/transformers/lazy-routes-transformer.ts (around line 151, where ɵentryName is made relative to basePath) and packages/angular/build/src/utils/server-rendering/manifest.ts (around line 262, where entryPointToBrowserMapping is keyed by esbuild's entryPoint, relative to absWorkingDir). Reproduce with the issue's steps, where the tsconfig sits in projects/site/, and confirm that preload is empty in angular-app-manifest.mjs. Done means both sides use the same base, so routes get modulepreload hints regardless of tsconfig location, and the existing workspace-root case still passes its tests.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Command
build
Is this a regression?
- Yes, this behavior used to work in the previous version
The previous version in which this bug was not present was
No response
Description
When an application's tsconfig.app.json is not at the workspace root, SSR adds no <link rel="modulepreload"> for any lazy route. That includes the CLI's own multi-project layout (ng generate application puts it in projects/<name>/) and every Nx workspace. The routes are written in the shape lazyRoutesTransformer recognises, and the pages render correctly. Only the hints are missing, and nothing warns about it.
Cause. The two sides of the lookup use different base directories:
lazyRoutesTransformerstampsɵentryNameas a path relative tocompilerOptions.basePath(lazy-routes-transformer.ts#L151). The compiler setsbasePathto the directory of the tsconfig, hereprojects/site.generateLazyLoadedFilesMappingskeysentryPointToBrowserMappingby esbuild'sentryPoint(manifest.ts#L262). That path is relative toabsWorkingDir, which is the workspace root (application-code-bundle.ts#L631).
So the stamp reads src/app/home/home.ts and the key reads projects/site/src/app/home/home.ts. appendPreloadToMetadata finds nothing and every route's preload stays empty. When the tsconfig is at the workspace root, as in a default ng new, the two bases happen to coincide, which is probably why this has gone unnoticed.
projects/site/tsconfig.app.json |
ɵentryName in the server bundle |
preload in angular-app-manifest.mjs |
route hints in index.html / pricing/index.html |
|---|---|---|---|
| as generated | src/app/home/home.ts |
none | 0 / 0 |
"angularCompilerOptions": { "basePath": "." } added |
projects/site/src/app/home/home.ts |
on both routes | 1 / 1 (the route's own chunk) |
Workaround. "angularCompilerOptions": { "basePath": "." } in the app's tsconfig. It works only because the value is read raw and resolved against the process cwd, and the build happens to run from the workspace root.
Expected. Route hints do not depend on where the tsconfig lives. One option is for the transformer to stamp paths relative to the workspace root, which the builder already knows, instead of relative to basePath.
Real-world impact. In our Nx workspace (22 lazy routes, @nx/angular:application, which delegates to buildApplication unchanged), no route had ever received a hint. With the workaround every route does. On the home page, the shell route's chunk finishes 5.8 s earlier in throttled Lighthouse runs (mobile, devtools throttling, 8× CPU, 5 runs), and TTI drops by 1.3 s.
Minimal Reproduction
npx -p @angular/[email protected] ng new ws --create-application=false --skip-git --package-manager=npm --defaults --ai-config=none
cd ws
npx ng generate application site --ssr --routing --style=css --skip-tests --defaults
projects/site/src/app/app.routes.ts
import { Routes } from '@angular/router';
export const routes: Routes = [
{ path: '', loadComponent: () => import('./home/home').then((m) => m.Home) },
{
path: 'pricing',
loadComponent: () => import('./pricing/pricing').then((m) => m.Pricing),
},
];
projects/site/src/app/home/home.ts (and pricing/pricing.ts, the same with Pricing)
import { Component } from '@angular/core';
@Component({ selector: 'app-home', template: '<h1>Home</h1>' })
export class Home {}
npx ng build site
grep -c '"preload"' dist/site/server/angular-app-manifest.mjs # 0
grep -o '<link rel="modulepreload"[^>]*>' dist/site/browser/index.html # only the shared initial chunk
grep -rhoE 'entryName:"[^"]*"' dist/site/server/*.mjs # src/app/home/home.ts, src/app/pricing/pricing.ts
Then add "angularCompilerOptions": { "basePath": "." } to projects/site/tsconfig.app.json and build again. Both routes get preload, each page gets its own chunk's hint, and the stamps become projects/site/src/app/….
Exception or Error
None. The build succeeds and the pages render; only the lazy-route modulepreload hints are missing.
Your Environment
Angular CLI : 22.2.3
Angular : 22.2.3
Node.js : 24.20.0
Package Manager : npm 11.19.0
Operating System : darwin arm64
@angular/build 22.2.3
@angular/cli 22.2.3
@angular/common 22.2.3
@angular/compiler 22.2.3
@angular/compiler-cli 22.2.3
@angular/core 22.2.3
@angular/platform-browser 22.2.3
@angular/platform-server 22.2.3
@angular/router 22.2.3
@angular/ssr 22.2.3
typescript 6.0.3
Anything else relevant?
Also observed on 22.2.1, in our Nx workspace. The transformer's relative(basePath, …) is unchanged since it was introduced in 8d7a51dfc ("feat(@angular/ssr): add modulepreload for lazy-loaded routes").
- Ngôn ngữ chính
- TypeScript
- Star
- 27k
- Fork
- 11.8k
- Merge trung bình
- 1 ngày 3 giờ
- Pull request đã merge (30 ngày)
- 193
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của angular/angular-cli
-
area: @angular/cli
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
angular/angular-cli#34307 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Can't use an array of hostnames in --allowedHosts cli parameter in @angular/build:dev-serverĐang mởarea: @angular/build gemini-triaged
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 74/100
angular/angular-cli#33955 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
area: @angular/cli gemini-triaged
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
angular/angular-cli#33055 · 1 bình luận · 3 reaction ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Angular SSR redirects can take healthy proxies upstreams out of rotation through an unbounded Location headerCó thể đã có người làm @SkyZeroZx đã nhận 1 ngày trước. Đang mởarea: @angular/ssr
Độ khó 3/5 Nửa ngày Mức phù hợp với người mới 30/100
angular/angular-cli#34365 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
`ng serve` crashes with `EMFILE: too many open files, watch` on macOS when `preserveSymlinks` is enabled (22.2 regression)Có thể đã có người làm @clydin đã nhận 1 ngày trước. Đang mởarea: @angular/build
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 48/100
angular/angular-cli#34312 ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của angular/angular-cli
Issue tương tự
-
bnv-manager-v2: accept_invite creates the Mailcow domain admin before the commitCó thể đã có người làm @myOmikron đã nhận hôm nay. Đang mởbug ready-for-agent
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
-
Windows: mio 1.2.3 named-pipe use-after-free panics the native IPC broker and hangs every toolĐang mởplatform:windows tool triaged wontfix
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
nicolettas-muggelbude/RechnungsFee#448 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Android bug feature/error-tracking react-native team/error-tracking
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
PostHog/posthog-js#5310 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày