合拾

使用Rollup构建React组件

2019-01-03

Rollup是第一个提出Tree Shaking的打包工具,在打包react组件发布到npm上时,我对其进行了一些研究,本文总结了Rollup构建的基础知识,让你也能轻松使用Rollup来构建出自己的组件。

image

为什么是Rollup

当我开始编写一个组件的时候,除了业务代码,我开始思考应该怎样打包成模块发布到npm,于是,我调研了当下最流行的React组件库-antd,antd为每个组件单独打包,分别打包到lib和es文件夹下,然后在package.json中声明了main和module两个字段,如下:

"main": "lib/index.js",
"module": "es/index.js",

其中,main是指定的入口文件,当我们require(‘antd’)的时候,就会根据main字段去查找入口文件,这是早期的CommonJS规范所定义的。ES6时代,ES Module横空出世,利用ES Module的静态分析的特性,模块打包工具可以更好的优化你的代码。module字段就是指当前模块使用ES Module规范进行构建的,当构建工具遇到module字段时,会优先使用,如果没有找到,则会使用main字段。antd就采用了ES Module进行构建,所以我们在开发时可以方便得使用babel插件来进行按需加载。除此之外,antd自己开发了一个通用的组件开发工具-ant-tool,ant-tool使用gulp来进行打包,执行打包任务时,gulp以任务的形式调用babel打包组件,调用less来打包css。

Rollup 是第一个提出 Tree Shaking 的打包工具。Rollup 会静态分析你所引入的模块,去掉没有真正被用到的部分,只引入你需要的部分,减少项目的体积。相比webpack,使用rollup来构建的组件体积会更小。vue、react等框架也采用了Rollup来进行构建,所以,最后我也采用了Rollup来进行构建react组件。

Rollup基本用法

安装:

npm i rollup --save-dev

Rollup的配置文件为rollup.config.js,通常放在项目根目录下,在package.json中定义使用Rollup配置文件进行打包的命令。

"scripts": {
"compile": "rollup -c"
}

一个基本的rollup配置文件如下:

// rollup.config.js
export default {
input: 'src/main.js',
moduleName: 'ModuleName',
external: ['react', 'react-dom'],
globals: {
react: 'React',
"react-dom": "ReactDOM",
},
output: {
file: 'bundle.js',
format: 'cjs'
},
plugins: []
};

其中,moduleName为打包模块的名称,input为模块入口文件,output为输出的文件,多个输出可以指定数组,output.file指定输出的文件路径,output.format指定打包的模块规范,有如下几种:

  • amd – 异步模块定义,用于像RequireJS这样的模块加载器
  • cjs – CommonJS,适用于 Node 和 Browserify/Webpack
  • es – 打包为ES模块文件
  • iife – 一个自动执行的方法,适合作为script标签。(如果要为应用程序创建一个捆绑包,您可能想要使用它,因为它会使文件大小变小。)
  • umd – 通用模块定义,以amd,cjs 和 iife 为一体

external字段告诉rollup不要将这些包打包进我们的组件,而是作为外部引用。globals字段与external是配套使用的,表示global.React即是外部依赖react。plugins为使用的插件数组,比如使用babel插件转译代码、postcss插件处理css等,通过使用插件可以为Rollup增加更强大的功能。需要注意的是,Rollup的插件添加顺序决定了在构建过程中插件的调用顺序,因此要注意插件在配置文件中的添加顺序。

Rollup常用插件

Rollup本身只提供了一些构建的核心功能,在进行一些复杂的构建时需要使用Rollup中的各种强大的插件,这跟webpack的loader和plugin是非常相似的。下面介绍一些我在打包组件的时候用到的一些插件:

  • rollup-plugin-babel:使用babel编译ES6语法

  • rollup-plugin-node-resolve:查找node_modules中的外部模块

  • rollup-plugin-postcss:编译css、less、sass等样式文件

  • rollup-plugin-commonjs:将 CommonJS 模块转换成 ES6 模块(Rollup只能解析ES6模块)

构建配置

介绍了使用Rollup的基础知识后,下面就开始编写组件构建的配置:

以我编写的一个React组件为例,rollup.config.js如下:


import babel from 'rollup-plugin-babel';
import resolve from 'rollup-plugin-node-resolve';
import postcss from 'rollup-plugin-postcss';
import commonjs from 'rollup-plugin-commonjs';

export default {
moduleName: 'ReactIndexList',
input: 'src/components/indexlist/index.js',
external: ['react', 'react-dom', 'prop-types', 'better-scroll'],
globals: {
react: 'React',
"react-dom": "ReactDOM",
"prop-types": "PropTypes",
"better-scroll": "BScroll"
},
output: [{
name: 'IndexList',
format: 'es',
file: 'es/index.js'
}, {
name: 'IndexList',
format: 'umd',
file: 'lib/index.js'
}],
plugins: [
resolve(),
babel({
exclude: '**/node_modules/**',
runtimeHelpers: true
}),
commonjs(),
postcss({
extract: true,
extensions: ['.less']
})
]
}

在配置开头,引入了之前介绍的常用插件,在导出的配置中,指定了moduleName作为模块名称,input为构建的入口文件,external指定了组件中使用到的库作为外部引用不进行打包,同时指定globals,输出文件output指定数组来配置多个输出,最终输出两份文件,分别输出到es和lib文件夹下,es文件夹使用ES Module规范,lib文件夹使用umd规范。

在plugins中,使用resolve来解析node_modules中的模块,使用babel来转译ES6语法,同时在根目录下配置了.babelrc文件,指定babel解析的预设和插件:

// .babelrc

{
"presets": ["@babel/react", [
"@babel/env", {
"modules": false
}
]],
"plugins": [
["@babel/plugin-proposal-decorators", { "legacy": true }],
"@babel/plugin-syntax-dynamic-import",
["@babel/plugin-proposal-class-properties", { "loose": true }],
"@babel/plugin-transform-runtime"
]
}

在rollup的babel插件配置中,exclude指定node_modules下的文件不进行打包,runtimeHelper是为了开启babel-transform以精简体积。
下面使用了commonjs插件来转换commonjs规范的模块,测试发现不能放在babel之前,否则会报错。
最好使用了postcss插件来转换样式文件,此处我使用了less,postcss的插件会自动识别less文件进行打包,需要额外安装less的npm包。使用extract将less打包成单独的css文件,输出为index.css。

上述就是打包一个react组件的rollup配置,此外,还需要在package.json中配置:

"main": "./lib/index",
"module": "./es/index",

在实际使用中,webpack等构建工具会识别上述字段,优先使用ES Module的构建文件,以提供更好的Tree Shakeing体验。

总结

随着Web应用的愈加复杂,构建工具的使用越来越多,且有越来越多的构建工具涌现出来,不断改善我们的开发体验和提升生产力。Webpack一般用来构建大型应用,Rollup用来构建组件或者库,以零配置打包工具而出名的parcel也有了一席之地,根据不同的需求,可以选择不同的构建工具,以构建出更优秀的Web应用。

使用支付宝打赏
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏

扫描二维码,分享此文章