前言
最近接到需求,需要将某个开源项目二次开发,提供给几个项目用。经过比对后决定使用Rollup
来打包。
这篇文章记录下过程中踩的一些坑和一些优化项。
安装和配置
安装rollup
yarn global add rollup
// 或
npm i -g rollup
创建 rollup.config.js
// rollup.config.js
const config = {
input: './src/index.js', // 入口文件
external: ['lodash', 'jquery'], // 排除的依赖包
output: {
name: 'index',
file: 'dist/index.js', // 打包后的index文件
format: 'umd', // umd格式 可换成 iife
globals: {
vue: 'Vue',
jquery: '$'
},
inlineDynamicImports: true
}
}
export default config
说明:
external
可以排除不需要打包的依赖,比如peerDependencies
中的依赖,然后需要去globals
中声明他们的全局变量,比如项目中用jquery
会使用$
变量。umd
是一种通用格式,iife
是给浏览器运行的。
Rollup 插件
需要装哪些插件
提起插件真的令人头疼,生态里各种插件五花八门,用的时候要时刻警惕一些坑和版本问题。
rollup 打包完整的 vue 项目需要用到大量的插件,咱们先分个类
基本的工程化插件
rollup-plugin-node-resolve
帮助 rollup 识别外部模块rollup-plugin-vue
vue2.x使用5.x版本 vue3使用6.x版本rollup-plugin-babel
babel插件 将es6+转为es5rollup-plugin-copy
直接复制静态文件rollup-plugin-terser
压缩代码@rollup/plugin-commonjs
将commonjs模块转为es模块@rollup/plugin-alias
路径别名
// rollup.config.js
import resolve from 'rollup-plugin-node-resolve'
import vue from 'rollup-plugin-vue'
import babel from 'rollup-plugin-babel'
import commonjs from '@rollup/plugin-commonjs'
import alias from '@rollup/plugin-alias'
import { terser } from 'rollup-plugin-terser'
import path from 'path'
const config = {
... 其他配置
plugins: [
resolve({
extensions: ['.vue'], // 无后缀名引用时,需要识别 .vue 文件
exclude: '**/node_modules/**' // 排除node_modules
}),
alias({
entries: [
{
find: 'demo-lib', // 别名名称,作为依赖项目需要使用项目名
replacement: path.resolve(__dirname, 'src'),
customResolver: resolve({
extensions: ['.js', '.jsx', '.vue', '.sass', '.scss']
})
}
]
}),
// 将不需要编译的静态文件直接复制到dist
copy({
targets: [
{ src: 'public/tinymce/*', dest: 'dist/tinymce' }
]
}),
vue({
css: true,
compileTemplate: true
}),
babel({ // 排除node_modules
exclude: 'node_modules/**'
}),
commonjs(),
terser()
]
}
export default config
打包css、图片、字体的插件
@rollup/plugin-image
识别图片文件rollup-plugin-svg
识别svg文件rollup-plugin-require-context
支持 require.context 语法rollup-plugin-url
这里用来识别字体rollup-plugin-postcss
识别css和预处理文件
Tip: 如果使用了scss
,rollup-plugin-postcss
需要配合node-sass
使用
// rollup.config.js
import image from '@rollup/plugin-image'
import postcss from 'rollup-plugin-postcss'
import svg from 'rollup-plugin-svg'
import url from 'rollup-plugin-url'
import sass from 'node-sass'
const isProd = process.env.BUILD === 'production' // 稍后在命令行说明
const config = {
... 其他配置
plugins: [
... 其他配置
postcss({
extract: true,
minimize: isProd, // 生产环境开启压缩
extensions: ['.css', '.scss'], // 识别css和scss文件
// 在打包过程中需要配合 node-sass 使用
process: function(context, payload) {
return new Promise((resolve, reject) => {
sass.render({
file: context
}, function(err, result) {
if (!err) {
resolve(result)
} else {
reject(err)
}
})
})
}
}),
url({
include: ['**/*.woff', '**/*.ttf'], // 打包字体为base64
limit: Infinity
}),
image(),
svg(),
requireContext()
]
}
export default config
到这里,完整的 vue 工程的rollup打包配置已经有了,但是对开发环境很不友好,打包一次要一分多钟,加上主项目热更新要再等一分多钟,太浪费时间了。
优化项,打包加速🚀
一番网上冲浪过后,找到了一些热更新和优化打包的方案。
- 开启热更新,使用
rollup-plugin-livereload
插件 - watch模式打包时排除第三方依赖,使用
rollup-plugin-peer-deps-external
- 关闭sourceMap
- 配置babel为runtime模式,不打包babel的helpers,前提安装
@babel/runtime
import livereload from 'rollup-plugin-livereload'
import peerDepsExternal from 'rollup-plugin-peer-deps-external'
import commonjs from '@rollup/plugin-commonjs'
const isProd = process.env.BUILD === 'production' // 稍后在命令行说明
const config = {
... 其他配置
external: ['lodash', 'jquery', /@babel\/runtime/],
plugins: [
... 其他配置
livereload(),
commonjs({
sourceMap: false
}),
// 该插件默认排除peerDependencies中的依赖
peerDepsExternal({
includeDependencies: !isProd // 开启该选项,排除dependencies
})
]
}
export default config
完整配置
// rollup.config.js
import resolve from 'rollup-plugin-node-resolve'
import vue from 'rollup-plugin-vue'
import babel from 'rollup-plugin-babel'
import commonjs from '@rollup/plugin-commonjs'
import image from '@rollup/plugin-image'
import alias from '@rollup/plugin-alias'
import requireContext from 'rollup-plugin-require-context'
import postcss from 'rollup-plugin-postcss'
import svg from 'rollup-plugin-svg'
import url from 'rollup-plugin-url'
import path from 'path'
import sass from 'node-sass'
import { terser } from 'rollup-plugin-terser'
import livereload from 'rollup-plugin-livereload'
import copy from 'rollup-plugin-copy'
import peerDepsExternal from 'rollup-plugin-peer-deps-external'
const isProd = process.env.BUILD === 'production'
const config = {
input: './src/index.js',
external: ['lodash', 'jquery', /@babel\/runtime/],
output: {
name: 'index',
file: 'dist/index.js',
format: 'umd',
globals: {
vue: 'Vue',
jquery: '$'
},
inlineDynamicImports: true
},
plugins: [
resolve({
extensions: ['.vue'],
exclude: '**/node_modules/**'
}),
alias({
entries: [
{
find: 'demo-lib',
replacement: path.resolve(__dirname, 'src'),
customResolver: resolve({
extensions: ['.js', '.jsx', '.vue', '.sass', '.scss']
})
}
]
}),
copy({
targets: [
{ src: 'public/tinymce/*', dest: 'dist/tinymce' }
]
}),
vue({
css: true,
compileTemplate: true
}),
babel({
exclude: 'node_modules/**'
}),
postcss({
extract: true,
minimize: isProd,
extensions: ['.css', '.scss'],
process: function(context, payload) {
return new Promise((resolve, reject) => {
sass.render({
file: context
}, function(err, result) {
if (!err) {
resolve(result)
} else {
reject(err)
}
})
})
}
}),
url({
include: ['**/*.woff', '**/*.ttf'],
limit: Infinity
}),
commonjs({
sourceMap: false
}),
image(),
svg(),
requireContext(),
terser(),
peerDepsExternal({
includeDependencies: !isProductionEnv
})
]
}
if (!isProd) {
config.plugins.push(livereload())
}
export default config
命令行
node --max-old-space-size=4096
给node开启大内存 避免打包时内存不够node_modules/rollup/dist/bin/rollup -c
直接用本地安装的rollup,避免部署时某个服务器没有全局安装rollupdev
模式开启-w
监听文件动态打包BUILD:development
配置环境变量 代码里从process.env.BUILD
取到
{
"main": "dist/index.js",
"scripts": {
"dev": "node --max-old-space-size=4096 node_modules/rollup/dist/bin/rollup -c -w --environment BUILD:development",
"build": "node --max-old-space-size=4096 node_modules/rollup/dist/bin/rollup -c --environment BUILD:production"
}
}