Fancy Front End Fancy Front End
  • 开始上手
  • 基础
  • 调度器(Scheduler)
  • 更新器(Updater)
  • 渲染器(Render)
  • 更新周期
  • hooks 原理
  • 总结
  • 📙 React源码漂流记
  • 开始上手
  • 基础
  • reactivity
  • runtime-core
  • runtime-dom
  • Awesome Web
  • Awesome NodeJS
话题
  • 导航
  • Q&A
  • 幻灯片
  • 关于
  • 分类
  • 标签
  • 归档
博客 (opens new window)
GitHub (opens new window)

Jonsam NG

让有意义的事变得有意思,让有意思的事变得有意义
  • 开始上手
  • 基础
  • 调度器(Scheduler)
  • 更新器(Updater)
  • 渲染器(Render)
  • 更新周期
  • hooks 原理
  • 总结
  • 📙 React源码漂流记
  • 开始上手
  • 基础
  • reactivity
  • runtime-core
  • runtime-dom
  • Awesome Web
  • Awesome NodeJS
话题
  • 导航
  • Q&A
  • 幻灯片
  • 关于
  • 分类
  • 标签
  • 归档
博客 (opens new window)
GitHub (opens new window)
  • 开始上手
  • Plan 计划
  • typescript-utility

  • single-spa源码

  • qiankun源码

  • webpack

    • 开始阅读
    • tapable源码

    • init阶段

      • 本章概要
      • init 阶段:compiler
      • init 阶段:options
        • 目录
        • getNormalizedWebpackOptions
        • 顶层 option
        • applyWebpackOptionsBaseDefaults 和 applyWebpackOptionsDefaults
        • NodeEnvironmentPlugin
        • WebpackOptionsApply
        • 参考
    • make阶段

    • 总结

  • axios

  • solid

  • vite源码

  • jquery源码

  • snabbdom

  • am-editor

  • html2canvas

  • express

  • acorn源码

  • immutable.js源码

  • web
  • webpack
  • init阶段
jonsam
2022-04-22
目录

init 阶段:options

在上一节中,我们以 compiler 为主线探讨了 webpack 在 init 阶段的核心原理,在本节中我们将对 init 阶段 options 的处理进行更细化的探讨。

# 目录

  • 目录
  • getNormalizedWebpackOptions
  • 顶层 option
  • applyWebpackOptionsBaseDefaults 和 applyWebpackOptionsDefaults
  • NodeEnvironmentPlugin
  • WebpackOptionsApply
  • 参考

# getNormalizedWebpackOptions

// lib/config/normalization.js
const getNormalizedWebpackOptions = configs => {
  // ......
  return normalizedConfigs;
};
1
2
3
4
5

这部分代码主要是校验和规整(normalize)options,代码很繁琐,甚至 option 都是按照字母顺序排序,与主流程关系不大,此处不再赘述。

不过可以借此机会,熟悉下 webpack 的 顶层options 有哪些?

# 顶层 option

webpack 配置有如下顶层 option。

