npm 包輸出 es/cjs 產物
在開發一個 npm 包時,通常需要同時輸出 ES 模塊和 CommonJS 模塊的產物供不同的構建進行使用。在只使用tsc
進行產物編譯的情況下,我們通常可以通過配置兩個獨立的 tsconfig.json
配置文件,并在一個 npm script 中 執行兩次 tsc 命令來實現
項目結構
假設我們的項目結構如下:
my-package/
├── src/
│ └── index.ts
├── dist/
│ ├── es/
│ └── cjs/
├── package.json
├── tsconfig.es.json
└── tsconfig.cjs.json
配置 TypeScript
tsconfig.es.json
為 ES 模塊創建一個 tsconfig.es.json
文件:
{"compilerOptions": {"rootDir": "src","module": "ESNext","moduleResolution": "Node","outDir": "dist/es"},"include": ["src"]
}
tsconfig.cjs.json
為 CommonJS 模塊創建一個 tsconfig.cjs.json
文件:
{"compilerOptions": {"rootDir": "src","module": "CommonJS","moduleResolution": "Node","outDir": "dist/cjs"},"include": ["src"]
}
配置構建腳本
在 package.json 中,我們可以添加以下腳本來構建我們的項目,執行兩次 tsc 并分別指定不同的配置文件
{"scripts": {"build": "tsc -p tsconfig.es.json && tsc -p tsconfig.cjs.json",}
}
通過運行 npm run build,可以生成同時包含 ES 模塊和 CommonJS 模塊的產物
TypeScript 的 references 是什么
TypeScript 的項目引用(Project References)是 TypeScript 3.0 引入的一項功能,允許一個 TypeScript 項目引用另一個 TypeScript 項目。這使得我們可以將大型代碼庫拆分為多個較小的項目,并且這些項目可以相互依賴
Project References 的好處
- 增量編譯:當項目引用被正確配置時,TypeScript 只會重新編譯發生變化的部分,從而大幅提升編譯速度。
- 模塊化:通過項目引用,可以將代碼庫拆分為多個獨立的、可復用的模塊,提升代碼的可維護性和可讀性。
- 類型安全:項目引用確保了項目之間的類型安全,避免了類型不一致的問題。
配置
要使用項目引用,需要在 tsconfig.json 中添加 references
字段。例如:
{"compilerOptions": {"composite": true,"declaration": true,"outDir": "./dist"},"include": ["src"],"references": [{ "path": "../other-project" }]
}
相應的子項目需要存在相應的tsconfig.json
配置,并且配置compilerOptions.composite=true
,這樣才能被主項目引用。如
{"compilerOptions": {"composite": true,"types": [],"rootDir": "src","module": "ESNext","moduleResolution": "Node","outDir": "dist"}
}
使用 TypeScript 的 references 后如何實現一個命令 tsc 輸出 ES 和 CommonJS 產物并且提升增量編譯的性能
仍以上面的項目結構為例子,我們使用 TypeScript 的項目引用來實現這個需求。
項目結構
假設我們的項目結構如下:
my-package/
├── src/
│ └── index.ts
├── dist/
│ ├── es/
│ └── cjs/
├── package.json
├── tsconfig.json
├── tsconfig.base.json
├── tsconfig.es.json
└── tsconfig.cjs.json
首先,我們需要在根目錄下創建一個 tsconfig.json 文件,用于配置項目引用:
{"files": [],"references": [{ "path": "./tsconfig.es.json" },{ "path": "./tsconfig.cjs.json" }]
}
配置 tsconfig.es.json
為 ES 模塊創建一個 tsconfig.es.json 文件:
{"extends": "./tsconfig.base.json","compilerOptions": {"outDir": "./dist/es","module": "ESNext"}}
配置 tsconfig.cjs.json
為 CommonJS 模塊創建一個 tsconfig.cjs.json 文件:
{"extends": "./tsconfig.base.json","compilerOptions": {"outDir": "./dist/cjs","module": "CommonJS"}
}
公共配置 tsconfig.base.json
為了避免重復配置,我們可以創建一個 tsconfig.base.json 文件,包含通用的配置:
{"compilerOptions": {"target": "ES5","declaration": true,"moduleResolution": "node","esModuleInterop": true,"skipLibCheck": true,"composite": true,"rootDir": "src"},"include": ["src"]
}
構建腳本
在 package.json 中,我們可以添加以下腳本來構建我們的項目
{"scripts": {"build": "tsc -b"}
}
此時我們不再需要執行兩次 tsc 命令,而是只需要執行一次 tsc -b 命令即可輸出符合我們需求的 es + cjs 產物(和上面的兩次執行 tsc
是一樣的效果)。
在這個場景下 TypeScript 會根據項目引用的配置,自動構建 ES 模塊和 CommonJS 模塊,并且只會重新編譯發生變化的部分,從而提升增量編譯的性能