webpack源码分析(六)

这一章我们先给一个demo,从demo的视角讲解,new WebpackOptionsApply().process(options, compiler);都发生了什么。

先上demo

首先第一步,把webpack源码clone下来, git clone https://github.com/webpack/webpack.git

然后执行yarn,把npm包下载下来,然后mkdir demo 创建一个demo文件夹,文件夹内部创建一个webpack.js文本就是下方的内容

var path = require("path");
var webpack = require("../lib/index").webpack;
const config = {
	// mode: "development" || "production",
	entry: {
		main: "./example"
	},
	output: {
		path: path.join(__dirname, "dist"),
		filename: "[name].chunkhash.js"
	}
};


webpack(config,(err,stats)=>{
    console.log(err,stats)
})

然后node inspect webpack.js,然后打开浏览器f12,发现有一个node的小点(绿色的),然后点击开来,我们就可以调试了。

为什么我要讲解这里呢,还要写一个demo呢,因为不同的配置,对应的插件不一样,我不可能细到所有的都说出来,只能尽可能的全。

回到 new WebpackOptionsApply().process(options, compiler);

我们先看这两个参数,一个option,一个compiler,option是我们传入,然后经过webpack的两个方法处理过的值,compiler就是我们new compiler编译对象。

这块代码太多了,我就不讲了,后续用到,触发这个plugin(后续用到我在讲),我们说一下他做了哪些处理,1.绑定plguin事件

绑定了非常多的事件,2. 触发了几个事件

我们讲一下触发的事件

compiler.hooks.entryOption.call(options.context, options.entry);

compiler.hooks.afterPlugins.call(compiler);

compiler.hooks.afterResolvers.call(compiler);

entryOption

webpack 一共有两个钩子会触发这个事件,一个是EntryOptionPlugin,一个是DLLPlugin,第二个是webpack5中已经没人用了,他的作用是静态资源链接,打包一次,之后就不用在打包了,既然已经不是主流了,vue,react的脚手架都放弃了,那我们就不讨论了。

那我们就看EntryOptionPlugin

	apply(compiler) {
		// 注册entryOption
		compiler.hooks.entryOption.tap("EntryOptionPlugin", (context, entry) => {
			EntryOptionPlugin.applyEntryOption(compiler, context, entry);
			return true;
		});
	}

EntryOptionPlugin.applyEntryOption(compiler, context, entry);

他就执行了这个,那我们看这个方法

	static applyEntryOption(compiler, context, entry) {
		if (typeof entry === "function") {
			const DynamicEntryPlugin = require("./DynamicEntryPlugin");
			new DynamicEntryPlugin(context, entry).apply(compiler);
		} else {
			const EntryPlugin = require("./EntryPlugin");
			// {main:{import:['./example']}}
			for (const name of Object.keys(entry)) {
				// {import:['./example']}
				const desc = entry[name];
				// name :main
				const options = EntryOptionPlugin.entryDescriptionToOptions(
					compiler,
					name,
					desc
				);
				for (const entry of desc.import) {
					// context  entry:'./example' options:{name:'main'}
					new EntryPlugin(context, entry, options).apply(compiler);
				}
			}
		}
	}

这段代码的关键就是EntryPlugin

	apply(compiler) {
		// 给compilation 增加 dependencyFactories
		compiler.hooks.compilation.tap(
			"EntryPlugin",
			(compilation, { normalModuleFactory }) => {
				compilation.dependencyFactories.set(
					EntryDependency,
					normalModuleFactory
				);
			}
		);

		const { entry, options, context } = this;
		const dep = EntryPlugin.createDependency(entry, options);
		// 增加 make
		compiler.hooks.make.tapAsync("EntryPlugin", (compilation, callback) => {
			compilation.addEntry(context, dep, options, err => {
				callback(err);
			});
		});
	}

	static createDependency(entry, options) {
		const dep = new EntryDependency(entry);
		// TODO webpack 6 remove string option
		dep.loc = { name: typeof options === "object" ? options.name : options };
		return dep;
	}

给 compilation.dependencyFactories set(EntryDependency, normalModuleFactory) 给一个map增加一个属性,这个normalModuleFactory挺关键,现在不讲,后续会抽一节讲

然后,创建一个dep,const dep = EntryPlugin.createDependency(entry, options); 注意 就是这个dep new EntryDependency,所以dep.constructor === EntryDependency,所以compilation.dependencyFactories.get(dep.construtor) ===normalModuleFactory 后续有用

所以entryOption就是给make钩子增加一个事件,事件执行,compilation.addEntry方法

afterPlugins

ModuleFederationPlugin模块联邦,默认也没有用,就先不讲了

afterResolvers

没有方法,就不说这个钩子了

回顾一下,WebpackOptionsApply().process,做了什么?

  1. 注册插件
  2. 执行三个函数

前端技术专栏分享 文章被收录于专栏

1. 包含常规前端面试题解析,和源码分析 2. 从0-1深入浅出理解前端相关技术栈

全部评论

相关推荐

安静的仰泳鲈鱼sp到手了:你这比赛获奖和实习,跟你的技术栈有半点关系吗😮
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务