option 描述
amd (opens new window) 设置 require.amd 或 define.amd 的值。设置 amd 为 false 会禁用 webpack 的 AMD 支持。
bail (opens new window) 在第一个错误出现时抛出失败结果,而不是容忍它。这将迫使 webpack 退出其打包过程。
cache (opens new window) 缓存生成的 webpack 模块和 chunk,来改善 构建速度 。
context (opens new window) 基础目录,绝对路径,用于从配置中解析入口点 (entry point) 和 加载器 (loader)。默认使用 Node.js 进程的当前工作目录。
dependencies (opens new window) 一个 name 列表,定义它所依赖的所有兄弟(sibling)配置。需要首先编译依赖的配置。
devServer (opens new window) 配置 webpack-dev-server
devtool (opens new window) 此选项控制是否生成,以及如何生成 source map。
entry (opens new window) 开始应用程序打包过程的一个或多个起点。如果传入数组,则会处理所有条目。一个需要考虑的规则:每个 HTML 页面都有一个入口起点。单页应用 (SPA):一个入口起点,多页应用 (MPA):多个入口起点。
experiments (opens new window) experiments 配置是在 webpack 5 中推出,目的是为了给用户赋能去开启并试用一些实验的特性。
externals (opens new window) 防止将某些 import 的包 (package) 打包到 bundle 中,而是在运行时 (runtime) 再去从外部获取这些扩展依赖 (external dependencies)。
externalsPresets (opens new window) 为特定的 target 启用 externals 的 preset。
externalsType (opens new window) 指定 externals 的默认类型。当 external 被设置为 amd,umd,system 以及 jsonp 时,output.libraryTarget 的值也应相同。
ignoreWarnings (opens new window) 告诉 webpack 忽略掉特定的警告。
infrastructureLogging (opens new window) 用于基础设施水平的日志选项。
loader (opens new window) 在 loader 上下文 中暴露自定义值。
mode (opens new window) 提供 mode 配置选项,告知 webpack 使用相应模式的内置优化。
module (opens new window) 这些选项决定了如何处理项目中的不同类型的模块。
name (opens new window) 配置的名称。当加载不同的配置时会被使用。
node (opens new window) 这些选项可以配置是否 polyfill 或 mock 某些 Node.js 全局变量。此功能由 webpack 内部的 NodeStuffPlugin 插件提供。
optimization (opens new window) 从 webpack 4 开始,会根据你选择的 mode 来执行不同的优化, 不过所有的优化还是可以手动配置和重写。
output (opens new window) output 位于对象最顶级键 (key),包括了一组选项,指示 webpack 如何去输出、以及在哪里输出你的「bundle、asset 和其他你所打包或使用 webpack 载入的任何内容」。
parallelism (opens new window) 限制并行处理的模块数量。可以用于调优性能或获取更可靠的性能分析结果。
performance (opens new window) 控制 webpack 如何通知「资源 (asset) 和入口起点超过指定文件限制」。
plugins (opens new window) plugins 选项用于以各种方式自定义 webpack 构建过程。webpack 附带了各种内置插件,可以通过 webpack.[plugin-name] 访问这些插件。
profile (opens new window) 捕获一个应用程序 "配置文件",包括统计和提示,然后可以使用 Analyze 分析工具进行详细分析。
recordsInputPath (opens new window) 指定读取最后一条记录的文件的名称。这可以用来重命名一个记录文件。
recordsOutputPath (opens new window) 指定记录要写入的位置。
resolve (opens new window) 这些选项能设置模块如何被解析。webpack 提供合理的默认值,但是还是可能会修改一些解析的细节。
resolveLoader (opens new window) 这组选项与上面的 resolve 对象的属性集合相同, 但仅用于解析 webpack 的 loader 包。
snapshot (opens new window) snapshot 配置项决定文件系统是如何创建和无效快照。
stats (opens new window) stats 选项让你更精确地控制 bundle 信息该怎么显示。 如果你不希望使用 quiet 或 noInfo 这样的不显示信息,而是又不想得到全部的信息,只是想要获取某部分 bundle 的信息,使用 stats 选项是比较好的折衷方式。
target (opens new window) webpack 能够为多种环境或 target 构建编译。告知 webpack 为目标 (target) 指定一个环境。默认值为 "browserslist",如果没有找到 browserslist 的配置,则默认为 "web"
watch (opens new window) 启用 Watch 模式。这意味着在初始构建之后,webpack 将继续监听任何已解析文件的更改。
watchOptions (opens new window) 一组用来定制 watch 模式的选项

参考:

  • Why AMD? (opens new window)
  • Plugins | webpack 中文文档 (opens new window)

# applyWebpackOptionsBaseDefaults 和 applyWebpackOptionsDefaults

这两个函数为 webpack 默认的 options 合并进应用配置的 options。

以 applyWebpackOptionsDefaults 为例:

context/target/devtool/watch/profile/parallelism/recordsInputPath/recordsOutputPath => cache => applySnapshotDefaults => applyModuleDefaults => applyOutputDefaults => applyExternalsPresetsDefaults => applyLoaderDefaults => externalsType => applyNodeDefaults => performance => applyPerformanceDefaults => applyOptimizationDefaults ......
1

下面开看下几个辅助函数:

