前沿
Rollup 是一个用于 JavaScript 的模块打包工具,它将小的代码片段编译成更大、更复杂的代码,例如库或应用程序。它使用 JavaScript 的 ES6 版本中包含的新标准化代码模块格式,而不是以前的 CommonJS 和 AMD 等特殊解决方案。ES 模块允许你自由无缝地组合你最喜欢的库中最有用的个别函数。这在未来将在所有场景原生支持,但 Rollup 让你今天就可以开始这样做。
目录
前沿
1、安装
2、准备工作
3、快速开始
4、除屑优化(Tree-Shaking)
5、配置文件
6、导入 package.json
7、使用插件
1、安装依赖
2、更新main.js入口文件
3、使用@rollup/plugin-json插件
4、执行编译
8、使用输出插件(压缩)
1、安装依赖
2、使用@rollup/plugin-terser插件
3、执行编译
9、构建
1、安装
使用 npm 全局安装 rollup.js
$ npm install --global rollup
added 3 packages in 12s
安装完毕,node安装目录(D:\AppData\nodejs)会生产出来这三个文件
输入 rollup --help 可以查看当前rollup版本信息和其他选项操作
$ rollup --help
rollup version 4.18.0
=====================================
Usage: rollup [options] <entry file>
Basic options:
-c, --config <filename> 使用此配置文件
(如果使用参数但未指定值,则默认为 rollup.config.js)
-d, --dir <dirname> 用于块的目录(如果不存在,则打印到 stdout)
-e, --external <ids> 排除模块 ID 的逗号分隔列表
-f, --format <format> 输出类型(amd、cjs、es、iife、umd、system)
-g, --globals <pairs> `moduleID:Global` 对的逗号分隔列表
-h, --help 显示此帮助消息
-i, --input <filename> 输入(替代 <entry file>)
-m, --sourcemap 生成源映射(`-m inline` 为内联映射)
-n, --name <name> UMD 导出的名称
-o, --file <output> 单个输出文件(如果不存在,则打印到 stdout)
-p, --plugin <plugin> 使用指定的插件(可重复)
-v, --version 显示版本号
-w, --watch 监视产物文件并在更改时重新构建
--amd.autoId 基于块名称生成 AMD ID
--amd.basePath <prefix> 要预先添加到自动生成的 AMD ID 的路径
--amd.define <name> 在 `define` 位置使用的函数
--amd.forceJsExtensionForImports 在 AMD 导入中使用 `.js` 扩展名
--amd.id <id> AMD 模块的 ID(默认为匿名)
--assetFileNames <pattern> 发布资源的名称模式
--banner <text> 在产物顶部插入的代码(位于包装器之外)
--chunkFileNames <pattern> 发布次要块的名称模式
--compact 缩小包装器代码
--context <variable> 指定顶级 `this` 值
--no-dynamicImportInCjs 将外部动态 CommonJS 导入编写为 require
--entryFileNames <pattern> 发布入口块的名称模式
--environment <values> 传递给配置文件的设置(请参阅示例)
--no-esModule 不添加 __esModule 属性
--exports <mode> 指定导出模式(auto、default、named、none)
--extend 扩展由 --name 定义的全局变量
--no-externalImportAttributes 在 "es" 格式输出中省略导入属性
--no-externalLiveBindings 不生成支持实时绑定的代码
--failAfterWarnings 如果生成的构建产生警告,则退出并显示错误
--filterLogs <filter> 过滤日志信息
--footer <text> 在产物底部插入的代码(位于包装器之外)
--forceExit 当任务完成后,强制结束进程
--no-freeze 不冻结命名空间对象
--generatedCode <preset> 使用哪些代码特性(es5/es2015)
--generatedCode.arrowFunctions 在生成的代码中使用箭头函数
--generatedCode.constBindings 在生成的代码中使用 "const"
--generatedCode.objectShorthand 在生成的代码中使用简写属性
--no-generatedCode.reservedNamesAsProps 始终引用保留名称作为 props
--generatedCode.symbols 在生成的代码中使用符号
--hashCharacters <name> 使用指定的字符集来生成文件的哈希值
--no-hoistTransitiveImports 不将中转导入提升到入口块中
--importAttributesKey <name> 使用特定的关键词作为导入属性
--no-indent 不缩进结果
--inlineDynamicImports 使用动态导入时创建单次打包
--no-interop 不包括交互操作块
--intro <text> 在产物顶部插入的代码(位于包装器内部)
--logLevel <level> 要显示哪种类型的日志
--no-makeAbsoluteExternalsRelative 不规范化外部导入
--maxParallelFileOps <value> 并行读取的文件数
--minifyInternalExports 强制或禁用内部导出的缩小
--noConflict 为 UMD 全局生成 noConflict 方法
--outro <text> 在产物底部插入的代码(位于包装器内部)
--perf 显示性能计时
--no-preserveEntrySignatures 避免入口点的门面块
--preserveModules 保留模块结构
--preserveModulesRoot 将保留的模块放置在根路径下的此路径下
--preserveSymlinks 解析文件时不要跟随符号链接
--no-reexportProtoFromExternal 在使用重新导出星号('*')时,忽略 __proto__
--no-sanitizeFileName 不要替换文件名中的无效字符
--shimMissingExports 为丢失的导出创建卡扣变量
--silent 不打印警告
--sourcemapBaseUrl <url> 使用给定的基本 URL 发出绝对源映射 URL
--sourcemapExcludeSources 在源映射中不包括源代码
--sourcemapFile <file> 指定源映射的包位置
--sourcemapFileNames <pattern> 编译后 sourcemap 的命名模式
--stdin=ext 指定用于标准输入的文件扩展名
--no-stdin 不要从 stdin 读取 "-"
--no-strict 不在生成的模块中发出 `"use strict";`
--strictDeprecations 抛出有关不推荐使用的功能的错误
--no-systemNullSetters 不要将空的 SystemJS setter 替换为 `null`
--no-treeshake 禁用除屑优化
--no-treeshake.annotations 忽略纯调用注释
--treeshake.correctVarValueBeforeDeclaration 在声明之前将变量取消优化
--treeshake.manualPureFunctions <names> 手动将函数声明为纯函数
--no-treeshake.moduleSideEffects 假设模块没有副作用
--no-treeshake.propertyReadSideEffects 忽略属性访问副作用
--no-treeshake.tryCatchDeoptimization 不要关闭 try-catch-tree-shaking
--no-treeshake.unknownGlobalSideEffects 假设未知的全局变量不会抛出异常
--validate 验证输出
--waitForBundleInput 等待打包输入文件
--watch.buildDelay <number> 节流观察重建
--no-watch.clearScreen 重建时不要清除屏幕
--watch.exclude <files> 排除要观察的文件
--watch.include <files> 限制观察到指定文件
--watch.onBundleEnd <cmd> 在 "BUNDLE_END" 事件上运行的 Shell 命令
--watch.onBundleStart <cmd> 在 "BUNDLE_START" 事件上运行的 Shell 命令
--watch.onEnd <cmd> 在 "END" 事件上运行的 Shell 命令
--watch.onError <cmd> 在 "ERROR" 事件上运行的 Shell 命令
--watch.onStart <cmd> 在 "START" 事件上运行的 Shell 命令
--watch.skipWrite 在监视时不要将文件写入磁盘
Examples:
# use settings in config file
rollup -c
# in config file, process.env.INCLUDE_DEPS === 'true'
# and process.env.BUILD === 'production'
rollup -c --environment INCLUDE_DEPS,BUILD:production
# create CommonJS bundle.js from src/main.js
rollup --format=cjs --file=bundle.js -- src/main.js
# create self-executing IIFE using `window.jQuery`
# and `window._` as external globals
rollup -f iife --globals jquery:jQuery,lodash:_ \
-i src/app.js -o build/app.js -m build/app.js.map
Notes:
* When piping to stdout, only inline sourcemaps are permitted
For more information visit https://rollupjs.org
2、准备工作
- 创建一个简单的项目
mkdir -p Rollup
cd Rollup
- 创建入口文件main.js
# main.js
function test() {
const d = new Date();
console.log(d.getFullYear(), d.getMonth())
}
export default test();
3、快速开始
可以通过带有可选配置文件的 命令行界面 或 JavaScript API 来使用 Rollup。
这些命令假定你的应用程序入口点命名为 main.js,并且希望将所有导入编译到一个名为 bundle.js 的单个文件中。
- 对于浏览器
# 编译为包含自执行函数('iife')的 <script>。
rollup main.js --file bundle.js --format iife
执行效果:
- 对于 Node.js
# 编译为一个 CommonJS 模块 ('cjs')
rollup main.js --file bundle.js --format cjs
执行效果:
- 对于浏览器和 Node.js
# UMD 格式需要一个包名
rollup main.js --file bundle.js --format umd --name "myBundle"
执行效果:
4、除屑优化(Tree-Shaking)
除了可以使用 ES 模块之外,Rollup 还可以静态分析你导入的代码,并将排除任何实际上没有使用的内容。这使你可以在现有的工具和模块的基础上构建,而不需要添加额外的依赖项或使项目的大小变得臃肿。
例如,使用 CommonJS 必须导入整个工具或库。
// 使用 CommonJS 导入整个 utils 对象
const utils = require('./utils');
const query = 'Rollup';
// 使用 utils 对象的 ajax 方法。
utils.ajax(`https://api.example.com?search=${query}`).then(handleResponse);
使用 ES 模块,我们不需要导入整个 utils 对象,而只需导入我们需要的一个 ajax 函数:
// 使用 ES6 的 import 语句导入 ajax 函数。
import { ajax } from './utils';
const query = 'Rollup';
// 调用 ajax 函数
ajax(`https://api.example.com?search=${query}`).then(handleResponse);
因为 Rollup 只包含最少的内容,因此它生成的库和应用程序更轻、更快、更简单。由于这种方法可以利用显式的 import 和 export 语句,因此它比仅运行最小化混淆工具更能有效检测出已编译输出代码中的未使用变量。
示例
这里更新了目录结构,执行以下命令将 main.js 编译为一个 es 模块
1、创建src文件夹将main.js移入,创建output文件夹为打包bundle.js做存储。
# 执行命令
rollup ./src/main.js --file ./output/bundle.js --format es
我们新增了一个 notCast 函数,但main.js的test函数并未使用它,output/bundle.js并未为其编译
我们新增了一个 notCast 函数,将其引入到test函数中使用,编译后发现已经编译并使用
5、配置文件
Rollup 配置文件是可选的,但它们非常强大和方便,因此推荐使用。配置文件是一个 ES 模块,它导出一个默认对象,其中包含所需的选项:
# rollup.config.mjs
export default {
input: 'src/main.js',
output: {
file: 'bundle.js',
format: 'es'
}
};
通常,它被称为 rollup.config.js 或 rollup.config.mjs,并位于项目的根目录中。
如果你想使用 require 和 module.exports 编写 CommonJS 模块的配置文件,你应该将文件扩展名更改为 .cjs。
要使用配置文件来运行 Rollup,请传递 --config 或 -c 标志:
# 向 Rollup 传递自定义配置文件位置
rollup --config my.config.js
# 如果你没有传递文件名,Rollup 将会尝试
# 按照以下顺序加载配置文件:
# rollup.config.mjs -> rollup.config.cjs -> rollup.config.js
rollup --config
执行效果
6、导入 package.json
导入你的 package 文件可能很有用,例如自动将你的依赖项标记为 “external”。
在 Rollup 中,可以通过 external 选项来指定哪些模块应该被视为外部依赖。这些模块不会被打包进最终的构建文件中,而是会被认为是已经存在于运行环境中的模块,例如在浏览器端通过 script 标签引入的第三方库或者在 Node.js 中通过 require 引入的内置模块。
external 选项有两个作用:
- 减小打包后文件的体积:如果某个模块被指定为外部依赖,那么它不会被打包进最终的构建文件中,这样可以减小打包后文件的体积,优化加载速度和性能。
- 避免重复打包:如果多个模块都引用了同一个外部依赖,而且每个模块都把这个依赖打包进了自己的构建文件中,那么就会造成代码冗余和重复打包的问题。通过 external 选项,我们可以把这个外部依赖从多个模块中剔除出来,只在最终的构建文件中打包一次,避免了代码冗余和重复打包的问题。
在实际应用中,external 选项特别适用于打包一些常用的第三方库或者框架,例如 React、Vue、Lodash 等,这些库通常已经被广泛使用,并且已经存在于用户的浏览器或者 Node.js 环境中,所以没有必要再把它们打包进构建文件中。
构建package.json
$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.
See `npm help init` for definitive documentation on these fields
and exactly what they do.
Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
package name: (rollup)
version: (1.0.0)
description: rollup test unit
entry point: (index.js) src/main.js
test command:
git repository:
keywords:
author: vinca
license: (ISC)
About to write to D:\vinca\Rollup\package.json:
{
"name": "rollup",
"version": "1.0.0",
"description": "rollup test unit",
"main": "src/main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "vinca",
"license": "ISC"
}
Is this OK? (yes)
安装一下vue3依赖,为后续引入package.json 排除vue模块做铺垫
$ npm install vue
added 20 packages, and audited 21 packages in 15s
3 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
完善你的rollup.config.mjs文件内容
import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);
const pkg = require('./package.json');
console.log(pkg)
const config = {
input: 'src/main.js',
output: {
file: 'output/bundle.js',
format: 'es'
},
external: Object.keys(pkg.dependencies)
}
export default config
输出日志说明:
# pkg
{
name: 'rollup',
version: '1.0.0',
description: 'rollup test unit',
main: 'src/main.js',
scripts: { test: 'echo "Error: no test specified" && exit 1' },
author: 'vinca',
license: 'ISC',
dependencies: { vue: '^3.4.27' }
}
# Object.keys(pkg.dependencies)
[ 'vue' ]
7、使用插件
可以看到第六点是使用createRequire方式使用package.json文件,那么现在我们准备将其优化
1、安装依赖
将 @rollup/plugin-json 安装到开发依赖中:
npm install --save-dev @rollup/plugin-json
我们使用 --save-dev 而不是 --save,因为我们的代码在运行时实际上不依赖于插件,只有在打包时才需要。
2、更新main.js入口文件
# main.js
import { version } from '../package.json';
export default function () {
console.log('version ' + version);
}
3、使用@rollup/plugin-json插件
# rollup.config.mjs
import json from '@rollup/plugin-json';
import pkg from './package.json' assert { type: 'json' };
console.log(pkg)
const config = {
input: 'src/main.js',
output: {
file: 'output/bundle.js',
format: 'es'
},
plugins: [json()],
external: Object.keys(pkg.dependencies)
}
export default config
4、执行编译
rollup -c
如果rollup.config.mjs不添加plugins: [json()]插件会出现编译错误(无法识别json文件)
# bundle.js
var version = "1.0.0";
function main () {
console.log('version ' + version);
}
export { main as default };
【注意】结果中只导入了我们实际需要的数据 ——version ;package.json 中其他内容都被忽略了。这就是 除屑优化 的作用。
8、使用输出插件(压缩)
让我们扩展上一个示例,生产一个压缩文件和一个不压缩文件。
1、安装依赖
npm install --save-dev @rollup/plugin-terser
完成后,你的package.json > devDependencies 模块,将是这样的:
# package.json
"devDependencies": {
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-terser": "^0.4.4"
}
2、使用@rollup/plugin-terser插件
更新你的rollup.config文件,内容如下:
# rollup.config.mjs
import json from '@rollup/plugin-json';
import terser from '@rollup/plugin-terser';
import pkg from './package.json' assert { type: 'json' };
console.log(pkg)
const config = {
input: 'src/main.js',
output: [
{
file: 'output/bundle.js',
format: 'es'
},
{
file: 'output/bundle.min.js',
format: 'iife',
name: 'version',
plugins: [terser()]
}
],
plugins: [json()],
external: Object.keys(pkg.dependencies)
}
export default config
3、执行编译
在终端编译 rollup -c 命令后,将产生一个压缩文件bundle.min.js和一个非压缩文件bundle.js
9、构建
在你的 package.json 中加入构建命令
# package.json
{
"scripts": {
"build": "rollup -c"
}
}
执行操作
或通过命令行模式,执行 npm run build
$ npm run build
> rollup@1.0.0 build
> rollup -c
src/main.js → output/bundle.js...
created output/bundle.js in 52ms
效果和上面执行rollup命令(rollup -c)一样,这样会在output目录产生bundle.js文件