addEntry
EntryPlugin的注册
webpack会从入口开始解析依赖。
-
WebpackOptionsApply
new WebpackOptionsApply().process(compiler, options); class WebpackOptionsApply { constructor () {} process () { // 注册 EntryOptionPlugin new EntryOptionPlugin().apply(compiler); } }
-
EntryOptionPlugin
EntryOptionPlugin的作用是注册compiler.hooks.entryOption钩子,当钩子被触发的时候,调用EntryOptionPlugin.applyEntryOption方法注册DynamicEntryPlugin或者EntryPluginclass EntryOptionPlugin { apply(compiler) { compiler.hooks.entryOption.tap("EntryOptionPlugin", (context, entry) => { // 调用静态方法 applyEntryOption EntryOptionPlugin.applyEntryOption(compiler, context, entry); return true; }); } static applyEntryOption(compiler, context, entry) { if (typeof entry === "function") { // 动态入口 const DynamicEntryPlugin = require("./DynamicEntryPlugin"); new DynamicEntryPlugin(context, entry).apply(compiler); } else { // 普通入口 const EntryPlugin = require("./EntryPlugin"); for (const name of Object.keys(entry)) { for (const entry of desc.import) { new EntryPlugin(context, entry, options).apply(compiler); } } } } }
-
EntryPlugin
- 订阅了compiler.hooks.compilation钩子,触发时设置EntryDependency的ModuleFactory normalModuleFactory工厂,这个用于创建入口模块
- 订阅compiler.hooks.make钩子,触发的时候调用compilation.addEntry方法,将入口模块加载到factorizeQueue队列,这样依赖就启动了以入口模块为七点的模块构建流程。
class EntryPlugin { constructor(context, entry, options) {} apply(compiler) { compiler.hooks.compilation.tap( "EntryPlugin", (compilation, { normalModuleFactory }) => { compilation.dependencyFactories.set( EntryDependency, normalModuleFactory ); } ); const { entry, options, context } = this; const dep = EntryPlugin.createDependency(entry, options); compiler.hooks.make.tapAsync("EntryPlugin", (compilation, callback) => { compilation.addEntry(context, dep, options, err => { callback(err); }); }); } }
-
EntryPlugin的触发
调用compiler.run() -> compiler.compile()方法触发compiler.hooks.make钩子,进而触发EntryPlugin钩子
class Compiler {
compile(callback) {
this.hooks.beforeCompile.callAsync(params, err => {
this.hooks.compile.call(params);
this.hooks.make.callAsync(compilation, err => {})
})
}
}
流程为: npm run build -> webpack -> webpack-cli -> compiler.run() -> compiler.compile() -> compiler.hooks.make.callAsync() -> EntryPlugin -> compilation.addEntry()
compilation.addEntry方法的讲解
方法参数
- context: 上下文目录,构建中就是当前目录的项目目录
- entry: 入口对象,结合EntryPlugin可以看到传入的路由,Entryplugin.createDependency方法返回值对象
- optionsOrName: 选项或者名字
- callback: entry的回调函数,用于和compiler通信进行后续的流程
class Compilation {
addEntry(context, entry, optionsOrName, callback) {
const options =
typeof optionsOrName === "object"
? optionsOrName
: { name: optionsOrName };
this._addEntryItem(context, entry, "dependencies", options, callback);
}
_addEntryItem(context, entry, target, options, callback) {}
}
方法逻辑
- 标准化处理options,根据optionsOrName格式化成不同的对象
- 调用compilation._addEntryItem()方法
compilation._addEntryItem
- context: webpack构建上下文目录,以及项目目录
- entry: 入口对象,上文中的EntryPlugin.createDependency()返回的EntryDependency类型的实例对象
- target: 目标类型,用于在entryData中分类类型进行缓存的标志
- options: webpack的配置对象或者是nameOptions对象,由compilation.addEntry标准化
- callback: 回调函数,用于和compiler进行通信使用
class Compilation {
_addEntryItem(context, entry, target, options, callback) {
// 根据options是否由name属性或者是compilation.entries或者是compilation.globalEntry中尝试获取缓存的入口entryData
const { name } = options;
let entryData =
name !== undefined ? this.entries.get(name) : this.globalEntry;
// 没有entryData的时候,会构建entryData对象,将其缓存到compilation.entries,另外entryData.dependency设置为初始的entry入口对象
if (entryData === undefined) {
entryData = {
dependencies: [],
includeDependencies: [],
options: {
name: undefined,
...options
}
};
entryData[target].push(entry);
this.entries.set(name, entryData);
} else {
// 这里不成立,先忽略
}
// 触发this.hooks.addEntry钩子
this.hooks.addEntry.call(entry, options);
// this.addModuleTree方法
this.addModuleTree(/* ... */);
}
}
callback回调 => _addEntryItem的回调
addEntry(context, entry, optionsOrName, callback) {
this._addEntryItem(context, entry, "dependencies", options, callback);
}
compilation.addModuleTree
- context: 上下文,当前项目的目录
- dependency: 依赖对象
- contextInfo: 上下文对象
class Compilation {
// ...
addModuleTree({ context, dependency, contextInfo }, callback) {
const Dep = dependency.constructor;
const moduleFactory = this.dependencyFactories.get(Dep);
this.handleModuleCreation(
{
factory: moduleFactory,
dependencies: [dependency],
originModule: null,
contextInfo,
context
},
(err, result) => {
if (err && this.bail) {
} else if (!err && result) {
callback(null, result);
} else {
callback();
}
}
);
}
}
执行模块以及其依赖的子模块的构建,构建工作