原来rollup这么简单之 rollup.generate + rollup.write篇 (3)

调用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的话,推导出导出模式

for (const chunk of chunks) { // 尽可能少的打包模块 // 设置chunk的exportNames if (!inputOptions.preserveModules) chunk.generateInternalExports(outputOptions); // 尽可能多的打包模块 if (inputOptions.preserveModules || (chunk.facadeModule && chunk.facadeModule.isEntryPoint)) // 根据导出,去推断chunk的导出模式 chunk.exportMode = getExportMode(chunk, outputOptions, chunk.facadeModule!.id); }

预渲染chunks。
使用magic-string模块进行source管理,初始化render配置,对依赖进行解析,添加到当前chunks的dependencies属性上,按照执行顺序对依赖们进行排序,处理准备动态引入的模块,设置唯一标志符(?)

for (const chunk of chunks) { chunk.preRender(outputOptions, inputBase); }

优化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进而抛出错误提示

let chunkCount = 0; //计数 for (const fileName of Object.keys(bundle)) { const file = bundle[fileName]; if (file.type === 'asset') continue; chunkCount++; if (chunkCount > 1) break; } if (chunkCount > 1) { // sourcemapFile配置 if (outputOptions.sourcemapFile) return error({ code: 'INVALID_OPTION', message: '"output.sourcemapFile" is only supported for single-file builds.' }); // file字段 if (typeof outputOptions.file === 'string') return error({ code: 'INVALID_OPTION', message: 'When building multiple chunks, the "output.dir" option must be used, not "output.file".' + (typeof inputOptions.input !== 'string' || inputOptions.inlineDynamicImports === true ? '' : ' To inline dynamic imports, set the "inlineDynamicImports" option.') }); }

之后调用写入方法: 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);

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zywwgw.html