《打包系列|rollup配置篇》

优点

  • 不像webpack 配置比较繁琐
  • ejs模式自动tree shaking
  • 不会像webpack一样打包生成很多多余代码(webpack自定的require,factory函数等)

所以常用来打包公共js库

注意:

rollup tree shaking 无法直接处理 Class 模块(一般用gulp在处理一次)
Rollup tree shaking 只处理函数和顶层 import / export导入的变量

基础配置

npm i rollup -g全局安装
通过rollup.config.js来配置rollup的打包规则, 使用的是esm语法.
关于各个配置项的介绍

  • input:
    入口文件地址

  • output:

    1
    2
    3
    4
    5
    6
    7
    output: {
    file: 'bundles.js' // 输出文件
    format: 'cjs' // 输出格式: cjs, umd, iife, es6, amd
    // format为iife或者umd的时候必须配置, 会作为全局变量
    // name: 'woyaoUtil',
    sourcemap: true // 生成源码映射文件
    }
  • plugins:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    // rollup typescript配置处理
    `@rollup/plugin-typescript`
    /*
    * 帮助寻找node_modules里的包
    * rollup.js编译源码中的模块引用默认只支持ES6+的模块方式import/export。
    * 然而大量的npm模块是基于CommonJS模块方式,这就导致了大量 npm 模块不能直接编译使用。
    * 所以辅助rollup.js编译支持npm模块和CommonJS模块方式的插件就应运而生
    */
    `@rollup/plugin-node-resolve`
    // 支持import 'xx.json'文件
    `@rollup/plugin-json`
    // 在打包的时候把目标字符串替换å
    `@rollup/plugin-replace`
    // 对打包的js进行压缩
    `rollup-plugin-terser`
    // 删除原来的bundle
    `rollup-plugin-delete`
    // 显示打包后文件的大小
    `rollup-plugin-filesize`
    // 将CommonJs语法转成es5
    `rollup-plugin-commonjs`
    // rollup 的 babel 插件,ES6转ES5
    `rollup-plugin-babel`
  • external:

    告诉rollup不要把第三方库进行打包,而是作为外部依赖, 配合”peerDependencies“使用,
    这样业务代码引入我们的公共库的时候避免了重复下载

    1
    2
    3
    4
    // 第三方esm 语法的包
    const external = [/lodash-es\/[a-z]+/, 'ts-date', 'classnames']
    // 第三方cjs 语法的包
    const cjsExteranl = ['classnames']
  • global:

    1
    2
    3
    4
    globals: {
    'react': 'React',
    'react-dom': 'ReactDOM'
    },

package.json中需要注意的点:

1
2
3
4
5
6
7
8
"module" // 打包的esm规范的bundle设置入口
"peerDependencies" // 第三方库应该在这里强调依赖的版本
"scripts": {
"build": "rollup -c",
"build:dev": "npm run clean && env_type=development npm run build",
"build:prod": "npm run clean && env_type=production npm run build",
"clean": "rimraf umd"
}

下面是一个生成umd bundle的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import nodeResolve from '@rollup/plugin-node-resolve'
import replace from '@rollup/plugin-replace'
import { terser } from 'rollup-plugin-terser'
import filesize from 'rollup-plugin-filesize'
import commonjs from '@rollup/plugin-commonjs'
import { babel } from '@rollup/plugin-babel'

const env = process.env.env_type
const isProdEnv = env === 'production'

const config = {
input: 'src/index.js',
external: ['react', 'react-dom'],
output: {
name: 'WoyaoUtil',
file: 'umd/woyao-util.js',
format: 'umd',
sourcemap: true
}
}

const plugins = [
nodeResolve(),
babel({
exclude: '**/node_modules/**',
babelHelpers: 'bundled'
}),
isProdEnv && filesize(),
replace({
'process.env.NODE_ENV': JSON.stringify(env)
}),
commonjs(),
isProdEnv && terser()
].filter(Boolean)

config.plugins = plugins

export default config

babel需要作如下配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"presets": [
[
"@babel/preset-env",
{
// 设置为false, 否则babel会在rollup有机会执行其操作之前导致我们的模块转化为commonjs
"modules": false,
// polyfill按需引入
"useBuiltIns": "usage",
"corejs": 3
}
],
"@babel/preset-react"
]
}

不过我们实际开发并不会打包成umd格式的文件,因为umd格式的包文件很大。

一般会分开打包一个cjs包和一个es包。然后把cjs包写进package.json的main属性,

把es包写进package.json的module属性

typescript 配置

需要安装下面几个包:

  • typescript
  • @rollup/plugin-typescript
  • tslib

rollup.config.js的配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import typescript from '@rollup/plugin-typescript'

const plugins = [
typescript({
declaration: false
}),
nodeResolve(),
commonjs(),
replace({
'process.env.NODE_ENV': JSON.stringify(env)
}),
babel({
exclude: '**/node_modules/**',
babelHelpers: 'bundled'
}),
isProdEnv && filesize(),
isProdEnv && terser()
].filter(Boolean)

typescript的配置文件tsconfig.json一般如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
{
"compilerOptions": {
"allowUnreachableCode": true, // 不报告执行不到的代码错误。
"allowUnusedLabels": false, // 不报告未使用的标签错误
"alwaysStrict": false, // 以严格模式解析并为每个源文件生成 "use strict"语句
"baseUrl": ".", // 工作根目录
"experimentalDecorators": true, // 启用实验性的ES装饰器
"jsx": "react", // 在 .tsx文件里支持JSX
"sourceMap": true, // 是否生成map文件
"module": "ES2015", // 指定生成哪个模块系统代码
"noImplicitAny": false, // 是否默认禁用 any
"removeComments": true, // 是否移除注释
"target": "ESNext", // 编译的目标是什么版本的
"outDir": "./dist", // 输出目录
"declaration": true, // 是否自动创建类型声明文件
"declarationDir": "./ts/lib", // 类型声明文件的输出目录
"allowJs": true, // 允许编译javascript文件。
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"lib": [ // 编译过程中需要引入的库文件的列表
"es5",
"es2015",
"es2016",
"es2017",
"es2018",
"dom"
]
},
// 指定一个匹配列表(属于自动指定该路径下的所有ts相关文件)
"include": [
"src/**/*"
],
// 指定一个排除列表(include的反向操作)
"exclude": [
"node_modules",
"dist"
]
}

编译css

需要安装下面插件

  • rollup-plugin-postcss

Rollup.config.js的配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import postcss from 'rollup-plugin-postcss'

const plugins = [
typescript(),
nodeResolve(),
commonjs(),
replace({
'process.env.NODE_ENV': JSON.stringify(env)
}),
babel({
exclude: '**/node_modules/**',
babelHelpers: 'bundled'
}),
postcss(),
isProdEnv && filesize(),
isProdEnv && terser()
].filter(Boolean)

最后

我写了两个rollup的配置,一个是生成js公共库的,一个是生成js组件库的。
js公共库打包的代码是umd规范的,但是一般来说是要分别生成一个cjs和es规范的
两个文件。

js组件库我是分了两个环境的,开发环境打包成csj,生产环境打包成commonjs.
另外开发环境允许热更行并开启服务,生产环境除了代码打包以后,因为rollup的
treeshaking机制对直接处理 Class 模块,只处理函数和顶部Import/exprot.
所以我还写了一个gulp的打包后的es规范的包进行二次处理。

这是rollup配置js公共库的代码

这是rollup和gulp配置公共组件库的代码

文章作者: woyao
文章链接: https://chenwoyao.github.io/2021/05/24/前端笔记/打包系列/打包系列rollup配置篇/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 woyao的博客