从入口文件开始,构建module,匹配文件类型的loader链,运行loader进行处理,得到module的依赖文件。 再对依赖文件进行module构建,由此递归形成module的依赖网。 根据入口和其他成组需要,组织chunk与module映射关系,并分组chunkGroup。最后根据chunk做静态文件的输出。
template
- main
- chunk
- 一个文件视为 `dependency`
- `dependency` ----`ModuleFactory`-->> `module`
- `module` 的 `dependency` ->> `module` ==》 `module graph`
-
- 用 `loader` 预处理 `module`
- 模块之间的依赖关系 `dependency`
lib/node/NodeEnvironmentPlugin.jscompiler.hooks.environmentcompiler.hooks.afterEnvironmentlib/WebpackOptionsApply.js target library externals devtool moduleentry 做到支持 String, Array, Function,增加 make 插件使增加入口entry-optioncompilation 插件compiler.hooks.afterPluginscompiler.resolverFactory.hooks.resolveOptionscompiler.hooks.afterResolverscompiler.hooks.beforeRuncompiler.hooks.runcompilation.hooks.needAdditionalPasscompiler.hooks.donecompiler.hooks.additionalPasscompiler.hooks.failed根据文件变化时间戳判断是否更新
compiler.hooks.watchRuncompiler.hooks.watchClosecompiler.hooks.beforeCompilecompiler.hooks.compilecompiler.hooks.thisCompilationcompiler.hooks.compilationcompiler.hooks.make compilation.prefetch / compilation.addEntry SingleEntryPlugin MultiEntryPlugin DllEntryPlugin DynamicEntryPlugin PrefetchPlugin AutomaticPrefetchPlugin
compilation.hooks.addEntrycompilation.hooks.failedEntrycompilation.hooks.succeedEntrymodule(这里以normalModuleFactory作说明)
自定义模块类需绑定工厂:
compilation.dependencyFactories.set(userDependency, userFactory)自定义的 dependencie 需继承webpack/lib/Dependency.js自定义的 factory 需有create(data: ModuleFactoryCreateData, callback: ModuleCallback)函数lib/NormalModule.js/lib/NormalModuleFactory.js
before-resolvefactoryresolver(): resolver require 字符串正则解析,得到内敛 loader 格式:
loader!loader!loader!file前部可以设置此文件是否使用外部的前/中/后处理
- '-!xxxx' 只使用外部后处理
- '!xxxx' 不使用外部中处理
- '!!xxxx' 不使用任何外部loader
loader
loader根据enforce指定使用的时机并以此排序 顺序:外部后 - 内敛 - 外部中 - 外部前 后续会从左往右调用loader的pitch方法(有返回值时不再执行后面的loader),再从右往左调用loader方法
resolve 验证模块和loader有效parserafter-resolvecreate-module()module 实例module(): moduledependencie 绑定 module 做缓存 ············ __NormalModuleFactoryCachebuild-module(modules): voidloader处理
loader内部解析文件处理完后转成js格式文本返回或直接调用loaderContext.callback
program(ast, comments): any 得到
dependencies
hashwarn/errorfailed-module(modules): voidsucceed-module(modules): voidmodule 作为 preparedChunkcompilation.hooks.finishModulescompilation.hooks.sealcompilation.hooks.optimizeDependenciesBasiccompilation.hooks.optimizeDependenciescompilation.hooks.optimizeDependenciesAdvancedcompilation.hooks.afterOptimizeDependenciescompilation.hooks.beforeChunkscompilation.hooks.afterChunkscompilation.hooks.optimizecompilation.hooks.optimizeModulesBasiccompilation.hooks.optimizeModulescompilation.hooks.optimizeModulesAdvancedcompilation.hooks.afterOptimizeModulescompilation.hooks.optimizeChunksBasiccompilation.hooks.optimizeChunkscompilation.hooks.optimizeChunksAdvancedcompilation.hooks.afterOptimizeChunkscompilation.hooks.optimizeTreecompilation.hooks.afterOptimizeTreecompilation.hooks.optimizeChunkModulesBasiccompilation.hooks.optimizeChunkModules terser-webpack-plugin 做 Tree-Shakingcompilation.hooks.optimizeChunkModulesAdvancedcompilation.hooks.afterOptimizeChunkModulescompilation.hooks.shouldRecordcompilation.hooks.reviveModulescompilation.hooks.optimizeModuleOrdercompilation.hooks.advancedOptimizeModuleOrdercompilation.hooks.beforeModuleIdscompilation.hooks.moduleIdscompilation.hooks.optimizeModuleIdscompilation.hooks.afterOptimizeModuleIdscompilation.hooks.reviveChunkscompilation.hooks.optimizeChunkOrdercompilation.hooks.beforeChunkIdscompilation.hooks.optimizeChunkIdscompilation.hooks.afterOptimizeChunkIdscompilation.hooks.recordModulescompilation.hooks.recordChunks
crypto
compilation.hooks.beforeHashcompilation.hooks.afterHashcompilation.hooks.recordHashcompilation.hooks.beforeModuleAssetscompilation.hooks.shouldGenerateChunkAssetscompilation.hooks.beforeChunkAssetscompilation.hooks.additionalChunkAssetscompilation.hooks.recordcompilation.hooks.additionalAssetscompilation.hooks.optimizeChunkAssetscompilation.hooks.afterOptimizeChunkAssetscompilation.hooks.optimizeAssetscompilation.hooks.afterOptimizeAssetscompilation.hooks.needAdditionalSealcompilation.hooks.afterSealcompiler.hooks.afterCompilecompiler.hooks.shouldEmitcompiler.hooks.assetEmittedcompiler.hooks.afterEmitcompiler.hooks.emitrecordsInputPath/recordsOutputPath/recordsPathwebpackConfig.resolve.pluginsresolveparsedResolvedescribedResolverawModulemodulerelativedescribedRelativedirectoryexistingDirectoryundescribedRawFilerawFilefileexistingFileresolved以‘下划线拼写’定义,
resolver.getHook并支持before-和after-前缀
resolver.getHook(name).tapAsync(pluginName, (request, resolveContext, callback)=>{return callback()})resolver.getHook(name).tapPromise(pluginName, (request, resolveContext)=>{return Promise.resolve(undefined)})chunk 拆分插件,根据配置
options.optimization.splitChunks运行
在compilation.hooks.optimizeChunksAdvanced阶段
遍历modules根据test配置匹配 -> 根据优先级(priority/size/...)-> 根据maxInitialRequests/maxAsyncRequests去除多的chunk
默认:
const splitChunks = {
// 选择哪些 chunk 进行优化
// all - 优化所有chunks,chunk 可以在异步和非异步 chunk 之间共享
// async - 非异步 chunk
// (chunk)=>boolean - 判断函数
chunks: 'async',
// 生成 chunk 的最小体积(以 bytes 为单位)
minSize: 20000,
minRemainingSize: 0,
// 拆分前必须共享模块的最小 chunks 数
minChunks: 1,
// 按需加载时的最大并行请求数
maxAsyncRequests: 30,
// 入口点的最大并行请求数
maxInitialRequests: 30,
enforceSizeThreshold: 50000,
// 缓存组,继承上面的属性
cacheGroups: {
defaultVendors: {
// 匹配规则
test: /[\\/]node_modules[\\/]/,
// 优先级
priority: -10,
// 如果当前 chunk 包含已从主 bundle 中拆分出的模块,则它将被重用,而不是生成新的模块
reuseExistingChunk: true,
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
},
// 设置为 false 以禁用默认缓存组
// defaultVendors: false
// default: false
},
}
对有依赖关系的 compiler 同步编译;无依赖关系的,依次运行编译,因编译过程异步,即是同时编译的。
期间 chunks/modules 一直未释放,为 Stats 提供数据。
!分隔!之后为文件??后面带ident RuleSet 定义与解析(存在对象中)compiler.options.module.defaultRules.concat(compiler.options.module.rules)对文件的缓存,定义并保存lastAccess用于maxAge判断。