让你的npmPackage同时支持cjs和mjs

介绍

CJSCommonJS)是一种用于在服务器端和旧版浏览器中组织和导入/导出 JavaScript 代码的模块系统, 后缀名为 .cjs。 它使用 requiremodule.exports 语法来导入和导出模块。CJS 模块是同步加载的,这意味着在导入模块时,代码会阻塞执行直到模块加载完成。

MJSESMECMAScript 模块)是 ECMAScript 6ES6)引入的官方 JavaScript 模块系统, 后缀名为 .mjs。它使用 importexport 语法来导入和导出模块。MJS 模块是异步加载的,这意味着在导入模块时,代码会继续执行,而不会阻塞。

CJSMJS 之间的主要区别在于语法和加载方式。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 同时使用 requireimport, 于是看到后面的其他封装类库的引入都变成了 require 形式 ,这样不太方便,因为在 vue 项目里我是希望有些封装的函数能直接操作 vue 实例和 store 的,但是他们都仅支持 import 导入, 这样我 util 里封装的函数就被迫以只能通过参数的形式传递 vue 实例和 store :::

解决思路

我们将 npm 包编译成 cjsmjs 各一份,用户在 import 时,就返回 mjs 文件,如果是使用 require, 就返回 cjs 文件 ,这样在不同的场景就可以灵活使用了

目录说明

拿我其中一个 @muyi086/var-type 的包举例, 这是项目目录结构

varType_tree
  1. lib目录存放核心代码, 后续用 esbuildindex.ts 文件编译成 cjsmjs 两份

  2. package.json.npmignore 分别存放项目配置和忽略文件

  3. readme.md 保存文档说明,LICENSE 保存开源协议

实现

其中最重要的是 package.jsonesbuild 编译的配置

  1. package.json 我们增加如下代码, 这样我们通过 requireimport 就会导入不同的文件

  2. esbuild 编译 index.tscjsmjs 两份

具体代码如下

::: code-group

:::

最后

packagenpmjs 后,我们就可以通过包名下载使用了

参考

Last updated

Was this helpful?