resolveId :做路径解析,比如我 import foo from 'foo'; 要去找这个 foo 文件究竟在哪里。还有一个虚拟模块(Virtual Module)的概念,就是 resolveId 不是返回的一个真实的文件而是一个虚拟的 module。虚拟模块很有用,rollup 中很多功能都是用虚拟模块实现的,虚拟模块id约定都以 \0 开头,这样告诉其它插件不要去 load 和 transform 这些模块。
load :读取文件,默认实现是从文件系统中读取,虚拟模块一般都要重写 load, 因为虚拟模块一般不对应真正的文件。
transform: 对文件内容进行转换,如把 ts 编译为 js。就是 webpack 中 loader 的概念。
moduleParsed: 在一个模块完全解析完毕时回调(就是这个文件的所有依赖已经找到,所有 transfrom 也已经执行完毕)
buildEnd: 在所有模块及其依赖都已经解析完毕时回调,这时整个Graph(依赖图)图里的结点都已经处理完毕,下一步就可以输出 bundle 了。在这里可以拿到所有解析完毕的 module。
buildEnd() {
const moduleIds = this.getModuleIds();
for(let id of moduleIds) {
const module = this.getModuleInfo(id);
}
}
moduleParsed 每解析完一个文件都会回调一次, 而buildEnd 只会调用一次。
黄色的 hooks 是 first (resolveId, load 等)类型的,如果多个插件都注册了 first 类型的钩子,前面插件的钩子如果返回非 null, 后面插件的钩子就不会执行了,具有截断功能。
sequential: 顾名思义,按插件注册顺序依次执行,即使前面插件有 async 的钩子也要等 async 函数 resolve 后,后面插件的钩子才会执行。
parallel: 如果有 async 的钩子,这些 async 函数是并行调起的,后面插件的钩子不会等前面插件的钩子先 resolve。
order: pre/post 可以改变插件钩子的执行顺序, pre 第一个执行, post 最后一个执行。如果有多个插件都使用了 pre/post 再按照插件的注册顺序排序。
插件可以在 module 中添加 meta 信息供其它插件使用。
插件中可以通过手动调用 this.resolve() 方法来添加用户自定义的 optison 信息供其它插件使用。
如 commonjs 插件会添加 commonjs:{isCommonJS}, isCommonJS 表示模块是否是 cjs。
node-resolve 插件会添加 {"node-resolve":{"resolved":"id"}}。
基本每个 rollup 项目都会添加这两个插件,我们可以在自己的插件中使用这些 options。
this.resolve() 函数的作用: 前面说过通过手动调用 this.resolve() 可以添加自定义的 options。 resolve() 会把所有插件的 resolveId 钩子重新调用一遍,包括当前插件自己。skipSelf:true 参数可以跳过当前插件的 resolveId 。 你能想到在 resolveId 中调用 this.resolve() 如果不 skipSelf 很容易死循环。
commonjs 和 node-resolve 里面都主动调用了 this.resovle() 来添加自定义的 options , node-resolve 中也没有 skipSelf 而是自己处理了死循环的情况。
node-resolve 插件和 commonjs 插件谁应该写在前面谁应该写在后面???
答案是都行
commonjs 无论你写在哪里都会自己把自己的 resolveId 作为一个独立插件插入到第一个位置。因为 resolveId 是 first 类型的容易被别的插件拦截,这样 commonjs 就处理不到了。
node-resolve 插件的 resolveId 是 post 类型的,会最后一个执行。你自己插件的 resolveId 一般都是在 node-resolve 之前执行的。如果你也用 post 然后挂在 node-resolve 之后你的resolveId 才能在 node-resolve 后面执行。但这样你的 resolveId 大概率不会回调,因为 node-resolve 插件实现了经典的 node 路径解析算法,大部分的路径 node-resolve 都能解析到, 这也是 node-resolve 默认最后一个 resolveId 的原因。
perf:true 配置可以对各个构建阶段进行打点统计,在进行性能分析时很有用。
Rollup 设计挺好的,我都想用 Rust 重写一个 Rollup 。为什么不用 C/C++, 想用 Rust 主要是 Rust 生态还行,有 swc 等轮子可以复用,毕竟我也不会重头写 js ast 解析等高级功能。