使用rollup和typescript封装一个npm工具库
前一段时间正好学习了 rollup,这次为了学有所用,以使用 rollup 封装一个 npm 前端工具库来巩固所学,该前端工具库是由实验室中常见业务功能函数构成。主要包括时间处理和科学计算。
rollup 配置
rollup 是一个现代 javascript 打包工具,可以将小的代码片段合成一个大的库或者应用(redux),并且可以通过简单的配置打包多端(commonjs esmodule browser)环境。 使用 rollup 打包的库必须使用 es module 不可以使用 commonjs 或者其他模块化方式
对于一个打包工具而言,显然需要入口(input)和出口(output),为了在打包过程中插入一些特定操作,这也就有了插件(plugin)。对于不同的输出格式,常见的如 commonjs 、 es module 、浏览器格式 iife。 这三种输出只需要在 output 配置项配置 format 即可。
- 常用插件的使用场景
- 如果编写的库文件中使用了第三方库(库默认是 commonjs 模块化),想将第三方库打包进源代码里,可以使用 @rollup/plugin-node-resolve 插件。
- 如果编译打包的场景需要对编译的 js 有较高的向下兼容性要求,可以使用@rollup/plugin-babel 配置常见的预设环境 preset-env
- 如果对编译打包的代码要压缩处理,可以使用@rollup/plugin-terser
- 如果库文件由 typescript 编写,可以使用@rollup/plugin-typescript 作为 rollup 和 tsc 的桥梁进行打包处理,默认会读取 tsconfig.json 的配置。
external 配置项:将第三方库打包到源代码里不是一个很好的选择,配置 external 后可以默认在安装该 npm 包时,会自动下载对应的 第三方包。配置就是键值对的形式,以 dayjs 为例,键是包的名字 值是 dayjs 默认导出的结果。
1
2
3
4
5export default defineConfig({
external: {
dayjs: "dayjs",
},
});但是这种配置方式不是很合理,如果引用的第三包较多时,一个个手动配置就很麻烦了,可以直接引入 package.json 里的 dependencies 字段里的值就可以解决了,使用这种方式一定要注意,区分开发依赖和服务依赖的安装
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20import { readFileSync } from "fs";
const pkg = JSON.parse(readFileSync("./package.json"));
const external = [...Object.keys(pkg.dependencies || {})].map((name) =>
RegExp(`^${name}($|/)`)
);
export default defineConfig({
input: "./index.ts",
output: [
{
file: "./dist/bundle.es.mjs",
format: "es",
},
{
file: "./dist/bundle.common.js",
format: "cjs",
},
],
external,
});解决 ts 打包成 js 并且 对 js 做降级兼容处理的方案,bable 和 tsc 都可以处理这个问题,这里选择了 tsc 的方案,选择使用@rollup/plugin-typescript 作 rollup 和 tsc 的桥梁,生成声明文件并且将编译打包的源代码作 es5 兼容处理。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23{
"compilerOptions": {
// 编译后的js代码是es5格式
"target": "ES5",
// 编写的ts源代码可以使用最新的ts特性
"module": "ESNext",
// 以node寻找文件的方式 所以可以省略扩展名.ts
"moduleResolution": "node",
"allowJs": true,
// 生成.d.ts声明文件
"declaration": true,
// 明确声明文件生成的文件夹
"outDir": "./dist",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"lib": ["ES2016", "DOM"],
"resolveJsonModule": true
},
"include": ["lib/**/*", "index.ts"],
"exclude": ["node_modules", "dist"]
}结合 ts 处理 压缩代码处理 完整的配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23import { defineConfig } from "rollup";
import typescript from "@rollup/plugin-typescript";
import terser from "@rollup/plugin-terser";
import { readFileSync } from "fs";
const pkg = JSON.parse(readFileSync("./package.json"));
const external = [...Object.keys(pkg.dependencies || {})].map((name) =>
RegExp(`^${name}($|/)`)
);
export default defineConfig({
input: "./index.ts",
output: [
{
file: "./dist/bundle.es.mjs",
format: "es",
},
{
file: "./dist/bundle.common.js",
format: "cjs",
},
],
external,
plugins: [typescript(), terser()],
});
package.json 的两个配置项
main 属性: main 是 npm 包的入口文件,npm 包主要是存在于 node 环境中,所以 main 配置的文件应是 rollup 以 commonjs 格式打包的 bundle.common.js。
module 属性: module 并不是 npm 官方 规定的格式,但是对于由 rollup 和 webpack 构建的环境下,这些构建工具会扫描 package.json 属性里的 module 属性,如果 module 属性里有值,那么构建环境中使用 es module 的形式引入 npm 包就会引入 module 属性配置的文件。所以 module 配置项存放的应该是 rollup 以 es 格式打包的 bundle.es.mjs。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// d9lab_front_end_utils_pkg这个库文件
// rollup.config.js
export default defineConfig({
input: "./index.ts",
output: [
{
file: "./dist/bundle.es.mjs",
format: "es",
},
{
file: "./dist/bundle.common.js",
format: "cjs",
},
],
});1
2
3
4
5
6
7//d9lab_front_end_utils_pkg这个库文件
// package.json
{
"main": "dist/bundle.common.js",
"module": "dist/bundle.es.js",
"types": "dist/index.d.ts"
}1
2
3// commonjs 环境使用 d9lab_front_end_utils_pkg
// 这里d9lab_front_end_utils指向的是上述配置文件中的bundle.common.js
const { transferTime } = require("d9lab_front_end_utils_pkg");1
2
3// es module使用
//这里d9lab_front_end_utils指向的是上述配置文件中的bundle.es.js
import { transferTime } from "d9lab_front_end_utils_pkg";