欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 文化 > webpack源码解析---addEntry

webpack源码解析---addEntry

2024/10/24 19:13:43 来源:https://blog.csdn.net/m0_73280507/article/details/140108172  浏览:    关键词:webpack源码解析---addEntry

addEntry

EntryPlugin的注册

webpack会从入口开始解析依赖。

  1. WebpackOptionsApply

    new WebpackOptionsApply().process(compiler, options);
    class WebpackOptionsApply {constructor () {}process () {// 注册 EntryOptionPlugin new EntryOptionPlugin().apply(compiler);}
    }
    
  2. EntryOptionPlugin
    EntryOptionPlugin的作用是注册compiler.hooks.entryOption钩子,当钩子被触发的时候,调用EntryOptionPlugin.applyEntryOption方法注册DynamicEntryPlugin或者EntryPlugin

    class EntryOptionPlugin {apply(compiler) {compiler.hooks.entryOption.tap("EntryOptionPlugin", (context, entry) => {// 调用静态方法 applyEntryOptionEntryOptionPlugin.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);}}}}
    }
    
  3. 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);});});}
    }
    
  4. 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方法的讲解

方法参数

  1. context: 上下文目录,构建中就是当前目录的项目目录
  2. entry: 入口对象,结合EntryPlugin可以看到传入的路由,Entryplugin.createDependency方法返回值对象
  3. optionsOrName: 选项或者名字
  4. 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) {}
}

方法逻辑

  1. 标准化处理options,根据optionsOrName格式化成不同的对象
  2. 调用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中尝试获取缓存的入口entryDataconst { 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();}});}
}

执行模块以及其依赖的子模块的构建,构建工作

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com