webpack源码分析(八)
先看上一节的_create函数
_create(type, resolveOptionsWithDepType) { const originalResolveOptions = { ...resolveOptionsWithDepType }; const resolveOptions = convertToResolveOptions( this.hooks.resolveOptions.for(type).call(resolveOptionsWithDepType) ); const resolver = Factory.createResolver(resolveOptions) const childCache = new WeakMap(); resolver.withOptions = options => { const cacheEntry = childCache.get(options); if (cacheEntry !== undefined) return cacheEntry; const mergedOptions = cachedCleverMerge(originalResolveOptions, options); const resolver = this.get(type, mergedOptions); childCache.set(options, resolver); return resolver; }; this.hooks.resolver.for(type).call(resolver, resolveOptions,originalResolveOptions); return resolver; }
先来一行一行过,第一行直接跳过,{...object}
看第二行
this.hooks.resolveOptions.for(type).call(resolveOptionsWithDepType)
其实这就是调用了方法
在之前我们说的WebpackOptionsApply.process()这个方法赋值了几个钩子函数
先说一下,一共赋值了3个钩子,normal,context,loader,先不说这三种都是干什么的,因为说了大概率现在也不懂,后续会用到,自然就懂了。
这里说一下normal的吧,三个其实都差不多,说一个就阔以了。
compiler.resolverFactory.hooks.resolveOptions
.for("normal")
.tap("WebpackOptionsApply", resolveOptions => {
resolveOptions = cleverMerge(options.resolve, resolveOptions);
resolveOptions.fileSystem = compiler.inputFileSystem;
return resolveOptions;
});
其实就是,获取resolveOption的值而已
const resolver = Factory.createResolver(resolveOptions)
const Factory = require("enhanced-resolve").ResolverFactory;
const resolver = Factory.createResolver(resolveOptions);
先跳过这个,先把最简单的代码讲了
const childCache = new WeakMap();
resolver.withOptions = options => {
const cacheEntry = childCache.get(options);
if (cacheEntry !== undefined) return cacheEntry;
const mergedOptions = cachedCleverMerge(originalResolveOptions, options);
const resolver = this.get(type, mergedOptions);
childCache.set(options, resolver);
return resolver;
};
一看就知道了,其实就是在resolver对象上面增加_create方法,这样就可以通过resolver,定义不同配置的新的resolver对象。
this.hooks.resolver.for(type).call(resolver, resolveOptions, originalResolveOptions);
这个插件会被调用,webpack有个插件叫做,ResolverCachePlugin看名字就知道是干什么的,肯定是增加缓存的。
这个插件我就说一下是干啥用的吧,不多介绍了,他在resolver阶段,注册了resolver.hooks.resolve.tapAsync,注册了别的生命周期的插件,并且优先级是最低的,保证是最后执行的。(这里用不到,如果后续用到,就会讲,现在就是在他的钩子里注册别人的钩子没必要讲)
回归正题
所以我上一节说的核心就是const resolver = Factory.createResolver(resolveOptions),现在看没一点问题。
const Factory = require("enhanced-resolve").ResolverFactory;
const resolver = Factory.createResolver(resolveOptions);
enhanced-resolve 一个非常熟悉的东西,我们之前的CachedInputFileSystem就是内部的。
那我们来说一下这个ResolverFactory
我们先来举例一个demo吧。
const { ResolverFactory, CachedInputFileSystem } = require("enhanced-resolve");
const fs = require("fs");
const path = require("path");
const myResolver = ResolverFactory.createResolver({
fileSystem: new CachedInputFileSystem(fs, 4000),
extensions: [".json", ".js", ".ts"]
});
const context = {};
const resolveContext = {};
const lookupStartPath = path.resolve(__dirname);
const request = "./a";
myResolver.resolve( context, lookupStartPath, request, resolveContext,
(err, path, result) => { console.log("createResolve path: ", path); }
);
我们只需要在同级创建一个a.js即可,不需要输入内容。
➜ node xx.js
最后会输出createResolve path: xxxx/a.js
通过这个demo,我们就知道了,原来 ResolverFactory,和名字一样,就是实现一个resolve功能。
这节就讲到这里,本章知道了ResolverFactory是什么,并给了一个demo,可以拿到绝对路径
1. 包含常规前端面试题解析,和源码分析 2. 从0-1深入浅出理解前端相关技术栈