npm 发布的 package 如何支持 commonjs 与 es module

169 阅读1分钟

最近需要写一些基础代码同时在 Node 和 前端项目中使用,于是想如何以 node package 的形式同时支持 Node 和 前端。

例:

// index.ts

export const a = () => console.log("hello");

这份代码如果直接通过 tsc 以 "module": "commonjs" 编译 ,前端则无法使用:

The requested module '省略路径/index.js' does not provide an export named 'a'

但是如果以 "module": "ESNext" 编译,Node 则无法使用:

SyntaxError: Unexpected token 'export'

如何让一份代码即可以在 前端 使用,也可以在 Node(后端)使用 ?

通过查看 Node 的文档(英文 | 中文) 可以得知,package.json 支持多种加载方式:

"exports": {
  "import": "es module 模式时 加载文件",
  "require": "common js 模式时 加载文件",
  "types": ".d.ts 所在位置"
},

注:exports 的优先级大于 main。

所以只需要分别打对应的包,通过 exports 指定位置即可。

打包可以借助 rollup 来实现

pnpm add rollup @rollup/plugin-typescript -D

rollup.config.mjs 配置文件:

import typescript from "@rollup/plugin-typescript";

/**
 * @type {import('rollup').RollupOptions}
 */
const config = {
  plugins: [typescript()],

  input: "index.ts",
  output: [
    {
      file: "dist/c.js",
      format: "cjs",
    },
    {
      file: "dist/m.js",
      format: "es",
    },
  ],
};
export default config;

如果需要压缩,可以使用 @rollup/plugin-terser 插件

package.json 关键部分:

{
  "exports": {
    "import": "./dist/m.js",
    "require": "./dist/c.js",
    "types": "./dist/index.d.ts"
  },

  "scripts": {
    "build": "rollup -c"
  },

  "devDependencies": {
    "@rollup/plugin-typescript": "^11.1.6",
    "rollup": "^4.18.0"
  }
}

tsconfig.json 部分节选:

{
  "compilerOptions": {
    /* Visit https://aka.ms/tsconfig.json to read more about this file */
    "target": "ESNext" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */,
    "module": "ESNext" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
    "declaration": true /*如果需要 .d.ts 文件,就打开这个 */,
    "outDir": "./dist",
    "rootDir": "./"
  }
}

参考 demo 地址:gitee.com/expup/xd-pa…

参考

segmentfault.com/q/101000004…