用 rollup 构建一个 sdk
因项目要求,要产出一个 js_sdk 给别人用,这里选择 rollup 作为构建工具。
目标:集成第三方包,解析 less、css,将图片打包成 base64 ,打包后去掉注释和 console,
生成项目
yarn add rollup global
yarn init -y
然后就可以往里面堆代码了。
最终目录结构如下
├─dist ├─node_modules ├─src │ ├─components │ ├─css │ ├─images │ ├─lib │ ├─index.js ├─rollup.config.js ├─.babelrc ├─.browserslistrc ├─.eslintrc
开发与打包命令如下,开发时开启 watch 模式
"scripts": {
"build": "rollup -c rollup.config.js",
"dev": "rollup -w -c rollup.config.js"
},
rollup.config.js 整体代码结构比较简单
export default{
input:'',
output:'',
plugins:[],
external:[]
}
rullup 插件配置
1、确定 sdk 使用目标,及使用的浏览器版本,
.browserslistrc 内容,可以修改,决定了最终产出的 sdk 代码的行数
> 1%
chrome > 50
not dead
.babelrc
{
"presets": [
[
"@babel/env",
{
"modules": false // 设置为false,否则babel会在rollup有机会执行其操作之前导致我们的模块转化为commonjs
}
]
]
}
2、确定输出目标,最终的使用方式为 script 标签使用
export default{
input: 'src/index.js',
output: {
file: './dist/xxx_sdk.js',
format: 'iife', // iife es umd cjs
name: 'XxxSdk', // iife 模式下必加参数 ,最终导出的对象名
// sourcemap: true,
// sourcemapFile: './dist/bundle.js.map'
},
}
打包后会得到一个 /dist/xxx_sdk.js,会向外暴露一个对象 XxxSdk
使用如下
<script src="./lib/xxx_sdk.js"></script>
const {yyy} = XxxSdk
3、添加 babel 插件
将代码按照 browserslistrc 中的目标进行编译,以兼容这里面的浏览器
安装
yarn add @babel/core @babel/preset-env babel-plugin-transform-remove-console rollup-plugin-babel -D
引入
import babel from 'rollup-plugin-babel'
使用
plugins:[
// ... 其他 plugin
babel({
exclude: "node_modules/**",
extensions: [".js", ".jsx", ".ts", ".tsx"],
plugins: [
transformRemoveConsole // 代码打包时移除 console
]
}),
]
4、添加 commonjs 插件
有时候需要使用的第三方包是用 commonjs 方式写的,这时要将其转换为 esm 方式的代码,就要使用 commonjs 插件,注意此插件要在 babel 之前调用书写
安装
yarn add rollup-plugin-commonjs -D
引入
import commonjs from 'rollup-plugin-commonjs'
使用
plugins:[
// ...
commonjs(), // 将 commonjs 解析成 es2015, 与 babel 同在时必须在 babel 之前调用;
]
5、windicss 支持
因为要编写 css ,这里选择使用神器 windicss,可以减少 80% 的 css 编写,也减少 css 命名的麻烦,配置简单粗暴,没有花样。
安装
yarn add rollup-plugin-windicss -D
使用
import WindiCSS from 'rollup-plugin-windicss'
plugins:[
//...
WindiCSS(),
]
6、增加 less、css 支持
windicss 不能满足所有样式编写,还是要手动写一部分 css 代码,不安装 less 不知道可行不,没试
yarn add rollup-plugin-postcss less cssnano -D
使用
import postcss from 'rollup-plugin-postcss'
import cssnano from "cssnano";
import autoprefixer from "autoprefixer";
plugings:[
postcss({
plugins: [
autoprefixer(), // 自动添加 css 兼容性前缀
cssnano() ,// 压缩 css 成一行
],
extensions: [".less", ".css", ".scss"], // 解析 less。css, scss
// extract: 'css/index.css' // 将 css 抽离成单独的文件,一般不需要开启,因为最后只要暴露一个js 出来,不想拆分
}),
]
7、将图片打包成 base64
因为最后只能暴露出一个 js 文件,此时需要将图片打包成内联的 base64,找了好几个插件都不够满意,最后这个感觉挺好用
安装
yarn add @rollup/plugin-url -D
使用
// 引入
import url from '@rollup/plugin-url'
// 配置
plugins:[
// ...
url({
limit: 300*1024, // 300k 以内的图片都转成内联的 base64
exclude: 'node_modules/**'
}),
]
8、集成第三方包
需要使用第三方包,如果不解析,就只会在代码中有一行
import 'xxxx'
而 xxxx 的内容代码并没有打包集成到输出文件中,这里选用 官方的 插件 @rollup/plugin-node-resolve ;
安装
yarn add @rollup/plugin-node-resolve -D
使用如下,配合 extenal 属性,可以将一些包不集成到输出文件中,比如不将 lodash 集成到 输出文件中,最后需要用户自行安装 lodash ;
import resolve from '@rollup/plugin-node-resolve';
plugins: [
// ...
resolve(), // 使用时要比 commonjs 和 babel 早调用
commonjs(),
babel()
],
external: ['lodash']
这里我遇到一个坑,第三方包嵌套较深,有四层,最后只要开启了 resolve() 打包就会卡死,只有前面成功过一次,后面一直卡死,无奈将第三方包拆了,将其代码复制到 lib 目录中,最后也能成功;
9、代码压缩
打包后的js 代码需要压缩减小体积,压缩后的代码会自动去掉 debugger 断点
安装
yarn add rollup-plugin-terser -D
使用
import { terser } from 'rollup-plugin-terser'
plugins:[
// ...
terser({
ecma: 6,
output: {
comments: false // 移除注释
}
}),
]
还可以添加 eslint 插件,rollup-plugin-eslint ,配合 .eslintrc.js 使用
rollup.config.js 完整代码
import babel from 'rollup-plugin-babel'
import postcss from 'rollup-plugin-postcss'
import resolve from '@rollup/plugin-node-resolve';
import { terser } from 'rollup-plugin-terser'
import commonjs from 'rollup-plugin-commonjs'
import WindiCSS from 'rollup-plugin-windicss'
import clear from "rollup-plugin-clear";
import url from '@rollup/plugin-url'
import transformRemoveConsole from "babel-plugin-transform-remove-console";
import autoprefixer from "autoprefixer";
import cssnano from "cssnano";
import { eslint } from "rollup-plugin-eslint";
export default {
input: 'src/index.js',
output: {
file: './dist/xxx.js',
format: 'iife', // iife es
name: 'xxxSdk', // iife 必加参数
// sourcemap: true,
// sourcemapFile: './dist/bundle.js.map'
},
plugins: [
// 每次编译之前清空历史编译目录
// clear({
// targets: ["dist"], // 项目打包编译生成的目录
// watch: true, // 实时监听文件变化
// }),
resolve(), // 识别集成第三方包
commonjs(), // 将 commonjs 解析成 es2015, 与 babel 同在时必须在 babel 之前调用;
babel({
exclude: "node_modules/**",
extensions: [".js", ".jsx", ".ts", ".tsx"],
plugins: [
transformRemoveConsole // 移除 console
]
}),
url({
limit: 300*1024, // 300k 以内的图片都转成内联的 base64
exclude: 'node_modules/**'
}),
WindiCSS(),
postcss({
plugins: [
// autoprefixer(), // 自动添加 css 兼容性前缀
cssnano() ,// 压缩 css
],
extensions: [".less", ".css"],
// use: ["less"],
// extract: 'css/index.css' // 将 css 抽离成单独的文件,一般不需要开启
}), // 解析 less。css, scss
// 将代码压缩,去掉注释
terser({
ecma: 6,
output: {
comments: false
}
}),
// 会自动加载文件根目录的 `.eslintrc.js` 配置文件
eslint({
fix: true,
throwOnError: true, // 有错误时会抛出
throwOnWarning: true, // 有警报时会抛出
include: ['src'],
exclude: [], // 默认值 node_modules/**
formatter: () => { }
// https://www.npmjs.com/package/rollup-plugin-eslint
})
],
}