背景
项目需要开发一个发版通知插件,同时公司项目属于乾坤架构的微前端应用,涉及多个子应用,如果每个项目都写一遍逻辑,在修改时可能会重复修改多个项目,于是想着能不能通过开发一个插件,对项目侵入最少方式,插件升级后依赖项目npm i
一下就可以了。
调研
待编
行动
基于Rollup开发一个插件,起步还是建议先阅读一遍官网的介绍,以便对它有一个基本的了解。
但是官网的资料很多有坑(因为版本更新然后没有人更新官网资料导致......),所以如果全部按官网的指导走,是走不下去的,一堆问题。
最明显的一个就是 babel,官网说明默认是 babel6,但如果直接从 npm 执行安装,默认安装 babel 则是 7+,配置起来完全不是一个世界的东西......
包括搜到的很多博文也都是过期状态,无法参考,所以决定写个分享来汇总下这次遇到的问题和一些可复用的配置。
注:以下大部分操作都是依赖于命令行操作,Windows 你可以用你熟悉的 cmd
或者 powerShell
或者我熟悉的 cmder
,macOS 可以用终端等等
创建项目
Rollup 只是个工具,不是脚手架,所以没有自己的创建命令,需要走传统的项目生成方法去创建。
js
mkdir rollup-demo && cd rollup-demo
初始化项目
执行 npm init
命令,一路回车,生成package.json 文件。
建议把入口文件设置为src/main.js
,因为实际项目会有很多个分文件,包括你自己编写的lib
文件、config
文件等,统一放在src
下面进行归类管理。
然后打开package.json文件在scripts字段下新增build命令:
js
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "rollup -c rollup.config.js"
},
安装依赖
js
npm install --save-dev rollup @rollup/plugin-node-resolve @rollup/plugin-babel @rollup/plugin-commonjs @rollup/plugin-json @rollup/plugin-alias rollup-plugin-terser rollup-plugin-banner @babel/core @babel/plugin-proposal-class-properties @babel/preset-env
各个包的作用如下
基础包名 | 作用 | 用途补充说明 |
---|---|---|
rollup | Rollup 的核心包 | |
@rollup/plugin-node-resolve | Rollup 插件包,帮助 Rollup 识别 node_modules 的包 | |
@rollup/plugin-babel | Rollup 插件包,自动化解决 babel 的转换问题 | 你可以更爽的写 ES6 以上的新语法... |
@rollup/plugin-commonjs | Rollup 插件包,可将 CommonJS 模块转换为 ES6 | 大部分 npm 包都是 CommonJS,比如常用的 axios/qs 库,如果你项目里用到了他们,不引入这个插件的话会构建失败 |
@rollup/plugin-json | Rollup 插件包,可将.json 文件转换为 ES6 模块 | 比如:作为类库当然要涉及到版本更新,版本号肯定不能各种地方都手写,这种情况下就可以从 package.json 读取 |
@rollup/plugin-alias | Rollup 插件包,配置路径别名 | alias 的作用大家都懂,开发环境必备 |
rollup-plugin-terser | Rollup 插件包,混淆压缩 js 代码 | 打包发布必备 |
rollup-plugin-banner | Rollup 插件包,给打包后的文件添加注释 | 一般可以添加开发者信息、版本号等信息 |
@babel/core | @rollup/plugin-babel 的依赖包,该插件基于 babel7 | |
@babel/plugin-proposal-class-properties | @rollup/plugin-babel 的依赖包,该插件基于 babel7 | |
@babel/preset-env | @rollup/plugin-babel 的依赖包,该插件基于 babel7 |
配置文件
上面提到修改了 package.json
的 script
字段,修改的含义是告知 node 在执行 build 命令的时候,通过 rollup 命令去运行一个叫 rollup.config.js
的配置文件(-c 是--config 的缩写)
js
import resolve from '@rollup/plugin-node-resolve'
import babel from '@rollup/plugin-babel'
import commonjs from '@rollup/plugin-commonjs'
import json from '@rollup/plugin-json'
import alias from '@rollup/plugin-alias'
import { terser } from 'rollup-plugin-terser'
import banner from 'rollup-plugin-banner'
const path = require('path')
const resolveDir = (dir) => path.join(__dirname, dir)
export default {
input: 'src/main.js',
output: [
{
file: `demo/js/demo.js`,
format: 'umd',
name: 'demo',
},
{
file: `dist/${process.env.npm_package_version}/demo.min.js`,
format: 'umd',
name: 'demo',
plugins: [terser()],
},
],
plugins: [
resolve({
browser: true,
}),
babel({
babelHelpers: 'bundled',
}),
commonjs(),
json(),
alias({
entries: [{ find: '@', replacement: resolveDir('src') }],
}),
banner(
`name: <%= pkg.name %>\nversion: v<%= pkg.version %>\nauthor: <%= pkg.author %>`
),
],
}
这份配置的功能是,在执行了 npm run build
之后,会在 dist
文件夹里,生成一个 "版本号" 文件夹,版本号文件夹下是一个被压缩混淆了的版本。
同时在 demo
的 js 文件夹下,会生成一个没有混淆的版本用于 demo 的开发调试。
核心配置选项说明:
字段 | 作用 |
---|---|
input | 入口文件 |
output | 出口文件,一个数组,支持打包多个版本(通常是一个完整版开发,一个混淆压缩上线) |
output.file | 出口的文件名,需要包含到文件夹里就把路径也写上,上面的 ({}).npm_package_version 是以版本号为文件夹归类发布 |
output.format | 输出格式:amd=异步模块、cjs=CommonJS、es=ES 模块文件、iife=自动执行、umd=通用模块(包含 amd/cjs/iife 为一体) |
output.name | 暴露的全局变量,可以通过 window.xxx 来访问你的类库,类似 window.jQuery 的作用 |
output.plugins | 打包插件,目前只配置了一个 terser 用于打包一个压缩版本发布 |
完整配置项请参考Rollup官网。
编译打包
开发阶段你可以根据自己的习惯使用各种 npm 包、自己写的 lib/module
文件等等,但是最终都需要在 main.js
导出一个变量
js
class Demo {
sayHi(name) {
console.log(`Hi, ${name}`)
}
}
const demo = new Demo()
export default demo
这样使用的人就可以在引入你打包好的文件之后,通过这个变量去使用你的类库里的方法,觉得有点绕?看看最后的例子。
Babel配置
因为开发阶段会使用大量的 ES6 等浏览器还不完全兼容的新特性,或者引入一些第三方库,比如 axios 之类的,对于低版本 IE 还不太友好,这些情况下都需要进行 Babel 转换。
命名为 .babelrc
保存到项目根目录下
js
{
"presets": [
[
"@babel/preset-env",
{
"modules": false,
"targets": {
"browsers": "> 1%, IE 11, not op_mini all, not dead"
},
"useBuiltIns": "usage",
"corejs": 2
}
]
],
"plugins": [
"@babel/plugin-proposal-class-properties"
]
}
🌰
我在 main.js
编写一个简单的函数,通过预设好的 demo
变量名打包导出。
dist 文件夹是最终要发版的混淆压缩版,每个版本都有独立的归类;demo 文件夹是用于开发调试的,这里的是未混淆的版本。
微信的 JSSDK 也是类似的用法 wx.config(options);
、wx.chooseImage()
等等