// Sets a constant default value when undefined
const D = (obj, prop, value) => {
 if (obj[prop] === undefined) {
  obj[prop] = value;
 }
};
// Sets a dynamic default value when undefined, by calling the factory function
const F = (obj, prop, factory) => {
 if (obj[prop] === undefined) {
  obj[prop] = factory();
 }
};
// 
const A = (obj, prop, factory) => {
 const value = obj[prop];
 if (value === undefined) {
  obj[prop] = factory();
 } else if (Array.isArray(value)) {
  let newArray = undefined;
  for (let i = 0; i < value.length; i++) {
   const item = value[i];
   if (item === "...") {
    if (newArray === undefined) {
     newArray = value.slice(0, i);
     //  注意:newArray 是应用,赋值之后 newArray 仍然在变化
     obj[prop] = newArray;
    }
    const items = factory();
    if (items !== undefined) {
     for (const item of items) {
      newArray.push(item);
     }
    }
   } else if (newArray !== undefined) {
    newArray.push(item);
   }
  }
 }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

# NodeEnvironmentPlugin

此插件初始化 Node 环境,包括日志组件 infrastructureLogger、文件 io 组件 inputFileSystem、文件 watch 组件 watchFileSystem。

class NodeEnvironmentPlugin {
 apply(compiler) {
  const { infrastructureLogging } = this.options;
  // 初始化创建 infrastructureLogger
  compiler.infrastructureLogger = createConsoleLogger(/** ...... */);
  // 初始化文件系统相关,inputFileSystem 和 watchFileSystem
  compiler.inputFileSystem = new CachedInputFileSystem(fs, 60000);
  const inputFileSystem = compiler.inputFileSystem;
  compiler.outputFileSystem = fs;
  compiler.intermediateFileSystem = fs;
  // this.watcher = new Watchpack(this.watcherOptions);
  compiler.watchFileSystem = new NodeWatchFileSystem(
   compiler.inputFileSystem
  );
  // 注册 Callback:Hook.beforeRun
  compiler.hooks.beforeRun.tap("NodeEnvironmentPlugin", (compiler) => {
   if (compiler.inputFileSystem === inputFileSystem) {
    compiler.fsStartTime = Date.now();
    inputFileSystem.purge();
   }
  });
 }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  • inputFileSystem 和 watchFileSystem 分别是根据 enhanced-resolve 包和 watchpack 实现的,链接见【参考】。

# WebpackOptionsApply

此组件(不具备 apply 方法,应该不视为 webpack 插件) 根据 options 注册内置插件。

代码位置:lib/WebpackOptionsApply.js

option 插件 作用 备注
externals ExternalsPlugin 从输出的 bundle 中排除依赖 CompilerHook.compile => ExternalModuleFactoryPlugin => NormalModuleFactoryHook.factorize => handleExternals => handleExternal
externalsPresets.node NodeTargetPlugin 将 node.js 的内置模块视为 external 模块(如 fs,path 或 vm),使用时通过 require () 加载。 ExternalsPlugin("node-commonjs", builtins)
externalsPresets.electronMain ElectronTargetPlugin("main") 将 main 上下文中的 electron 内置模块视为 external 模块(如 app,ipc-main 或 shell),使用时通过 require () 加载。 ExternalsPlugin
externalsPresets.electronPreload ElectronTargetPlugin("preload") 将预加载上下文的 electron 内置模块视为 external 模块(如 web-frame,ipc-renderer 或 shell),使用时通过 require () 加载。 ExternalsPlugin
externalsPresets.electronRenderer ElectronTargetPlugin("renderer") 将 renderer 上下文的 electron 内置模块视为 external 模块(如 web-frame、ipc-renderer 或 shell),使用时通过 require () 加载。 ExternalsPlugin
externalsPresets.electron ElectronTargetPlugin 将 main 和预加载上下文中常见的 electron 内置模块视为 external 模块(如 electron,ipc 或 shell),使用时通过 require () 加载。 ExternalsPlugin
externalsPresets.nwjs ExternalsPlugin("node-commonjs", "nw.gui") 将 NW.js 遗留的 nw.gui 模块视为 external 模块,使用时通过 require () 加载。 ExternalsPlugin
externalsPresets.webAsync ExternalsPlugin("import") 将 'http (s)😕/...' 以及'std:...' 的引用视为 external 模块,使用时通过 async import () 加载。(注意,此 external 类型为 async 模块,它对执行会产生各种副作用)。 ExternalsPlugin
externalsPresets.web ExternalsPlugin("module") 将 http (s)😕/... 以及 std:... 视为 external 模块,使用时通过 import 加载。(注意,这将改变执行顺序,因为 external 代码会在该块中的其他代码执行前被执行)。 ExternalsPlugin
ChunkPrefetchPreloadPlugin CompilerHook.compilation => ......
output.chunkFormat ArrayPushCallbackChunkFormatPlugin、CommonJsChunkFormatPlugin、ModuleChunkFormatPlugin chunk 的格式(formats 默认包含 'array-push' (web/WebWorker)、'commonjs' (node.js)、'module' (ESM))
output.enabledChunkLoadingTypes EnableChunkLoadingPlugin
output.enabledWasmLoadingTypes EnableWasmLoadingPlugin
output.enabledLibraryTypes EnableLibraryPlugin
output.pathinfo ModuleInfoHeaderPlugin
output.clean CleanPlugin
devtool EvalSourceMapDevToolPlugin、SourceMapDevToolPlugin、EvalDevToolModulePlugin、EvalDevToolModulePlugin
JavascriptModulesPlugin
JsonModulesPlugin
AssetModulesPlugin
experiments.syncWebAssembly WebAssemblyModulesPlugin
experiments.asyncWebAssembly AsyncWebAssemblyModulesPlugin
experiments.css CssModulesPlugin
experiments.lazyCompilation LazyCompilationPlugin
experiments.buildHttp HttpUriPlugin
EntryOptionPlugin
RuntimePlugin
InferAsyncModulesPlugin
DataUriPlugin
FileUriPlugin
CompatibilityPlugin (opens new window) Currently useless. Ensures compatibility with other module loaders.
HarmonyModulesPlugin
options.amd AMDPlugin、RequireJsStuffPlugin
CommonJsPlugin
LoaderPlugin
APIPlugin
ExportsInfoApiPlugin
WebpackIsIncludedPlugin
ConstPlugin
UseStrictPlugin
RequireIncludePlugin
RequireEnsurePlugin
RequireContextPlugin
ImportPlugin
ImportMetaContextPlugin
SystemPlugin
ImportMetaPlugin
URLPlugin
SystemPlugin
WorkerPlugin
DefaultStatsFactoryPlugin
JavascriptMetaInfoPlugin
options.mode WarnNoModeSetPlugin
EnsureChunkConditionsPlugin
optimization.removeAvailableModules RemoveParentModulesPlugin
optimization.removeEmptyChunks RemoveEmptyChunksPlugin
optimization.mergeDuplicateChunks MergeDuplicateChunksPlugin
optimization.flagIncludedChunks FlagIncludedChunksPlugin
optimization.sideEffects SideEffectsFlagPlugin
optimization.providedExports FlagDependencyExportsPlugin
optimization.usedExports FlagDependencyUsagePlugin
optimization.innerGraph InnerGraphPlugin
optimization.mangleExports MangleExportsPlugin
optimization.concatenateModules ModuleConcatenationPlugin
optimization.splitChunks SplitChunksPlugin
optimization.emitOnErrors NoEmitOnErrorsPlugin
optimization.realContentHash RealContentHashPlugin
optimization.checkWasmTypes WasmFinalizeExportsPlugin
optimization.moduleIds NaturalModuleIdsPlugin、NamedModuleIdsPlugin、WarnDeprecatedOptionPlugin、HashedModuleIdsPlugin、DeterministicModuleIdsPlugin、OccurrenceModuleIdsPlugin
optimization.chunkIds NaturalChunkIdsPlugin、NamedChunkIdsPlugin、DeterministicChunkIdsPlugin、OccurrenceChunkIdsPlugin
optimization.nodeEnv DefinePlugin (opens new window) DefinePlugin 允许在 编译时 将你代码中的变量替换为其他值或表达式。这在需要根据开发模式与生产模式进行不同的操作时,非常有用。
optimization.performance SizeLimitsPlugin
TemplatedPathPlugin
RecordIdsPlugin
WarnCaseSensitiveModulesPlugin
AddManagedPathsPlugin
cache MemoryWithGcCachePlugin、MemoryCachePlugin、AddBuildDependenciesPlugin、IdleFileCachePlugin、PackFileCacheStrategy
ResolverCachePlugin
ignoreWarnings IgnoreWarningsPlugin

# 参考

  • webpack/enhanced-resolve: Offers an async require.resolve function. It's highly configurable. (opens new window)
  • webpack/watchpack: Wrapper library for directory and file watching. (opens new window)
  • Plugins | webpack 中文文档 (opens new window)
编辑 (opens new window)
上次更新: 2022/09/06, 14:25:16
init 阶段:compiler
本章概要

← init 阶段:compiler 本章概要→

最近更新
01
渲染原理之组件结构与 JSX 编译
09-07
02
计划跟踪
09-06
03
开始上手
09-06
更多文章>
Theme by Vdoing | Copyright © 2022-2022 Fancy Front End | Made by Jonsam by ❤
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式