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

如何在TypeScript编译ESM与CJS时为单个文件提供不同版本?

TypeScript同时编译ESM/CJS时实现文件版本自动匹配的方案

你可以通过TypeScript的paths路径映射结合双tsconfig配置,实现同一导入路径在ESM/CJS编译产物中自动对应不同版本的文件,无需额外打包工具或构建后处理。

核心思路

  1. 为条件导入逻辑准备两个TypeScript源文件(区分CJS/ESM版本)
  2. 在两个tsconfig中分别配置paths,将统一的导入路径映射到对应版本的源文件
  3. 分别编译CJS和ESM产物到不同目录,确保导入逻辑自动适配环境

具体步骤

1. 源码文件结构

在源码目录下创建两个版本的条件导入文件,其余代码保持统一:

src/
├── try-import.cjs.ts   # CJS版本的条件导入逻辑
├── try-import.esm.ts   # ESM版本的条件导入逻辑
├── try-import.types.ts # 可选:抽离共用类型定义
└── other-file.ts       # 其他业务代码,统一导入try-import

CJS版本源文件(try-import.cjs.ts)

import type { SomeExportType } from './try-import.types';

let mod: { someExport: SomeExportType } | undefined;
try {
  mod = require('something');
  console.log('Imported successfully');
} catch (e) {
  console.error('Package not found');
}

export const x = mod?.someExport ?? null;

ESM版本源文件(try-import.esm.ts)

import type { SomeExportType } from './try-import.types';

let mod: { someExport: SomeExportType } | undefined;
try {
  mod = await import('something');
  console.log('Imported!');
} catch (e) {
  console.error('Package not found');
}

export const x = mod?.someExport ?? null;

共用类型定义(try-import.types.ts,可选)

export type SomeExportType = { /* 你的类型定义 */ };

2. 配置双tsconfig文件

CJS编译配置(tsconfig.cjs.json)

{
  "compilerOptions": {
    "module": "CommonJS",
    "target": "ES2018",
    "outDir": "./dist/cjs",
    "rootDir": "./src",
    "baseUrl": ".",
    "paths": {
      "./try-import": ["./src/try-import.cjs.ts"]
    },
    "declaration": true
  },
  "include": ["src/**/*"]
}

ESM编译配置(tsconfig.esm.json)

{
  "compilerOptions": {
    "module": "ESNext",
    "target": "ES2022", // 需支持模块级await
    "outDir": "./dist/esm",
    "rootDir": "./src",
    "baseUrl": ".",
    "paths": {
      "./try-import": ["./src/try-import.esm.ts"]
    },
    "declaration": true
  },
  "include": ["src/**/*"]
}

3. 统一导入逻辑

在所有业务代码中,直接使用统一路径导入:

// src/other-file.ts
import { x } from './try-import';

// 正常使用x即可,编译时会自动匹配对应版本

4. 编译脚本

在package.json中添加编译命令,分别编译CJS和ESM产物:

{
  "scripts": {
    "build:cjs": "tsc -p tsconfig.cjs.json",
    "build:esm": "tsc -p tsconfig.esm.json",
    "build": "npm run build:cjs && npm run build:esm"
  },
  "main": "./dist/cjs/index.js",
  "module": "./dist/esm/index.js",
  "types": "./dist/cjs/index.d.ts" // 或合并类型到单独目录
}

关键注意事项

  • 确保两个tsconfig的rootDir一致,保证输出目录结构与源码匹配
  • ESM版本需设置module为ESNext/ES2022+,以支持模块级await
  • 若需要统一类型输出,可单独配置一个tsconfig.types.json专门生成类型文件,避免重复编译
  • 两个版本的导出内容需保持类型一致,建议通过共用类型文件约束

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 20:44:53