Walk this on a QA SSR build. A miss here is a 19 regression unless the last chapter says otherwise. What changed in the bump lives in Angular 15 to 19.

Boot this, not that

The build that ships

Put nvm Node 20.19.6 first. Machine default 24 will fight you. Then:

npm run prerender-all-qaPORT=4100 npm run serve:ssrThat is dist/TopFans/server/server.mjs after a qa prerender.

A qa --prerender=false build is fine for click-through. It is not the artifact you upload.

Skip as gates

  • npm run build-dev is the wrong env and the wrong output shape.
  • ng lint still OOMs. It did that on 18.
  • ng test has no specs worth running.
  • Docker is not this list.
  • ng serve / node:start is Vite. Use it to poke HMR, not to sign off SSR.

What 19 actually moved

ThingPass when
AngularHTML has ng-version="19.2.25"
TypeScript / zone5.8.3 and 0.15.1 in package.json
CommonEngineImport is @angular/ssr/node, not @angular/ssr
Hostsserver.ts and angular.json both list loopback plus *.topfan.dev / *.topfan.com
ComponentsNgModule decls carry standalone: false
Scriptsstart is HMR-on. start:no-hmr exists. No dev:ssr, no start:hmr

Held on purpose

PrimeNG 17stay A PrimeNG 18/19 bump is a separate fight.
ngx-quill 16, intl-tel 15, stripe 18, audio 17stay Peers were forced. If those UIs work, do not "upgrade them while you are here."
Express server.tsstay Do not swap in the CLI default server. White-label host picking lives here.

Hit Express first

v19 CommonEngine refuses hosts that are not on the allowlist and falls back to the CSR shell. That looks like a 10ms empty page. Fix the allowlist, then click product.

Request
Trailing slash
  • /login/ is 301 to /login
  • Query string survives
Request
Unknown path
  • Garbage URL is HTTP 404
  • Not a 200 blank shell
Request
Query string
  • /creators?key= is live SSR
  • Not a prerender page that dropped the key
Trap
Loopback SSR
  • curl 127.0.0.1 must be fat HTML
  • Empty 119k shell means hosts

After prerender, both dist/TopFans/browser/index.html and index.csr.html exist. Live SSR uses the CSR file as the engine document.

Public pages that must still render

PathPass when
/auth/loginForm chrome is there. Submit success is not the gate.
/auth/forgot-passwordSame. Page paints.
/pricingPlans show. No empty layout.
/aboutCopy and layout survive.
/musicBrowser lands on /music-artists.
/wallet while logged outAuthGuard sends you to login. That is success.

Logged-in money and media

These need a real session. Compile-green is not a pass.

CheckPass when
Home feedPosts load. Like, comment, share on a normal post still open the old bootstrap/ng-bootstrap modals, not a crash.
WalletCurrent balance paints. Masked phone / amount fields still take keystrokes.
Create PlanName + benefit + open 1 Month + a Total Price of 1 or more enables Create Plan. Empty price stays disabled. That disable is old. Do not file it.
StripeA test payment or Connect flow completes. Package is still ngx-stripe 18.
AudioA portfolio track plays. Player stayed on 17.
VideoA video.js or IVS post plays. Close and reopen is not a dead player.
Phone inputsngx-intl-tel-input 15 country dropdown still works on contact or personal info.
ToastsA success and an error toast still appear and dismiss. ngx-toastr 19 made them OnPush.

Reels sheets are the Material 19 path

Angular Material in this app is only MatBottomSheet. It mounts on a reel at viewport ≤992px. Desktop tip / likes / share are ngx-bootstrap or ng-bootstrap. Those still inject Material tokens, so open them once on a wide window to prove they do not throw.

Log in. Open a reel. Narrow the window. You want the full-screen reel chrome with like, comment, tip, share on the right.

IconPass when
CommentsSheet opens with the current reel's comments. Close, swipe to the next reel, open again. Data matches the new reel.
LikesList of likers. Scroll stays inside the sheet.
TipAmounts work. Cancel closes with no charge. Confirm still pays.
Share, logged inCopy link / share options. Close dismisses.
Share, logged outLogin modal. Not a blank sheet.

The sheet will look a bit wrong

Look
White padding around a dark comments panel. Square top corners. Default Material chrome instead of the 24px radius and #002740 fill.
Cause
Our CSS still targets .mat-mdc-bottom-sheet-container. Material 19 renamed the host to .mat-bottom-sheet-container. Overlay sits on body, so theme-nested rules miss it too.
Call
File it as known 19 chrome, not as "comments are broken." Open, list, dismiss, next-reel data. If those work, the feature works. Restyle later.

Do not "fix" it by adding a /.well-known JSON file. That was a Vite overlay hack, reverted, and it does not belong in prerender output.

One white-label tenant

Generator copies TopFans build config, then stamps the tenant theme. Prove one QA tenant. Restore generator artifacts. Do not commit them, and do not commit environment.ts.

  • qa --prerender=false for that project succeeds.
  • SSR title and theme match the tenant. Login stays branded.
  • /creators vs cover behaves like 18 for that tenant.

Leave dirty on the machine

  • src/environments/environment.ts if you pointed it at QA.
  • Prefetch marketing files after prerender-all-qa.
  • A cloned tenant in angular.json. Pull it out after the smoke or getDistFolder will pick the wrong dist.

The red Vite overlay is Chrome

Look
[plugin:vite:json] Failed to parse JSON file on /.well-known/appspecific/com.chrome.devtools.json.
Cause
Chrome probes that URL on localhost so DevTools can map the folder. Angular 19's Vite 6 treats any .json path as a module, gets index.html, and the overlay screams. Express serve:ssr never does this.
Call
Dismiss it. Do not ship a dummy JSON into dist/ to shut it up. Later CLI versions added a middleware. We are on 19.2.27, which does not have it.

Do not file as a 19 bug

  • Create Plan disabled when 1 Month is selected and Total Price is empty. That is checkFormDisable from before.
  • ng lint running out of memory.
  • PrimeNG still saga-blue. That stay is the upgrade decision.
  • Prefetch-generated marketing files changing after prerender-all-qa. Restore them. Do not merge them.
  • HMR on ng serve by default. If styles ghost, npm run start:no-hmr.

Scripts you should see

package.jsonstart            ng serve          (style HMR on)start:no-hmr     ng serve --no-hmrnode:start       10GB heap + serveserve:ssr        Express from distgone             start:hmr, dev:hmr, node:start:hmr, dev:ssr

If SSR hosts work and a logged-in reel can open and close those four sheets, 19 is in. The white frame on the sheet is homework, not a rollback.

Branch feature/release-0.0.23/16-17-18-19. Companion: Angular 15 to 19.