Skip to content

Node export condition ignored in plain Node.js - loads generic build instead of node-specific build #2387

@franzgollhammer

Description

@franzgollhammer

Reporting a bug?

When importing vue-i18n in a Node.js ESM environment, the generic vue-i18n.mjs file is loaded instead of the Node-specific vue-i18n.node.mjs file, unless the --conditions=node flag is explicitly passed.

Root cause: In package.json exports, the "import" condition appears before "node", causing Node.js to match the generic ESM file first and never evaluate the node-specific conditions.

Impact: This causes runtime errors in Node.js production environments:

ReferenceError: __VUE_PROD_DEVTOOLS__ is not defined

The browser build (vue-i18n.mjs) expects browser globals that don't exist in Node.js, particularly in production mode.

Versions:

  • Node.js: 24.13.0
  • vue: 3.5.27
  • vue-i18n: 11.2.8

Expected behavior

When running plain Node.js (no bundler) with ESM imports like:

import { createI18n } from 'vue-i18n'

Node.js should automatically load vue-i18n.node.mjs (the Node-specific build) instead of vue-i18n.mjs (the generic ESM build), without throwing ReferenceError: __VUE_PROD_DEVTOOLS__ is not defined or similar errors when using createSSRApp() for server-side rendering in production mode.

Reproduction

// test.js
import { fileURLToPath } from 'url'
import { createSSRApp } from 'vue'
import { createI18n } from 'vue-i18n'
import { renderToString } from 'vue/server-renderer'

console.log('NODE_ENV:', process.env.NODE_ENV)
console.log('Loaded file:', fileURLToPath(import.meta.resolve('vue-i18n')))

const app = createSSRApp({
  template: '{{ $t("hello") }}',
})

const i18n = createI18n({
  locale: 'en',
  messages: { en: { hello: 'Hello' } },
})

app.use(i18n)

const html = await renderToString(app)
console.log(html)

Run with:

NODE_ENV=production node test.js

Error:

ReferenceError: __VUE_PROD_DEVTOOLS__ is not defined

Output shows wrong file loaded:

NODE_ENV: production
Loaded file: .../node_modules/vue-i18n/dist/vue-i18n.mjs

The generic vue-i18n.mjs build expects compile-time globals like __VUE_PROD_DEVTOOLS__ to be defined (typically by a bundler), but they don't exist in plain Node.js environments, especially in production mode. The Node-specific build (vue-i18n.node.mjs) handles this correctly.

Current package.json exports structure:

".": {
  "types": "./dist/vue-i18n.d.ts",
  "import": "./dist/vue-i18n.mjs",      // ← Matches first in Node.js
  "browser": "./dist/vue-i18n.esm-browser.js",
  "node": {                              // ← Never evaluated
    "import": "./dist/vue-i18n.node.mjs",
    ...
  }
}

Proposed fix: Reorder conditions to prioritize "node" before "import":

".": {
  "types": "./dist/vue-i18n.d.ts",
  "node": {
    "import": "./dist/vue-i18n.node.mjs",
    "require": { ... }
  },
  "browser": "./dist/vue-i18n.esm-browser.js",
  "import": "./dist/vue-i18n.mjs"
}

Workaround:

NODE_ENV=production node --conditions=node test.js

Output with workaround:

Loaded file: .../node_modules/vue-i18n/dist/vue-i18n.node.mjs

System Info

**Environment:**
- Node.js: 24.13.0
- vue: 3.5.27
- vue-i18n: 11.2.8
- Module type: ESM
- NODE_ENV: production

Run the following command for full details:

npx envinfo --system --npmPackages '{vue*,@vue/*,vue-i18n*,@intlify/*,vite*,@vitejs/*}' --binaries --browsers

Screenshot

No response

Additional context

This affects plain Node.js server environments where vue-i18n is used for server-side i18n (not SSR with a bundler). The error only manifests when NODE_ENV=production.

My specific use case: Server-side email template rendering using createSSRApp():

const app = createSSRApp({
  template: `
    <EmailBase>
      <${templateName}
        v-bind="propsToPass"
      />
    </EmailBase>
  `,
  components: {
    EmailBase,
    [templateName]: validTemplateNames[templateName],
  },
  data () {
    return {
      propsToPass: templateProps,
    }
  },
})

The vue-i18n.mjs file is intended for bundler environments where compile-time globals like __VUE_PROD_DEVTOOLS__ are defined via define plugins. In plain Node.js, especially in production mode, these globals don't exist, causing runtime errors.

The workaround of using --conditions=node works but requires users to understand Node.js export conditions, which isn't documented in vue-i18n's setup guides.

Related Node.js documentation: https://nodejs.org/api/packages.html#conditional-exports

Validations

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions