Skip to content

fix(h3): explicitly set compiler, messageResolver and localeFallbacker#182

Open
MikeBellika wants to merge 1 commit intointlify:mainfrom
MikeBellika:main
Open

fix(h3): explicitly set compiler, messageResolver and localeFallbacker#182
MikeBellika wants to merge 1 commit intointlify:mainfrom
MikeBellika:main

Conversation

@MikeBellika
Copy link

@MikeBellika MikeBellika commented Feb 25, 2026

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

export default defineI18nLocaleDetector((event, config) => {
  if (event.context.i18n) {
    event.context.i18n.messageResolver = resolveValue
  }
// rest of the locale detector

in my localeDetector.ts

Summary by CodeRabbit

Bug Fixes

  • Fixed the intlify middleware to ensure message compilation, resolution, and locale fallback features are properly initialized and consistently available at runtime, improving reliability across different build configurations.

@coderabbitai
Copy link

coderabbitai bot commented Feb 25, 2026

📝 Walkthrough

Walkthrough

This 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

Cohort / File(s) Summary
Runtime Context Setup
packages/h3/src/index.ts
Added imports from @intlify/core (resolveValue, compile, fallbackWithLocaleChain) and explicitly set intlify.messageCompiler, intlify.messageResolver, and intlify.localeFallbacker in the onRequest handler to guarantee runtime initialization despite tree-shaking.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

🐰 A hoppy fix for tree-shake woes,
Where rabbit code and intlify flows,
No sneaky removal shall pass the gate,
When contexts are set to synchronize fate! 🌍✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main fix: explicitly setting three runtime components (compiler, messageResolver, localeFallbacker) to prevent tree-shaking issues.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

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 | 🟠 Major

Move the static assignments out of onRequest and guard against overwriting user-provided options.

Lines 207-209 assign compile-time constants (compile, resolveValue, fallbackWithLocaleChain) on every request. There are two concrete problems:

  1. Wrong lifecycle — these are static initialization values, not per-request state. onRequest fires for every incoming request; executing these assignments every time is wasteful.
  2. Silently clobbers user-provided options — if a consumer passes a custom messageCompiler, messageResolver, or locale fallbacker in options, 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 as undefined, 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.locale
     onRequest: 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 as undefined, ??= fills them in. If createCoreContext already 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. resolveWithKeyValue instead of undefined), you may need an explicit comparison against the known bad value rather than a nullish check — worth verifying against what createCoreContext stores 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 | 🟠 Major

Move the static assignments out of onRequest and into initialization; guard against overwriting user-provided options.

There are two related problems with placing lines 38-40 inside onRequest:

  1. Wrong lifecycle — these three values are static defaults, not per-request state. Assigning them on every incoming request is unnecessary overhead.
  2. Silently clobbers user options — if a consumer passes a custom messageCompiler, messageResolver, or fallback function in their options, createCoreContext wires 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.locale
     onRequest: 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.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 343be42 and 9f1d0a9.

📒 Files selected for processing (1)
  • packages/h3/src/index.ts

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