本小节介绍下 rollup
和 esbuild
的基础用法,我们都知道 vite
本身使用的 rollup
打包,vite
的插件也和 rollup
的插件机制相吻合; esbuild
是用于在开发环境中对文件进行处理,也有自己的声明周期钩子函数,由于对文件的分割和 css
支持还不太友好,暂未应用到打包环节。
rollup
rollup
是成熟的构建工具, 开源类库优先选择,以 esm
标准为目标的构建工具,package.json
中提供了 module
字段,引用时以这个字段为主,不是 main
,默认不支持 commonjs
,需要使用插件 resolvenode
实现转换,webpack
适合企业级项目,写好的 loader
, plugins
,打包优化
- tree shaking
rollup
令人津津乐道的就是 treeshaking
功能,把没有使用的代码剔除,减小打包体积
如下一段代码
function test() {
var name = 'test';
console.log(123);
}
const name = '测试测试';
function fn() {
console.log(name);
}
fn();
打包后没有 test
函数的代码
'use strict';
const name = '测试测试';
function fn() {
console.log(name);
}
fn();
实现原理还是依赖于 ast
解析,也是为什么需要使用 esm
标准,解析的时候,会把代码统一到一个文件的最上层,import
和 export
的字段都会打上标记,在哪里定义,在哪里使用的。自然未使用的也不会引入。
常用命令
- npm i -g rollup 全局安装
- rollup -i index.js 打包 index.js 文件,在控制台查看内容
- rollup -i index.js --file dist.js 打包文件输出到 dist.js 中
- rollup -i index.js --file dist.js --format umd 以 umd 模式打包,
还有 iife cjs umd 模式
- rollup -i index.js a.js --dir dist 打包到dist 目录下,会自动生成index.js
- rollup -i index.js --file dist.js --format umd --name Index (--watch) 可以全局 global 命名
- rollup -h (--help) 查看命令
rollup.config.js
执行命令 rollup -c rollup.config.js --environment TEST:123
// 命令行定义环境变量,在脚本中可以直接获取
console.log(process.env.TEST)
export default {
input: 'index.js',
output: {
file: 'dist.js',
// 打包模式可以条件判断
format: isLocal ? 'es' : 'umd',
name: 'Index'
}
}
如果我们全局安装了 rollup
,命令行执行操作会使用全局 rollup
,如果想使用项目内的,执行 node\_modules
下的:
./node_modules/.bin/rollup -c rollup.config.js --plugin json
配置文件
rollup
不光可以打包一个文件,也可以打包多种,我们看下 vue3
打包出的种类如下,配置文件中导出数组形式即可
默认 根目录
// 模块引入可以不加后缀名或者引入目录下的 index.js 可以简写
improt resolve from '@rollup/plugin-node-resolve'
// commonjs 转为 esm
import commonjs from '@rollup/commonjs'
// 压缩
import {terser} from 'rollup-plugin-terser'
export default [
{
input:'index.js',
// 不想打包进的,我们使用 cdn 引入
external: ['react', {
// 对象需要全局名字
‘react’: 'React'
}],
output: {
file: 'dist/index.umd.js',
format: 'umd',
// 也有 plugin,编译完才用,压缩
plugins: [
terser()
],
// 和 terser 冲突,因为这是属于注释的内容
banner: '/\*\* hellp this is banner'
},
// 默认放第一个,先执行
plugins: [
resolve(), commonjs(), json()
]
},
{
input:'index.js',
output: {
file: 'dist/index.es.js',
format: 'es'
}
}
]
命令行命令默认全局,
package.json
中默认本地node\_modules
下的
rollup 插件
执行机制
input -> rollup main code -> plugin1 -> plugin2 ... -> emit file 输出到文件-> finish
我们编写插件就是对象要操作的类型的文件,根据不同 hook
在不同节点执行不同方法,完成我们想要的目的
配置对什么文件执行插件操作,什么文件不执行操作关键字:include
、exclude
- @rollup/plugin-alias 设置别名
import a from '../a' // ..写法繁琐想简写如下
import a from 'a'
// 插件配置
plugins: [
alias({
entries: {
a: "../a",// 页面的 ../a 用 a 替换
},
}),
],
// 最后是导出一个插件函数
...
export default function alias(options: RollupAliasOptions = {})
...
// 函数返回
return {
name: 'alias',// 插件名,报错查看
// inputOptions 对应 rollup.config.js 写的配置 导出的值
// 构建之前处理
async buildStart(inputOptions) {
await Promise.all(
[...(Array.isArray(options.entries) ? options.entries : []), options].map(
({ customResolver }) =>
customResolver &&
typeof customResolver === 'object' &&
typeof
// 路径映射 a ../a
resolveId(importee, importer) {
// 返回真正的 路径
}
其他相对重要的钩子函数如:
- transform
- 类型: Function
- 形式: ( source, id ) => (code|{ code, map, dependencies }|Promise)
可以被用来改变每个模块代码。在 --watch
模式中, 会监听 dependencies
数组中所有文件或者目录的变化。
例如我们使用 replace 插件,对文件内容进行替换
具体大家可以去官网学习
esbuild
因为 vite
内部文件编译使用了 esbuild
,他是 go
语言写的,完全命令行使用,能够解析 js
,但是不能运行 js
。代码中也是间接通过 node
执行命令行工具操作。我们需要了解 esbuild
的插件执行机制,我们在编写 vite
插件的时候,如果写自己插件有需要的话,也要同时兼容 rollup
和 esbuild
使用
npx esbuild index.js
npx esbuild index.js --ourfile=dist.js 输出
想打包的话(所有代码打包到一起)加上 --bundle,内部有 treeshaking
--target=esnext 指定编译目标,注意 esbuild 对 es5 编译不完整,const 依旧会 va
--platform=node, browser node 环境或者浏览器环境
--format=esm cjs
--watch
--define:TEST=12 环境变量
如果项目中使用了图片,需要使用 loade
import a from './logo.png'
--loader:.png=dataurl // 转成了 base64
esbuild 插件
在 esbuild
中,插件被设计为一个函数,该函数需要返回一个对象(Object),对象中包含 name
和 setup
等 2 个属性
build
对象上会暴露整个构建过程中非常重要的 2 个函数:onResolve
和 onLoad
,它们都需要传入 Options
(选项)和 CallBack
(回调)等 2 个参数。
// build.js
let exampleOnLoadPlugin = {
name: "example", // 名字为了报错警告提示
setup(build) {
let fs = require("fs");
// 输入的 options
console.log(build.initialOptions);
// 我们可以在操作中修改配置 build.initialOptions.outdir = 'lib'
/\*\*
build.onStart({}, () => {
// 不能再 onstart 中修改配置
})
\*/
// 处理哪类文件
build.onResolve(
{
filter: /\.txt$/,
},
async (args) => ({
path: args.path,
namespace: "txt", // 区分文件加载,标识
})
);
build.onLoad(
{
// 在 go 里执行 正则
filter: /\.\*$/, //什么类型文件执行
namespace: "txt",
},
async (args) => {
// 模块的文件路径
let text = await fs.promises.readFile(args.path, "utf-8");
return {
// 文件内容预处理
contents: `export default ${JSON.stringify([
...text.split(/\s+/),
"----------",
])}`,
// loader: "json",
};
}
);
},
};
require("esbuild")
.build({ // 命令行参数
entryPoints: ["index.js"],
bundle: true,
outdir: "dist",
loader: {
".png": "dataurl",
},
plugins: [exampleOnLoadPlugin],
})
.catch(() => process.exit(1));
onResolve 的回调函数
onResolve
函数的回调函数会在 esbuild
构建每个模块的导入路径(可匹配的)时执行。
onResolve
函数的回调函数需要返回一个对象,其中会包含 path
、namespace
、external
等属性。
通常,该回调函数会用于自定义 esbuild
处理 path
的方式,例如:
重写原本的路径,例如重定向到其他路径
将该路径所对应的模块标记为 external
,即不会对改文件进行构建操作(原样输出)
onLoad 的回调函数
onLoad
函数的回调函数会在 esbuild
解析模块之前调用,主要是用于处理并返回模块的内容,并告知 esbuild
要如何解析它们。并且,需要注意的是 onLoad
的回调函数不会处理被标记为 external
的模块。
onLoad
函数的回调函数需要返回一个对象,该对象总共有 9 个属性。这里我们来认识一下较为常见 2 个属性:
contents
处理过的模块内容
loader
告知 esbuild
要如何解释该内容(默认为 js
)。例如,返回的模块内容是 CSS
,则声明 loader
为 css
本节对 rollup
和 esbuild
中的常见使用方式做了介绍,包括常用命令和插件的使用,下一节会介绍下 vite
插件的学习使用,如果有问题欢迎留言,谢谢阅读!
原文地址:https://cloud.tencent.com/developer/article/1942747
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。