Rollup + Babel打包JS库
Rollup + Babel打包JS库
初始化项目
yarn init
配置Babel
安装Babel和TS
@babel/core
Babel 核心包@babel/cli
Babel 命令行工具@babel/preset-env
Babel 兼容性整合包@babel/preset-typescript
Babel TypeScript 整合包typescript
TypeScript 编译器工具
yarn add -D @babel/core @babel/cli @babel/preset-env @babel/preset-typescript typescript
# 安装完毕后,初始化 TS 配置
yarn tsc --init
配置babel.config.json
{
"presets": [
"@babel/preset-env",
"@babel/preset-typescript"
]
}
测试配置生效与否:
const fn: Function = () => 1
Babel 默认只编译 JS 代码,所以要增加参数 --extensions
让 Babel 识别 TS
yarn babel --extensions '.ts' ./index.ts
源码
src/utils.ts
/** 保留N位小数,不执行四舍五入,保留0位小数=取整 */
export function formatDecimal(dec: number, fixes: number) {
//...
}
src/unit-transform.ts
import { formatDecimal } from './utils';
type TransformOptions = {
scale?: number;
unit: 'c' | 'f';
};
export function createUnitTransform(opts: TransformOptions) {
//...
}
入口文件src/index.ts
export * from './utils'
export * from './unit-transform'
export { createUnitTransform as default } from './unit-transform'
对开发者而言,这样更方便使用
// import { formatDecimal, createUnitTransform } from 'unit-transform'
// import createUnitTransform from 'unit-transform' 这里等同于 default
进行打包输出
Babel编译CJS
babel.config.json
只能配置单个输出,为了能针对特定的配置而生成不同的代码,这里要用到 .babelrc.json
配置文件,它的格式和 babel.config.json
一样。
{
"presets": [
"@babel/preset-env",
"@babel/preset-typescript"
]
}
显式指定配置,目标位置 dist/cjs
,编译 src/
的代码,同时生成 SourceMap
yarn babel --config-file ./.babelrc.cjs.json --extensions '.ts' -d dist/cjs/ src/
# 编译完毕,会在 dist/cjs 看到结果
# dist/cjs/index.js 由于是 CJS 格式,可以通过 node 命令行直接引用
# 例子: node -e 'console.log(require("./dist/cjs"))
Babel编译ESM
如果不用 TypeScript,源代码就是一份 ES Module 格式的代码,所以 Babel 在这里再编译一次可以视为仅仅把 TypeScript 转换成 JavaScript。
.babelrc.esm.json
配置文件:
{
"presets": [
["@babel/preset-env", {
"modules": false
}],
"@babel/preset-typescript"
]
}
显式指定配置,目标位置 dist/esm
,编译 src/
的代码,同时生成 SourceMap
yarn babel --config-file ./.babelrc.esm.json --extensions '.ts' --source-maps -d dist/esm/ src/
# 编译完毕,会在 dist/esm 看到结果
# dist/esm 并不是兼容 Node 的版本,所以只能通过支持 ESM 的工具识别,如: webpack
Rollup+Babel打包UMD
安装Rollup:
rollup
Rollup 核心包@rollup/plugin-node-resolve
能让 Rollup 引用其他模块的插件@rollup/plugin-babel
能让 Rollup 借助 Babel 编译的插件@rollup/plugin-typescript
能让 Rollup 启动时读取 TypeScript 配置文件rollup-plugin-terser
能让 Rollup 对输出结果进行 Terser 压缩的插件rollup-plugin-bundle-size
能让 Rollup 显示 gzip 压缩前后代码大小的插件
yarn add -D rollup @rollup/plugin-node-resolve @rollup/plugin-babel @rollup/plugin-typescript rollup-plugin-terser rollup-plugin-bundle-size
Rollup 可以支持 TypeScript,故直接使用 TypeScript 编写配置,避开不必要的错误 新建rollup.config.ts
import { defineConfig } from 'rollup'
import { nodeResolve } from '@rollup/plugin-node-resolve'
import { babel } from '@rollup/plugin-babel'
import { terser } from 'rollup-plugin-terser'
// @ts-ignore
import bundleSize from 'rollup-plugin-bundle-size'
export default defineConfig({
input: './src/index.ts',
output: [
{
file: './dist/unit_transform.umd.js',
format: 'umd',
name: 'unit_transform', // umd 导出的名称
sourcemap: 'inline', // 把 SourceMap 写在目标代码里面
},
{
file: './dist/unit_transform.umd.min.js',
format: 'umd',
name: 'unit_transform',
plugins: [terser()], //经过 Terser 压缩的 UMD 代码
},
],
plugins: [
bundleSize(), // e.g. 命令行附带 unit_transform.umd.js: 2.91 kB → 923 B (gzip)
nodeResolve({ extensions: ['.ts'] }),
babel({ extensions: ['.ts'] }),
],
})
@rollup/plugin-babel
在 Rollup 运行时会读取 Babel 默认配置文件,如根目录的 babel.config.json
注意 nodeResolve
和 babel
,甚至 Rollup
本身只识别 .js 代码
,对于 TypeScript 项目,要配置 extensions
让它们识别 TS 文件
。
执行打包
yarn rollup -c rollup.config.ts --configPlugin typescript
# 打包完成,在 dist/ 看到结果
# 挑其中一份 UMD 代码,复制到浏览器 Console 执行
# 即可通过 unit_transform、window.unit_transform 调用模块
# 其中变量 unit_transform 即是 UMD 导出的名称
.d.ts
类型声明文件
生成修改tsconfig.json
rootDir
相对于 src/ 生成declaration
启用生成 .d.tsemitDeclarationOnly
仅生成 .d.ts ,不生成JS (JS 部分已经由 Babel 生成了)declarationDir
生成 .d.ts 的目标目录include
仅对 src/ 内的 TS 生成 .d.ts (编译器将专注 src/ 生成,忽略根目录和测试目录的 TS 文件)
{
"compilerOptions": {
...
+ "rootDir": "./src",
+ "declaration": true,
+ "emitDeclarationOnly": true,
+ "declarationDir": "./dist/types",
},
+ "include": ["./src"]
}
执行:
yarn tsc
# 生成完毕,结果存放 dist/types
生成CJS根入口
根目录增加index.js
// 在此之前,CommonJS 需要包名和路径引用:
// const unit_transform = require('unit_transform/dist/cjs')
module.exports = require('./dist/cjs')
module.exports.default = require('./dist/cjs').default
// 此时,CommonJS 可以通过包名直接引用:
// const unit_transform = require('unit_transform')
同时应该把入口写在 package.json 里面:
{
...
+ "main": "dist/cjs/index.js",
...
}
生成ESM根入口
对于 ES Module,webpack 会读取 package.json 中的 module 作为模块入口。
{
...
"main": "dist/cjs/index.js",
+ "module": "dist/esm/index.js",
+ "sideEffects": false,
...
}
生成类型声明入口
{
...
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
"sideEffects": false,
+ "types": "dist/types/index.d.ts",
...
}
为Husky增加配置
yarn husky add .husky/pre-commit "yarn build && git add dist/"