You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将ES6格式的node_modules依赖转译为CommonJS并纳入npm包?

解决Node.js CommonJS包中导入ES6模块依赖的问题

方案1:用tsup打包(推荐,配置简单)

tsup基于esbuild,能快速将TS代码和指定的ES6依赖一起打包成CommonJS,无需复杂配置。

  • 安装依赖:
    npm install tsup typescript --save-dev

  • 创建tsup.config.ts:

import { defineConfig } from 'tsup'

export default defineConfig({
  entry: ['src/index.ts'], // 你的入口文件路径
  format: 'cjs', // 输出CommonJS格式
  outDir: 'dist', // 构建输出目录
  noExternal: ['es6-dep-package', 'another-es6-dep'], // 填入需要转译的ES6依赖包名
  target: 'node16', // 适配你的Node运行版本
  clean: true, // 构建前清空dist目录
  dts: true, // 生成类型声明文件(按需开启)
})
  • 修改package.json的脚本和配置:
{
  "scripts": {
    "build": "tsup"
  },
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "files": ["dist"]
}

执行npm run build后,dist目录会包含打包后的CommonJS代码和所有指定的ES6依赖,发布时直接提交dist即可。

方案2:用Rollup定制打包

Rollup适合更精细的模块打包控制,能精准选择要打包的ES6依赖。

  • 安装依赖:
    npm install rollup @rollup/plugin-node-resolve @rollup/plugin-commonjs @rollup/plugin-typescript @rollup/plugin-babel @babel/preset-env --save-dev

  • 创建rollup.config.js:

import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import typescript from '@rollup/plugin-typescript';
import babel from '@rollup/plugin-babel';

export default {
  input: 'src/index.ts',
  output: {
    file: 'dist/index.js',
    format: 'cjs',
    sourcemap: true
  },
  plugins: [
    resolve({ preferBuiltins: true }), // 解析node_modules中的模块
    commonjs(), // 将CommonJS模块转成ES6格式以便Rollup处理
    typescript(), // 处理TS代码
    babel({
      babelHelpers: 'bundled',
      presets: [['@babel/preset-env', { targets: { node: '16' } }]],
      exclude: /node_modules\/(?!es6-dep-package)/ // 只转译指定的ES6依赖
    })
  ],
  external: ['fs', 'path'] // 填入不需要打包的Node内置模块或其他CommonJS依赖
};
  • 同样在package.json配置build脚本和files字段,确保dist目录被纳入发布范围。

方案3:用Babel单独转译指定ES6依赖

如果你不想整体打包,只想转译特定依赖并纳入构建产物:

  • 修改babel.config.json,允许转译指定的node_modules包:
{
  "presets": [
    ["@babel/preset-env", { "targets": { "node": "16" } }],
    "@babel/preset-typescript"
  ],
  "exclude": /node_modules\/(?!es6-dep-package)/
}
  • 编写脚本转译目标依赖到dist目录,比如创建scripts/transpile-deps.js:
const fs = require('fs-extra');
const { transformFileSync } = require('@babel/core');
const path = require('path');

const depPath = path.join(__dirname, '../node_modules/es6-dep-package');
const outputPath = path.join(__dirname, '../dist/node_modules/es6-dep-package');

// 递归转译文件
function transpileDir(src, dest) {
  fs.ensureDirSync(dest);
  const files = fs.readdirSync(src);
  for (const file of files) {
    const srcFile = path.join(src, file);
    const destFile = path.join(dest, file);
    if (fs.statSync(srcFile).isDirectory()) {
      transpileDir(srcFile, destFile);
    } else if (file.endsWith('.js') || file.endsWith('.ts')) {
      const result = transformFileSync(srcFile, { configFile: path.join(__dirname, '../babel.config.json') });
      fs.writeFileSync(destFile.replace(/\.ts$/, '.js'), result.code);
    } else {
      fs.copyFileSync(srcFile, destFile);
    }
  }
}

transpileDir(depPath, outputPath);
  • 修改package.json的build脚本,先转译依赖再构建自己的代码:
{
  "scripts": {
    "transpile-deps": "node scripts/transpile-deps.js",
    "build": "npm run transpile-deps && tsc",
  },
  "main": "dist/index.js",
  "files": ["dist"]
}

转译后的依赖会在dist/node_modules下,发布时会被包含,你的代码可以直接导入该依赖(Node会优先读取dist下的node_modules)。

关键注意事项

  • Babel可以转译node_modules中的模块,只要修改exclude配置,精确包含需要处理的包,避免全局转译所有node_modules导致构建变慢。
  • 确保package.json的files数组包含所有需要发布的文件(比如dist目录),避免转译后的依赖被遗漏。
  • 测试构建后的包:在本地用npm pack生成tgz包,然后在另一个项目中安装测试,确认可以通过require正常加载,且依赖能正常运行。

内容的提问来源于stack exchange,提问作者Jeff Pettis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 21:10:36