Skip to content

fix(nuxt): inject Nitro server chunks in SPA builds before upload - #4779

Open
posthog[bot] wants to merge 4 commits into
mainfrom
posthog-self-driving/fixnuxt-upload-source-maps-for-spa-294893
Open

fix(nuxt): inject Nitro server chunks in SPA builds before upload#4779
posthog[bot] wants to merge 4 commits into
mainfrom
posthog-self-driving/fixnuxt-upload-source-maps-for-spa-294893

Conversation

@posthog

@posthog posthog Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Problem

  • Every @posthog/nuxt SPA production build (ssr: false) with source maps enabled loses server-side symbolication, and each deploy adds an unwanted release.
  • A ssr: false build still gets a Nitro server bundle. The module skipped the server inject for it, then uploaded the whole .output directory, so the CLI hit server chunks that carry no chunk id and failed. The module catches that error, so the build stays green and the failure is silent.
  • The upload command carried no release flags, so the CLI derived a release from the checkout directory name — one extra release per deploy, next to the configured one.

Changes

  • The server inject now follows the server directory on disk instead of nuxt.options.ssr, so a SPA server bundle is injected and a nuxt generate build (no server bundle) is still skipped. This keeps #3005 fixed.
  • The upload is restricted to the directories that were injected — the server directory and the public directory — instead of the whole output directory.
  • --release-name, --release-version, and --build are now shared by inject and upload.
Build Before After
ssr: true inject server, upload all of .output inject + upload server, upload public
ssr: false, Nitro server bundle no inject, upload all of .output → CLI error inject + upload server, upload public
nuxt generate, no server bundle no inject, upload all of .output upload public only

Public source maps keep the existing two-step behaviour: they are uploaded and deleted before Nitro writes its asset manifest (#4275), and the close hook only uploads them when that early upload did not run or failed — without deleting them, because the manifest already lists them.

Release info Sub-libraries affected

Libraries affected

  • All of them
  • posthog-js (web)
  • posthog-js-lite (web lite)
  • posthog-node
  • posthog-react-native
  • @posthog/react-native-plugin
  • @posthog/react
  • @posthog/ai
  • @posthog/convex
  • @posthog/next
  • @posthog/nextjs-config
  • @posthog/nuxt
  • @posthog/openfeature-node-provider
  • @posthog/openfeature-web-provider
  • @posthog/rollup-plugin
  • @posthog/webpack-plugin
  • @posthog/types
  • @posthog/browser-common

Checklist

  • Tests for new code
  • Accounted for the impact of any changes across different platforms
  • Accounted for backwards compatibility of any changes (no breaking changes!)
  • Took care not to unnecessarily increase the bundle size

If releasing new changes

  • Ran pnpm changeset to generate a changeset file

🤖 Agent context

Autonomy: Fully autonomous

  • Agent: PostHog Desktop (Claude Code). Tools used: Bash, Read, Edit.
  • The earlier fix assumed ssr: false means "no server output". That holds for nuxt generate only. The disk check covers both builds with one rule.
  • Rejected: keeping the .output upload and adding an inject of the whole output directory. Injecting a preset directory that the module never controls is wider than the defect and can rewrite files the preset already hashed.
  • packages/nuxt/tests/sourcemaps-ssr.test.mjs gains a SPA case with a server bundle, a nuxt generate case, and a release-flag case. node tests/sourcemaps-ssr.test.mjs passes.
  • Not verified: pnpm lint and pnpm build. Workspace dependencies are not installed in this environment, and tests/nuxt5-consumer.test.mjs fails for the same reason, before and after this change.

Created with PostHog Desktop from this inbox report.

A `ssr: false` Nuxt build still produces a Nitro server bundle, but the module skipped the server inject and then uploaded the whole output directory. The CLI failed on the uninjected server chunks, so server exceptions had no symbolication. The upload also carried no release flags, so each deploy made a second release from the checkout directory name.

- Decide the server inject from the server directory on disk, not from `nuxt.options.ssr`.
- Upload only the injected directories (server and public) instead of the whole output directory.
- Pass the configured release name, version, and build to every source map command.

Generated-By: PostHog Desktop
Task-Id: 5c59904a-3a05-43e0-9c90-71ee91e183fd
@posthog

posthog Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

🦔 PostHog Review reviewed this pull request

Found 0 must fix, 0 should fix, 1 consider.

Published 1 finding (view the review).

Resolved comments: 1 fixed

@posthog

posthog Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

PostHog Review alpha 🦔 If you find any issues helpful - please reply "valid", "invalid", etc., for evaluation purposes 🙏

@posthog posthog Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

PostHog Review

Found 1 should fix.

Comment thread packages/nuxt/src/module.ts
The close hook ran the server inject, the server upload and the public upload in one try block, so a rejection from either server command jumped to the catch and skipped the public upload. With `deleteAfterUpload: false` the early hook uploads nothing, which makes the close hook the only client sourcemap upload of the build — a server-only failure silently removed client-side symbolication while the build stayed green.

- Give the server work and the public upload their own try blocks.
- Name the failing directory in each log line.
- Cover it with a `failServerUpload` case in tests/sourcemaps-ssr.test.mjs.

Generated-By: PostHog Desktop
Task-Id: 4f497a0e-0450-45ea-b2ac-20624c0789f5
@marandaneto marandaneto self-assigned this Sep 4, 2026
@marandaneto
marandaneto marked this pull request as ready for review September 4, 2026 12:38
@marandaneto
marandaneto requested review from a team as code owners September 4, 2026 12:38
@marandaneto

Copy link
Copy Markdown
Member

@PostHog/team-error-tracking i can reproduce this locally and looks good to me but i dont know nuxt enough, mind double checking?

@posthog posthog Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

PostHog Review

Found 1 consider.

Comment thread packages/nuxt/src/module.ts
…h deletion modes

The close hook uploaded the whole public directory whenever the early upload had
not run, which is every build with `deleteAfterUpload: false`. A Nitro preset may
nest the server directory inside the public one (`cloudflare-pages` writes
`dist/_worker.js` under `dist/`), so that upload walked the server chunks a second
time after the server upload had already sent them, and a failing server inject
took the public upload down with it.

The public upload now always runs in `nitro:build:public-assets`, which happens
before Nitro writes the server bundle, so it can never overlap the server tree.
The close hook keeps it only as a retry for a failed early upload.

Generated-By: PostHog Desktop
Task-Id: eacf25cc-c99b-40cb-ac6b-ee6cdd7970d0

@dustinbyrne dustinbyrne left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

no comments, still worth a look from @PostHog/team-error-tracking

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.

2 participants