大家好,我是小雨小雨,致力于分享有趣的、实用的技术文章。
内容分为翻译和原创,如果有问题,欢迎随时评论或私信,希望和大家一起进步。
大家的支持是我创作的动力。
计划rollup系列打算一章一章的放出,内容更精简更专一更易于理解
这是rollup系列的最后一篇文章,以下是所有文章链接。
rollup.rollup
rollup.generate + rollup.write
rollup.watch
tree shaking
plugins <==== 当前文章
TL;DRrollup的插件和其他大型框架大同小异,都是提供统一的标准接口,通过约定大于配置定义公共配置,注入当前构建结果相关的属性与方法,供开发者进行增删改查操作。为稳定可持续增长提供了强而有力的铺垫!
但不想webpack区分loader和plugin,rollup的plugin既可以担任loader的角色,也可以胜任传统plugin的角色。rollup提供的钩子函数是核心,比如load、transform对chunk进行解析更改,resolveFileUrl可以对加载模块进行合法解析,options对配置进行动态更新等等~
注意点所有的注释都在这里,可自行阅读
!!!提示 => 标有TODO为具体实现细节,会视情况分析。
!!!注意 => 每一个子标题都是父标题(函数)内部实现
!!!强调 => rollup中模块(文件)的id就是文件地址,所以类似resolveID这种就是解析文件地址的意思,我们可以返回我们想返回的文件id(也就是地址,相对路径、决定路径)来让rollup加载
rollup是一个核心,只做最基础的事情,比如提供, 比如打包成不同风格的内容,我们的插件中提供了加载文件路径,解析文件内容(处理ts,sass等)等操作,是一种插拔式的设计,和webpack类似
插拔式是一种非常灵活且可长期迭代更新的设计,这也是一个中大型框架的核心,人多力量大嘛~
Graph: 全局唯一的图,包含入口以及各种依赖的相互关系,操作方法,缓存等。是rollup的核心
PathTracker: 引用(调用)追踪器
PluginDriver: 插件驱动器,调用插件和提供插件环境上下文等
FileEmitter: 资源操作器
GlobalScope: 全局作用局,相对的还有局部的
ModuleLoader: 模块加载器
NodeBase: ast各语法(ArrayExpression、AwaitExpression等)的构造基类
插件机制分析rollup的插件其实一个普通的函数,函数返回一个对象,该对象包含一些基础属性(如name),和不同阶段的钩子函数,像这个样子:
function plugin(options = {}) { return { name: 'rollup-plugin', transform() { return { code: 'code', map: { mappings: '' } }; } }; }这里是官方建议遵守的.
我们平常书写rollup插件的时候,最关注的就是钩子函数部分了,钩子函数的调用时机有三类:
const chunks = rollup.rollup执行期间的
chunks.generator(write)执行期间的
监听文件变化并重新执行构建的rollup.watch执行期间的watchChange钩子函数
除了类别不同,rollup也提供了几种钩子函数的执行方式,每种方式都又分为同步或异步,方便内部使用:
async: 处理promise的异步钩子,也有同步版本
first: 如果多个插件实现了相同的钩子函数,那么会串式执行,从头到尾,但是,如果其中某个的返回值不是null也不是undefined的话,会直接终止掉后续插件。
sequential: 如果多个插件实现了相同的钩子函数,那么会串式执行,按照使用插件的顺序从头到尾执行,如果是异步的,会等待之前处理完毕,在执行下一个插件。
parallel: 同上,不过如果某个插件是异步的,其后的插件不会等待,而是并行执行。
文字表达比较苍白,咱们看几个实现:
钩子函数: hookFirst
使用场景:resolveId、resolveAssetUrl等
钩子函数: hookFirstSync
使用场景:resolveFileUrl、resolveImportMeta等