让你的npmPackage同时支持cjs和mjs
介绍
CJS(CommonJS)是一种用于在服务器端和旧版浏览器中组织和导入/导出 JavaScript 代码的模块系统, 后缀名为 .cjs。 它使用 require 和 module.exports 语法来导入和导出模块。CJS 模块是同步加载的,这意味着在导入模块时,代码会阻塞执行直到模块加载完成。
MJS(ESM,ECMAScript 模块)是 ECMAScript 6(ES6)引入的官方 JavaScript 模块系统, 后缀名为 .mjs。它使用 import 和export 语法来导入和导出模块。MJS 模块是异步加载的,这意味着在导入模块时,代码会继续执行,而不会阻塞。
CJS 和 MJS 之间的主要区别在于语法和加载方式。CJS 适用于服务器端和旧版浏览器,而 MJS 适用于现代浏览器和支持 ES6 模块的环境。
问题场景
让我们看下这段来自 util.js 的代码
:::code-group
const { qs } = require('@muyi086/qs') // [!code warning]
const { varType } = require('@muyi086/var-type') // [!code warning]
const authHttp = require('./authHttp')
const apiUser = require('./api/api_user')
const basicHttp = require('./common/basicHttp')
const uniUtil = require('./common/uniUtil')
const publicUtil = require('./common/publicUtil')
const { abortAllRequest, isAllRequestOver } = basicHttp
const { commonViewTap, getCurrentPageUrlWithArgs, getMiniPage } = uniUtil
const { newTimeStamp, formatDate, renderTodayTomorrowSoOn, transWeekDay, formatDateTime, randomStrFromCharCode } = publicUtil
const { config } = require('./configAll')
const storage = require('./storage')
const { stringify, parse } = qs:::
::: warning 注意 高亮的俩行是引入的外部 CJS 模块,也就是发布时 npm package 导出的方式为 module.exports = xxx
由于我们不能在一个 js 同时使用 require 和 import, 于是看到后面的其他封装类库的引入都变成了 require 形式 ,这样不太方便,因为在 vue 项目里我是希望有些封装的函数能直接操作 vue 实例和 store 的,但是他们都仅支持 import 导入, 这样我 util 里封装的函数就被迫以只能通过参数的形式传递 vue 实例和 store :::
解决思路
我们将 npm 包编译成 cjs 和 mjs 各一份,用户在 import 时,就返回 mjs 文件,如果是使用 require, 就返回 cjs 文件 ,这样在不同的场景就可以灵活使用了
目录说明
拿我其中一个 @muyi086/var-type 的包举例, 这是项目目录结构

lib目录存放核心代码, 后续用esbuild将index.ts文件编译成cjs和mjs两份package.json和.npmignore分别存放项目配置和忽略文件readme.md保存文档说明,LICENSE保存开源协议
实现
其中最重要的是 package.json 和 esbuild 编译的配置
package.json我们增加如下代码, 这样我们通过require和import就会导入不同的文件esbuild编译index.ts成cjs和mjs两份
具体代码如下
::: code-group
:::
最后
将 package 到 npmjs 后,我们就可以通过包名下载使用了
参考
Last updated
Was this helpful?