fix(h3): explicitly set compiler, messageResolver and localeFallbacker#182
fix(h3): explicitly set compiler, messageResolver and localeFallbacker#182MikeBellika wants to merge 1 commit intointlify:mainfrom
Conversation
📝 WalkthroughWalkthroughThis change adds explicit runtime context component assignments within the h3 middleware to ensure intlify's message compiler, resolver, and fallback handler are properly wired, preventing tree-shaking from removing necessary functionality. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~8 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Tip Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs). Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
packages/h3/src/index.ts (2)
200-212:⚠️ Potential issue | 🟠 MajorMove the static assignments out of
onRequestand guard against overwriting user-provided options.Lines 207-209 assign compile-time constants (
compile,resolveValue,fallbackWithLocaleChain) on every request. There are two concrete problems:
- Wrong lifecycle — these are static initialization values, not per-request state.
onRequestfires for every incoming request; executing these assignments every time is wasteful.- Silently clobbers user-provided options — if a consumer passes a custom
messageCompiler,messageResolver, or locale fallbacker inoptions,createCoreContext(line 180) will wire them correctly, but the unconditional per-request assignment will overwrite them before any translation runs.The fix is to move these three lines immediately after
createCoreContext(line 180) and use??=so they only fill in values that tree-shaking may have left asundefined, without stomping on anything the user explicitly supplied.🛠️ Proposed fix
const intlify = createCoreContext(options as unknown as CoreOptions) + + // `@intlify/core`'s default bundler entry is runtime-only, and some bundlers (e.g. esbuild + // used by Cloudflare) may tree-shake the register* calls in core/src/index.ts. + // Assign these once at init time; ??= preserves any user-supplied overrides from options. + intlify.messageCompiler ??= compile + intlify.messageResolver ??= resolveValue + intlify.localeFallbacker ??= fallbackWithLocaleChain + const orgLocale = intlify.localeonRequest: onRequest(event => { const context = getEventContext<H3EventContext>(event) context[SYMBOL_INTLIFY_LOCALE] = getLocaleDetector(event, intlify as CoreContext) intlify.locale = context[SYMBOL_INTLIFY_LOCALE] - - // `@intlify/core` has `sideEffects: false`. Some bundlers (like esbuild, used by cloudflare), may tree-shake the `register` calls in `core/src/index.ts` - // To get around this, we can explicitly set the compiler, messageResolver, and localeFallbacker here - intlify.messageCompiler = compile - intlify.messageResolver = resolveValue - intlify.localeFallbacker = fallbackWithLocaleChain - context[SYMBOL_INTLIFY] = intlify as CoreContext }),Note on
??=: if tree-shaking leaves the fields asundefined,??=fills them in. IfcreateCoreContextalready set them from user options,??=leaves them untouched. If the concern is that tree-shaking causes them to be set to a wrong fallback (e.g.resolveWithKeyValueinstead ofundefined), you may need an explicit comparison against the known bad value rather than a nullish check — worth verifying against whatcreateCoreContextstores in these fields when the register calls are absent.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/h3/src/index.ts` around lines 200 - 212, The three static assignments to intlify.messageCompiler, intlify.messageResolver, and intlify.localeFallbacker are currently inside the onRequest handler and overwrite user-provided values on every request; move these three assignments out of onRequest to immediately after createCoreContext (where intlify is created) and replace the unconditional assignments with nullish-coalescing assignments (e.g. use ??=) so you only supply compile, resolveValue and fallbackWithLocaleChain when the fields are undefined, preserving any user-supplied options wired by createCoreContext and avoiding per-request work.
200-211:⚠️ Potential issue | 🟠 MajorMove the static assignments out of
onRequestand into initialization; guard against overwriting user-provided options.There are two related problems with placing lines 38-40 inside
onRequest:
- Wrong lifecycle — these three values are static defaults, not per-request state. Assigning them on every incoming request is unnecessary overhead.
- Silently clobbers user options — if a consumer passes a custom
messageCompiler,messageResolver, or fallback function in theiroptions,createCoreContextwires them correctly at line 11, but the unconditional assignment on every request overwrites them before the request is processed.The assignments should be placed once, immediately after
createCoreContext, using??=so they only fill in values that tree-shaking may have left undefined, while preserving anything the user explicitly supplied.Proposed fix
const intlify = createCoreContext(options as unknown as CoreOptions) + + // `@intlify/core` has `sideEffects: false`. Some bundlers (e.g. esbuild) + // may tree-shake the `register*` calls in core/src/index.ts. + // Assign the defaults once at init; ??= preserves user-supplied overrides. + intlify.messageCompiler ??= compile + intlify.messageResolver ??= resolveValue + intlify.localeFallbacker ??= fallbackWithLocaleChain + const orgLocale = intlify.localeonRequest: onRequest(event => { const context = getEventContext<H3EventContext>(event) context[SYMBOL_INTLIFY_LOCALE] = getLocaleDetector(event, intlify as CoreContext) intlify.locale = context[SYMBOL_INTLIFY_LOCALE] - - // `@intlify/core` has `sideEffects: false`. Some bundlers (like esbuild, used by cloudflare), may tree-shake the `register` calls in `core/src/index.ts` - // To get around this, we can explicitly set the compiler, messageResolver, and localeFallbacker here - intlify.messageCompiler = compile - intlify.messageResolver = resolveValue - intlify.localeFallbacker = fallbackWithLocaleChain - context[SYMBOL_INTLIFY] = intlify as CoreContext }),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/h3/src/index.ts` around lines 200 - 211, Move the static fallback assignments for intlify out of the per-request onRequest handler and into the initialization right after createCoreContext so they run once; specifically, after createCoreContext(...) set intlify.messageCompiler, intlify.messageResolver, and intlify.localeFallbacker using the nullish-assignment operator (??=) so you only fill in missing values left by tree-shaking and do not overwrite user-supplied options, then leave onRequest to only attach context (SYMBOL_INTLIFY and SYMBOL_INTLIFY_LOCALE) to the event.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@packages/h3/src/index.ts`:
- Around line 200-212: The three static assignments to intlify.messageCompiler,
intlify.messageResolver, and intlify.localeFallbacker are currently inside the
onRequest handler and overwrite user-provided values on every request; move
these three assignments out of onRequest to immediately after createCoreContext
(where intlify is created) and replace the unconditional assignments with
nullish-coalescing assignments (e.g. use ??=) so you only supply compile,
resolveValue and fallbackWithLocaleChain when the fields are undefined,
preserving any user-supplied options wired by createCoreContext and avoiding
per-request work.
- Around line 200-211: Move the static fallback assignments for intlify out of
the per-request onRequest handler and into the initialization right after
createCoreContext so they run once; specifically, after createCoreContext(...)
set intlify.messageCompiler, intlify.messageResolver, and
intlify.localeFallbacker using the nullish-assignment operator (??=) so you only
fill in missing values left by tree-shaking and do not overwrite user-supplied
options, then leave onRequest to only attach context (SYMBOL_INTLIFY and
SYMBOL_INTLIFY_LOCALE) to the event.
Description
Some bundlers strip out the register calls from vue-i18n/packages/core/src/index.ts
I think this is because the package has sideEffects: false in the package.json.
This PR explicitly sets the compiler, messageResolver and localeFallbacker.
Reproduction link
https://github.com/MikeBellika/h3-intlify-repro
There are instructions for how to run it in the readme.
Linked Issues
Additional context
I ran into this issue, when localizing my nuxt api on Cloudflare. Cloudflare uses esbuild, so the messageResolver was
resolveWithKeyValue.As a temporary workaround I have added
in my
localeDetector.tsSummary by CodeRabbit
Bug Fixes