2024年适配浏览器与Node.js的TypeScript库module配置咨询
适配Node.js SSR与浏览器环境的TypeScript库配置方案
1. tsconfig.json的module选项配置
如果要同时兼容CJS和ESM生态,建议拆分两个tsconfig文件分别编译:
- 针对CJS版本(
tsconfig.cjs.json):{ "extends": "./tsconfig.json", "compilerOptions": { "module": "CommonJS", "outDir": "./lib/cjs", "declarationDir": "./lib/types" } } - 针对ESM版本(
tsconfig.esm.json):{ "extends": "./tsconfig.json", "compilerOptions": { "module": "NodeNext", "moduleResolution": "NodeNext", "outDir": "./lib/esm", "declarationDir": "./lib/types" } } - 主
tsconfig.json保留通用配置:比如target设为ES2020(兼顾Node.js v12+和现代浏览器),开启declaration: true生成类型文件。
如果只做ESM单版本,直接在主配置里设module: "NodeNext"即可——webpack完全兼容该输出,动态导入的bundle拆分逻辑也能正常工作。
2. 是否需要发布双版本并配置package.json
必须发布CJS+ESM双版本,核心原因:
- 仍有大量Node.js项目依赖
require()导入CJS模块,直接切换ESM会引发兼容性故障; - webpack等构建工具会自动优先读取ESM版本,实现更高效的tree-shaking和动态bundle拆分,而Node.js SSR场景若处于CommonJS环境,也能通过CJS版本正常运行。
package.json配置示例:
{ "name": "your-library", "type": "module", // 标记默认模块类型为ESM "main": "./lib/cjs/index.js", "module": "./lib/esm/index.js", "types": "./lib/types/index.d.ts", "exports": { ".": { "require": "./lib/cjs/index.js", "import": "./lib/esm/index.js", "types": "./lib/types/index.d.ts" } }, "scripts": { "build": "tsc -p tsconfig.cjs.json && tsc -p tsconfig.esm.json" } }
exports是Node.js v12+支持的标准字段,可精准区分require和import的导入路径;- 类型文件统一输出到
lib/types,避免重复生成。
3. ESM适配双环境的最佳实践
无需单独为某一环境保留CJS,只要做好以下配置即可同时适配Node.js和浏览器:
- 用
NodeNext输出的ESM模块,Node.js可直接识别(配合package.json的type: "module"),浏览器端webpack会自动处理模块路径(比如补全.js后缀); - 若使用Node.js专属API(如
fs、path),需添加环境判断:if (typeof window === 'undefined') { // Node.js SSR逻辑 import('fs').then(fs => { /* 处理文件操作 */ }); } else { // 浏览器端逻辑 } - 动态导入使用标准
import()语法,webpack会自动拆分bundle,ESM下的tree-shaking效果比CJS更彻底。
内容的提问来源于stack exchange,提问作者Flion
相关产品推荐
相关产品推荐

