vue.jsvitees6-modulescommonjs

Universal way to use CommonJS in Javascript with ESM


ESM is the normalized way for module function in Javascript. But there are many CommonJs package in npm. Vite is good tools for change CommonJs to ESM, I want to use protobufjs in a vue project. The protobufjs in: https://github.com/protobufjs/protobuf.js/

It works in npm run dev. I want to build it for production environment, following the guide in: https://cn.vitejs.dev/config/build-options.html#build-commonjsoptions

vite.config.js

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import commonjs from '@rollup/plugin-commonjs'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    commonjs({
      include: /node_modules/,
    }),
    vue(),
  ]
})

I use it in vue as following:

<script setup>
import * as protobuf from "protobufjs";
console.log(protobuf.Enum)
</script>

Everything is ok when I run the npm run dev. I occurs error in npm run build:

src/App.vue (13:21): "Enum" is not exported by "node_modules/.pnpm/protobufjs@7.4.0/node_modules/protobufjs/index.js", imported by "
src/App.vue".

The example is simple, and config is also. But what result in the error?

Update at 2024/11/12

Vite is a simple tool to use CommonJs, UMD or AMD modules in ESM. It use esbuild in dev and @rollup/plugin-commonjs in prod by default. So we needn't do the config it explicitly.

Thanks for @Estus Flask a lot.


Solution

  • CommonJS modules aren't recognized in ESM environment and require additional module interoperation to work, such as @rollup/plugin-commonjs in Vite/Rollup build. Since Vite has different toolchains for dev and build, there can be discrepancies.

    The "universal" way is to use default import. It's less natural for CJS to be translated to * because the export is dynamic, it cannot use ESM traits such as tree-shaking, and can be not just an object but anything.

    This is defined by defaultIsModuleExports option, which can be changed if necessary. Transpiled ES modules are automatically recognized by default, this is commonly determined with __esModule property in module object.

    Since protobufjs is CJS/UMD module depending on entry point and not transpiled ESM, the correct way to use it:

    import protobuf from "protobufjs";
    

    It may be desirable to map entry point to UMD bundle for performance, with the same result expected:

    alias: { ..., protobufjs: "protobufjs/dist/protobuf.min.js" }
    

    @rollup/plugin-commonjs isn't needed to be explicitly configured, it's already provided with suitable configuration in Vite default configuration.