让我们的 npm 包同时支持 CommonJS 和 ES modules

随着 JavaScript 生态系统的不断发展,ES Modules (ESM) 已经逐渐成为现代 JavaScript 项目的标准模块系统。然而,许多现有的项目仍然依赖于 CommonJS (CJS) 模块系统。为了确保我们的 npm 包能够兼容这两种模块系统,我们需要进行一些配置和代码调整。

本文将详细介绍如何让你的 npm 包同时支持 CommonJS 和 ES Modules。

1. 项目结构

首先,让我们来看一下项目的初始结构:

my-package/
├── dist/
│ ├── index.cjs
│ ├── index.mjs
├── package.json
├── .gitignore
├── README.md
  • dist/index.cjs:CommonJS 版本的入口文件。
  • dist/index.mjs:ES Modules 版本的入口文件。
  • package.json:项目的配置文件。

2. 编写代码

2.1 CommonJS 版本

dist/index.cjs 中编写 CommonJS 版本的代码:

// dist/index.cjs
module.exports = {
greet: function (name) {
return `Hello, ${name}!`;
}
};

2.2 ES Modules 版本

dist/index.mjs 中编写 ES Modules 版本的代码:

// dist/index.mjs
export function greet(name) {
return `Hello, ${name}!`;
}

3. 配置 package.json

为了让 npm 包同时支持 CommonJS 和 ES Modules,我们需要在 package.json 中进行一些配置。

{
"name": "my-package",
"version": "1.0.0",
"description": "A package that supports both CommonJS and ES Modules",
"main": "dist/index.cjs",
"module": "dist/index.mjs",
"type": "module",
"scripts": {
"build": "tsc",
"prepublishOnly": "npm run build"
},
"types": "dist/index.d.ts",
"files": ["dist/"],
"dependencies": {},
"devDependencies": {
"typescript": "^4.5.0"
}
}

3.1 主要配置项

  • main:指定 CommonJS 入口文件。
  • module:指定 ES Modules 入口文件。
  • type:设置为 "module",表示整个包默认使用 ES Modules。
  • scripts:定义构建脚本。
  • types:指定 TypeScript 类型定义文件。
  • files:指定包含在发布的包中的文件。

4. 使用 TypeScript 进行编译

为了确保代码的一致性和类型安全性,我们可以使用 TypeScript 进行编译。首先,安装 TypeScript:

npm install typescript --save-dev

然后,创建 tsconfig.json 文件:

{
"compilerOptions": {
"target": "es2015",
"module": "commonjs",
"outDir": "dist",
"rootDir": "src",
"declaration": true,
"moduleResolution": "node",
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src"]
}

4.1 编译命令

package.json 中添加构建脚本:

{
"scripts": {
"build": "tsc",
}
}

运行 npm run build 将会编译 TypeScript 代码,并生成 dist 目录中的 CommonJS 和 ES Modules 文件。

5. 测试

为了确保我们的包在不同的模块系统中都能正常工作,我们可以编写一些测试用例。

5.1 CommonJS 测试

// test/cjs.test.js
const { greet } = require('../dist/index.cjs');

test('greet function works with CommonJS', () => {
expect(greet('World')).toBe('Hello, World!');
});

5.2 ES Modules 测试

// test/esm.test.mjs
import { greet } from '../dist/index.mjs';

test('greet function works with ES Modules', () => {
expect(greet('World')).toBe('Hello, World!');
});

5.3 运行测试

安装测试框架,例如 Jest:

npm install jest --save-dev

package.json 中添加测试脚本:

{
"scripts": {
"test": "jest"
}
}

运行测试:

npm test

6. 发布

确保你的 package.json 文件中包含所有必要的配置,并且 dist 目录中的文件已经生成。然后,发布你的包到 npm:

npm publish

7. 总结

通过上述步骤,我们成功地让 npm 包同时支持 CommonJS 和 ES Modules。这样做不仅提高了包的兼容性,还确保了未来的可维护性和扩展性。

希望这篇文章对你有所帮助,如果你有任何问题或建议,请随时留言交流!