Rollup
概述
Rollup 是一个 JavaScript 模块打包器,可以将小块代码编译成大块复杂的代码,例如 library 或应用程序。Rollup 对代码模块使用新的标准化格式,这些标准都包含在 JavaScript 的 ES6版本中,而不是以前的特殊解决方案,如 CommonJS 和 AMD。ES6 模块可以使你自由、无缝地使用你最喜爱的 library 中那些最有用独立函数,而你的项目不必携带其他未使用的代码
Webpack和Rollup对比
Webpack
大型SPA项目的模块化构建(web应用)
- 通过各种
Loader处理各种各样的静态资源 - 通过各种插件
Plugins对整体文件进行一些处理 Code splitting将公共模块进行提取- 提供一个
webpack-dev-server,进行本地开发 - 支持
HMR模块热替换
优势
- 强大的生态插件
- 面向开发应用的特性支持
HMR,按需加载,公共模块提取 - 简化
Web开发的环节,图片自动转base64,资源的缓存
Rollup
Rollup设计之初就是面向ES Module的,构建出结构扁平,性能出众的类库
ES module的规则
import只能作为模块顶层的语句出现,不能出现在function里面或是if里面ES import的模块名只能是字符串常量- 不管
import的语句出现的问题在哪里,在模块初始化的时候所有的import都必须已经导入完成 Tree shaking机制
优势
- 构建高性能的模块文件
- 编译出来的代码可读性好,内容更小,执行效率更高
- 配置简单
Rollup是用来构建库还是应用程序?
Rollup 已被许多主流的 JavaScript 库使用,也可用于构建绝大多数应用程序。但是 Rollup 还不支持一些特定的高级功能,尤其是用在构建一些应用程序的时候,特别是代码拆分和运行时态的动态导入 dynamic imports at runtime. 如果你的项目中更需要这些功能,那使用 Webpack可能更符合你的需求
Tree-shaking
除了使用
ES6模块之外,Rollup还静态分析代码中的import,并将排除任何未实际使用的代码。这允许您架构于现有工具和模块之上,而不会增加额外的依赖或使项目的大小膨胀
例如,在使用 CommonJS时,必须导入(import)完整的工具(tool)或库(library)对象
// 使用 CommonJS 导入(import)完整的 utils 对象
var utils = require( 'utils' );
var query = 'Rollup';
// 使用 utils 对象的 ajax 方法
utils.ajax( 'https://api.example.com?search=' + query ).then( handleResponse );
但是在使用 ES6 模块时,无需导入整个 utils 对象,我们可以只导入(import)我们所需的 ajax 函数
// 使用 ES6 import 语句导入(import) ajax 函数
import { ajax } from 'utils';
var query = 'Rollup';
// 调用 ajax 函数
ajax( 'https://api.example.com?search=' + query ).then( handleResponse );
常用配置
在项目中创建一个名为 rollup.config.js 的文件
export default {
input: 'src/main.js',
output: {
file: 'bundle.js',
format: 'cjs'
}
};
Input
入口文件地址
output
如果要输出多个,可以是一个数组
output: {
file: 'bundle.js', // 输出文件
format: 'cjs, // 五种输出格式:amd / es6 / iife / umd / cjs
name: 'name', //当format为iife和umd时必须提供,将作为全局变量挂在window(浏览器环境)下:window.A=...
sourcemap: true, //生成bundle.map.js文件,方便调试
globals: {
'lodash': '_' // 告诉rollup,全局变量_就是lodash
}
}
format
生成包的格式
amd– 异步模块定义,用于像RequireJS这样的模块加载器cjs–CommonJS,适用于Node和Browserify/Webpackesm– 将软件包保存为ES模块文件,在现代浏览器中可以通过<script type=module>标签引入iife– 一个自动执行的功能,适合作为<script>标签。(如果要为应用程序创建一个捆绑包,您可能想要使用它,因为它会使文件大小变小。)umd– 通用模块定义,以amd,cjs和iife为一体
globals
Object 形式的 id: name 键值对,用于umd/iife包。例如:
import $ from 'jquery';
我们想告诉 Rollup jquery 模块的id等同于 $ 变量
// rollup.config.js
export default {
...,
format: 'iife',
name: 'MyBundle',
globals: {
jquery: '$'
}
};
/*
var MyBundle = (function ($) {
// 代码到这里
}(window.jQuery));
*/.
external
两者任一
Function需要一个id并返回true(外部引用)或false(不是外部的引用), 或者 Array 应该保留在bundle的外部引用的模块ID。
ID应该是:
- 外部依赖的名称
- 一个已被找到路径的
ID(像文件的绝对路径)
// rollup.config.js
import path from 'path';
export default {
...,
external: [
'lodash', // 告诉rollup不要将lodash打包,而作为外部依赖
'some-externally-required-library',
path.resolve( './src/some-local-file-that-should-not-be-bundled.js' )
]
};
插件
Babel
如果我们希望将ES6转成ES5的代码,可以在rollup中使用babel
npm install @rollup/plugin-babel @babel/core -D
import babel from '@rollup/plugin-babel';
import { DEFAULT_EXTENSIONS } from '@babel/core';
const plugins = [
babel({
exclude: 'node_modules/**', // 防止打包node_modules下的文件
extensions: [...DEFAULT_EXTENSIONS, '.ts', '.tsx'],
})
]
配置babel.config.js文件
module.exports = {
presets: [
"@babel/preset-env"
]
}
@rollup/plugin-node-resolve和@rollup/plugin-commonjs
rollup.js编译源码中的模块引用默认只支持ES6+的模块方式import/export。然而大量的npm模块是基于CommonJS模块方式,这就导致了大量npm模块不能直接编译使用。所以辅助rollup.js编译支持npm模块和CommonJS模块方式的插件就应运而生。
rollup-plugin-node-resolve插件允许我们加载第三方模块@rollup/plugin-commonjs插件将它们转换为ES6版本
npm install @rollup/plugin-node-resolve @rollup/plugin-commonjs -D
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
const plugins = [
commonjs(),
resolve(),
...
]
Postcss
开发项目我们用
webpack,开发js类库,rollup比webpack强。开发js类库一般是不写css,如果你要写大量的css,那可能你开发的是项目,优先选择webpack,webpack里也有开发library的配置。
如果你的
js类库里还是必不可少要写些css的话,rollup也是有插件编译css的
npm install rollup-plugin-postcss postcss -D
import postcss from 'rollup-plugin-postcss';
const plugins = [
postcss(),
...
]
Vue
npm install rollup-plugin-vue@next vue-template-compiler -D
import vue from 'rollup-plugin-vue';
const plugins = [
vue(),
...
]
此时打包后的文件运行可能会报错:
npm install rollup-plugin-replace -D
import replace from 'rollup-plugin-replace';
import vue from 'rollup-plugin-vue';
const plugins = [
replace({
'process.env.NODE_ENV': JSON.stringify('production')
})
vue(),
...
]
Terser
npm install rollup-plugin-terser -D
import { terser } from 'rollup-plugin-terser';
const plugins = [
terser(),
...
]
rollup-plugin-esbuild
esbuild是目前最快的Ts/ES6编译器之一,该插件取代了rollup-plugin-typescript2、@rollup/plugin-typescript、rollup-plugin-terser
yarn add esbuild rollup-plugin-esbuild -D
import esbuild from 'rollup-plugin-esbuild'
const plugins = [
esbuild({
minify: true,
target: 'es2018',
tsconfig: 'tsconfig.json',
})
]
// 配置tsconfig.json
{
"compilerOptions": {
"target": "esnext",
"useDefineForClassFields": true,
"module": "esnext",
"moduleResolution": "node",
"strict": true,
"jsx": "preserve",
"sourceMap": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
],
"allowJs": true,
"checkJs": true,
"importHelpers": true,
"skipLibCheck": true,
"allowSyntheticDefaultImports": true,
"noEmit": true,
"isolatedModules": true,
"declaration": true,
"declarationDir": "lib",
"types": [
"node"
],
},
"include": [
"packages/**/*.ts",
"packages/**/*.d.ts",
"packages/**/*.tsx",
"packages/**/*.vue",
"types/**/*.d.ts",
"types/**/*.ts"
],
"exclude": ["node_modules", "**/lib", "**/__tests__/**/*"]
}
别名使用
npm install @rollup/plugin-alias -D
import alias from '@rollup/plugin-alias'
const path = require('path')
const resolveDir = dir => path.join(__dirname, dir)
const plugins = [
alias({
entries: [
{ find: '@', replacement: resolveDir('src') }
]
}),
...
]
本地服务器
npm install rollup-plugin-serve -D
import serve from 'rollup-plugin-serve';
import replace from 'rollup-plugin-replace';
import vue from 'rollup-plugin-vue';
import typescript from '@rollup/plugin-typescript';
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import babel from '@rollup/plugin-babel';
import postcss from 'rollup-plugin-postcss';
// import { terser } from 'rollup-plugin-terser';
const output = {
file: '.temp/bundle.cjs.js',
format: 'cjs',
name: 'bundleName',
sourcemap: true // 配置sourcemap为true,方便调试代码
}
const devPlugins = [
resolve(),
replace({
'process.env.NODE_ENV': JSON.stringify('production')
})
vue(),
typescript(),
babel({
exclude: 'node_modules/**',
}),
commonjs(),
postcss(),
// terser(),
serve({
open: true, // 是否打开浏览器
port: 8080, // 监听哪一个端口
contentBase: "." // 服务哪一个文件夹
})
]
热更新
本地服务器有了,但是每次修改代码,还要重新启动才能生效,很不方便,所以需要热更新。
npm install rollup-plugin-livereload -D
import serve from 'rollup-plugin-serve';
import livereload from 'rollup-plugin-livereload';
import replace from 'rollup-plugin-replace';
import vue from 'rollup-plugin-vue';
import typescript from '@rollup/plugin-typescript';
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import babel from '@rollup/plugin-babel';
import postcss from 'rollup-plugin-postcss';
// import { terser } from 'rollup-plugin-terser';
const devPlugins = [
resolve(),
replace({
'process.env.NODE_ENV': JSON.stringify('production')
})
vue(),
typescript(),
babel({
exclude: 'node_modules/**',
}),
commonjs(),
postcss(),
// terser(),
serve({
open: true, // 是否打开浏览器
port: 8080, // 监听哪一个端口
contentBase: "." // 服务哪一个文件夹
}),
livereload()
]
其他插件
- @rollup/plugin-json:可以将
.json文件转化为ES6模块 - rollup-plugin-visualizer:可视化分析
Rollup捆绑包 - rollup-plugin-copy:复制文件和文件夹,并具有
glob支持