Skip to content

🔥 feat(web-sdk_angular): Add Angular Universal (SSR) support [NT-3467]#330

Draft
Felipe Mamud (fmamud) wants to merge 1 commit into
mainfrom
NT-3467-angular-ssr
Draft

🔥 feat(web-sdk_angular): Add Angular Universal (SSR) support [NT-3467]#330
Felipe Mamud (fmamud) wants to merge 1 commit into
mainfrom
NT-3467-angular-ssr

Conversation

@fmamud

Copy link
Copy Markdown
Contributor

Summary

  • Extends implementations/web-sdk_angular with Angular Universal SSR. Server-side SDK initialisation uses @contentful/optimization-node via a conditional dynamic import; the browser
    keeps using @contentful/optimization-web unchanged.
  • Resolved entries cross the hydration boundary through TransferState. Anonymous-id continuity is preserved across runtimes via a Set-Cookie written by the server preflight.
  • HTTP layer follows the existing node-sdk reference: express@5.2.1 + express-rate-limit@8.2.1, mounted on @angular/ssr/node's AngularNodeAppEngine.

What changed

  • SSR boilerplatesrc/main.server.ts, src/server.ts, src/app/app.config.server.ts, src/app/app.routes.server.ts. angular.json gains server, outputMode: "server", and
    ssr.entry. package.json adds @angular/ssr, @angular/platform-server, express, express-rate-limit, and a start script.
  • Server-side SDK preflightsrc/app/services/optimization-server.ts dynamic-imports @contentful/optimization-node, reads consent + anonymous-id cookies from Angular's REQUEST
    token, calls forRequest({ consent }).page(), runs resolveOptimizedEntry() per baseline, persists the anonymous-id back via RESPONSE_INIT, and stamps TransferState.
  • HydrationprovideClientHydration(withEventReplay()) on the browser side. src/app/services/entry.ts falls back to TransferState when the browser SDK is absent (server runtime).
    src/app/services/contentful-client.ts loadEntries short-circuits when the server already fetched the baselines.
  • Browser-only SDK serviceNgContentfulOptimization constructs @contentful/optimization-web only when isPlatformBrowser. SDK call sites in components and services use null-safe
    chains so server render skips browser-only side effects without a separate adapter type.

Why

Per the ticket implementation notes, "the existing browser SDK works cleanly in the SSR context without special-casing" was preferred — but the browser SDK touches localStorage at construction, which crashes server-side. The fallback the notes explicitly allow is used: @contentful/optimization-node for server-side SDK initialisation, conditional dynamic imports for runtime separation. There are no unsafe type assertions: server modules use the Node SDK with its real types; browser modules use the Web SDK with its real types; only ResolvedEntry data crosses the boundary, via TransferState.

A future Angular adapter package will extract these helpers into @contentful/optimization-angular and replace the in-impl wiring.

Test plan

  • pnpm implementation:run -- web-sdk_angular typecheck
  • pnpm exec eslint implementations/web-sdk_angular
  • pnpm implementation:run -- web-sdk_angular build — emits dist/web-sdk_angular/{browser,server}/
  • Dev server smoke (pnpm implementation:run -- web-sdk_angular dev + mocks):
    • Initial HTML carries ng-server-context="ssr"
    • With cookie: app-personalization-consent=granted: data-ctfl-variant-index, data-ctfl-optimization-id populated server-side; Set-Cookie: ctfl-opt-aid=… returned
    • Without consent: server skips Experience API; data-ctfl-baseline-id rendered; browser SDK takes over after hydration
    • /page-two route also serves SSR'd HTML
    • Server log shows Resolving optimized entry for baseline entry … and has been resolved to variant entry … lines per request
  • Reviewer: open http://localhost:4200 in a browser and exercise consent / identify / reset / live-updates / preview panel post-hydration
  • Reviewer: run shared E2E suite — pnpm test:e2e:web-sdk_angular (existing scenarios were authored against the SPA; SSR-specific assertions are intentionally deferred)

@wiz-inc-38d59fb8d7

Copy link
Copy Markdown

Wiz Scan Summary

Scanner Findings
Vulnerability Finding Vulnerabilities 1 High
Data Finding Sensitive Data -
Secret Finding Secrets -
IaC Misconfiguration IaC Misconfigurations -
SAST Finding SAST Findings -
Software Management Finding Software Management Findings -
Total 1 High

View scan details in Wiz

To detect these findings earlier in the dev lifecycle, try using Wiz Code VS Code Extension.

"@contentful/rich-text-types": "^17.2.7",
"contentful": "^11.12.4",
"express": "5.2.1",
"express-rate-limit": "8.2.1",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

High Vulnerability Finding

The following vulnerability impacts express-rate-limit versions <8.2.2: CVE-2026-30827.

It can be remediated by updating to version 8.2.2 or higher.

To ignore this finding as an exception, reply to this conversation with #wiz_ignore reason

If you'd like to ignore this finding in all future scans, add an exception in the .wiz file (learn more) or create an Ignore Rule (learn more).

To get more details on how to remediate this issue using AI, reply to this conversation with #wiz remediate

Suggested change
"express-rate-limit": "8.2.1",
"express-rate-limit": "8.2.2",

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant