fix(nextjs-config): warn when withPostHogConfig is not the outermost wrapper#3585
fix(nextjs-config): warn when withPostHogConfig is not the outermost wrapper#3585Ashut0sh-mishra wants to merge 3 commits into
Conversation
…wrapper withPostHogConfig returns an async function that Next.js calls during build init. If a downstream wrapper (e.g. withNextIntl, withSentryConfig) consumes that function and produces its own plain-object config without delegating, Next.js never calls our function, so the webpack/compiler hooks that upload source maps silently never run. Even with debug logging enabled the user sees zero output — no error, no warning, just a missing build step. Detect that by setting an invoked flag inside the returned function and scheduling a 5s unref'd setTimeout that warns if the flag is still false. When Next.js (or any outer wrapper) does call our function, the flag flips before the timer fires and no warning is emitted. The timer is .unref()'d so it never holds the process open by itself. The warning points the user at the fix (move withPostHogConfig to be the outermost wrapper) and links the tracking issue. Closes PostHog#3572 Co-authored-by: nik464 <nik464@users.noreply.github.com>
|
@Ashut0sh-mishra is attempting to deploy a commit to the PostHog Team on Vercel. A member of the Team first needs to authorize it. |
Prompt To Fix All With AIFix the following 2 code review issues. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 2
packages/nextjs-config/src/config.ts:59-62
The multi-step runtime type-guard for `unref()` is more complex than necessary (violates simplicity rule 4). Optional chaining via a single cast achieves the same result in one expression and doesn't need a separate `if` branch.
```suggestion
// Allow the Node process to exit normally even if our timer is pending.
;(timer as unknown as { unref?: () => void }).unref?.()
```
### Issue 2 of 2
packages/nextjs-config/src/config.ts:47-58
**False positive when config is imported outside a Next.js build**
If `next.config.js` is evaluated in a context that never goes through the full Next.js build pipeline — e.g. a Jest/Vitest test that imports the config file for assertions, or a custom script that reads the config object directly — `nextConfigFn` is never called and the 5-second warning fires. The user's setup may be perfectly correct, but they'd still see a misleading warning after 5 s of running their test suite. A comment (or an opt-out flag in `posthogConfig`) documenting this known false-positive would help, and the 5-second constant being named (e.g. `INVOCATION_TIMEOUT_MS`) would make the threshold easy to adjust.
Reviews (1): Last reviewed commit: "fix(nextjs-config): warn when withPostHo..." | Re-trigger Greptile |
…tant Addresses greptile review on PostHog#3585: - Replace the multi-step runtime type-guard for `unref()` with a single optional-chaining call. Same null-safety, simpler code, satisfies the repo's simplicity convention (rule PostHog#4). - Extract the 5000ms literal into `INVOCATION_TIMEOUT_MS` for clarity and easy future tuning. - Document the known false-positive when `next.config.js` is imported outside the Next.js build pipeline (e.g. test contexts). Co-authored-by: nik464 <nik464@users.noreply.github.com>
|
Thanks @greptile-apps! Addressed both:
Pushed. |
1 similar comment
|
Thanks @greptile-apps! Addressed both:
Pushed. |
|
The changes look good. Both items are well-handled:
The decision to document the false-positive rather than add an opt-out flag is sound. The warning is One minor observation: LGTM overall. |
|
Both changes look good. The optional-chain cast One minor nit: Otherwise this looks ready to merge. |
|
Reviews (2): Last reviewed commit: "refactor(nextjs-config): simplify unref(..." | Re-trigger Greptile |
Addresses greptile minor nit on PostHog#3585: the constant is configuration, not per-call state, so move it to module scope alongside the other module-level declarations. Avoids re-creation on every call and makes it easier to spot for future tuning. Co-authored-by: nik464 <nik464@users.noreply.github.com>
|
Reviews (3): Last reviewed commit: "refactor(nextjs-config): hoist INVOCATIO..." | Re-trigger Greptile |
|
Thanks @greptile-apps -- fair point. Hoisted INVOCATION_TIMEOUT_MS to module scope so it sits with the other module-level declarations and isn't re-created per call. Pushed. |
|
Confirmed — |
Problem
If
withPostHogConfigis not the outermost wrapper innext.config.js— e.g.
withNextIntl(withPostHogConfig(config, { ... }))— the PostHogbuild plugin silently never runs. No source maps upload, no errors, no
logs even with
logLevel: 'debug'. MovingwithPostHogConfigto bethe last wrapper makes it work as expected.
Root cause:
withPostHogConfigreturns an async function that Next.jscalls during build init. If a downstream wrapper consumes that function
and returns its own plain-object config without delegating, Next.js
never invokes our function, so the webpack/compiler hooks the plugin
adds never run.
Closes #3572
Fix
Set an
invokedflag inside the returned config function and schedulea
.unref()-ed 5-secondsetTimeoutthat prints a clear warning ifthe flag is still
false. When Next.js (or any properly delegatingouter wrapper) does call our function, the flag flips before the timer
fires and no warning is emitted.
The warning tells the user:
withPostHogConfigto be the outermost wrapper).It also links the tracking issue for context.
Notes:
.unref()ensures the timer never holds the Node process open byitself.
in the happy path (no extra work, just a flag flip on invocation).