调用renderStart钩子函数,用来访问output和input配置,可能大家看到了很多调用钩子函数的方法,比如hookParallel、hookSeq等等,这些都是用来触发插件里提供的钩子函数,不过是执行方式不同,有的是并行的,有的是串行的,有的只能执行通过一个等等,这会单独抽出来说。
await outputPluginDriver.hookParallel('renderStart', [outputOptions, inputOptions]);执行footer banner intro outro钩子函数,内部就是执行这几个钩子函数,默认值为option[footer|banner|intro|outro],最后返回字符串结果待拼接。
const addons = await createAddons(outputOptions, outputPluginDriver);处理preserveModules模式,也就是是否尽可能少的打包,而不是每个模块都是一个chunk
如果是尽可能少的打包的话,就将chunks的导出多挂载到chunks的exportNames属性上,供之后使用
如果每个模块都是一个chunk的话,推导出导出模式
预渲染chunks。
使用magic-string模块进行source管理,初始化render配置,对依赖进行解析,添加到当前chunks的dependencies属性上,按照执行顺序对依赖们进行排序,处理准备动态引入的模块,设置唯一标志符(?)
优化chunks
if (!optimized && inputOptions.experimentalOptimizeChunks) { optimizeChunks(chunks, outputOptions, inputOptions.chunkGroupingSize!, inputBase); optimized = true; }将chunkId赋到上文创建的outputBundleWithPlaceholders上
assignChunkIds( chunks, inputOptions, outputOptions, inputBase, addons, outputBundleWithPlaceholders, outputPluginDriver );设置好chunks的对象,也就是将chunks依照id设置到outputBundleWithPlaceholders上,这时候outputBundleWithPlaceholders上已经有完整的chunk信息了
outputBundle = assignChunksToBundle(chunks, outputBundleWithPlaceholders);语法树解析生成code操作,最后返回outputBundle。
await Promise.all( chunks.map(chunk => { const outputChunk = outputBundleWithPlaceholders[chunk.id!] as OutputChunk; return chunk .render(outputOptions, addons, outputChunk, outputPluginDriver) .then(rendered => { // 引用类型,outputBundleWithPlaceholders上的也变化了,所以outputBundle也变化了,最后返回outputBundle outputChunk.code = rendered.code; outputChunk.map = rendered.map; return outputPluginDriver.hookParallel('ongenerate', [ { bundle: outputChunk, ...outputOptions }, outputChunk ]); }); }) ); return outputBundle;generate内部的createOutput方法
createOutput接受generate的返回值,并对生成的OutputBundle进行过滤和排序
function createOutput(outputBundle: Record<string, OutputChunk | OutputAsset | {}>): RollupOutput { return { output: (Object.keys(outputBundle) .map(fileName => outputBundle[fileName]) .filter(outputFile => Object.keys(outputFile).length > 0) as ( | OutputChunk | OutputAsset )[]).sort((outputFileA, outputFileB) => { const fileTypeA = getSortingFileType(outputFileA); const fileTypeB = getSortingFileType(outputFileB); if (fileTypeA === fileTypeB) return 0; return fileTypeA < fileTypeB ? -1 : 1; }) as [OutputChunk, ...(OutputChunk | OutputAsset)[]] }; }rollup.write
write方法和generate方法几乎一致,只不过是generate方法的第二个参数为true,供generateBundle钩子函数中使用,已表明当前是wirte还是generate阶段。
之后是获取当前的chunks数,多出口的时候会检测配置的file和sourcemapFile进而抛出错误提示
之后调用写入方法: writeOutputFile
await Promise.all( Object.keys(bundle).map(chunkId => writeOutputFile(result, bundle[chunkId], outputOptions, outputPluginDriver) ) );writeOutputFile方法就很直观了,解析路径
const fileName = resolve(outputOptions.dir || dirname(outputOptions.file!), outputFile.fileName);