Preface
He said we got the factory, and other critical data and rely build modlule by addModuleTree through the above factorizeQueue
control come factory.create
. This time began the reslove process.
This article mainly analyzes the internal beforeResolve
of factorize
, resolve
, afterResolve
NormalModuleFactory
inside 0617551da42a2f.
Configuration file
The configuration files surrounding this article are as follows:
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.(js?|tsx?|ts?)$/,
use: [
{
loader: 'babel-loader',
},
],
},
]
},
resolve: {
extensions: ['.js', '.ts'],
alias: {
demo: path.resolve(__dirname, 'src/second'),
},
},
};
factory.create
The entrance starts at factory.create
, where factory
is the addModuleTree
obtained NormalModuleFactory
NormalModuleFactory
first triggered its internal beforeResolve
, and then executed the hook function factorize
factorize
within the hook and there are calls resolve
.
It looks rather convoluted here, just explain it briefly:
The calling sequence of the hooks is like this.beforeResolve
-> factorize
-> resolve
- beforeResolve I didn’t find the place I registered before. It seems that I didn’t do anything, or I didn’t find it.
- factorize has been
ExternalModuleFactoryPlugin
plugin before, and the informationexternal
resolve
hook is registered insideNormalModuleFactory
and is used to parse this module and generate the corresponding loader and dependency information. The focus here is onresolve
resolve
getLoaderResolver
In the first step, the resolve
hook first calls this.getResolver("loader")
to return to the loaderResolver, which can be understood as a method to resolve the loader.
Simply divided into the following steps:
- Calls to the
ResolverFactory
in theget
method - Determine whether there is a corresponding type of cache
- Created
resolveOptions
, - Call
require("enhanced-resolve").ResolverFactory
create aresolver
, and then return toNormalModuleFactory
to continue executing the code.
const loaderResolver = this.getResolver("loader");
loaderResolver
exposes a resolver
method for parsing loader
.
normalResolver
Then go down, skip some judgment, walked directly defaultResolve
this method here will be based on webpack profile resolve
option to generate a normalResolver
. Similarly, this normalResolver
is also require("enhanced-resolve").ResolverFactory
, which also exposes a resolve
method.
const normalResolver = this.getResolver(
"normal",
dependencyType
? cachedSetProperty(
resolveOptions || EMPTY_RESOLVE_OPTIONS,
"dependencyType",
dependencyType
)
: resolveOptions
);
Next, the normalResolver
and some context information will be passed to the resolveResource
method, which will eventually call node_modules/enhanced-resolve/lib/Resolver.js
of doResolve
.
this.resolveResource(
contextInfo,
context,
unresolvedResource,
normalResolver,
resolveContext,
(err, resolvedResource, resolvedResourceResolveData) => {
if (err) return continueCallback(err);
if (resolvedResource !== false) {
resourceData = {
resource: resolvedResource,
data: resolvedResourceResolveData,
...cacheParseResource(resolvedResource)
};
}
continueCallback();
}
);
Then according to doResolve
returned resolvedResource
and resolvedResourceResolveData
assembled together into resourceData
. We will use this in the subsequent parsing of the loader.
resourceData
data structure
Parsing loader
Continue execution in the callback of resolvedResource
const result = this.ruleSet.exec({
resource: resourceDataForRules.path,
realResource: resourceData.path,
resourceQuery: resourceDataForRules.query,
resourceFragment: resourceDataForRules.fragment,
scheme,
assertions,
mimetype: matchResourceData
? ""
: resourceData.data.mimetype || "",
dependency: dependencyType,
descriptionData: matchResourceData
? undefined
: resourceData.data.descriptionFileData,
issuer: contextInfo.issuer,
compiler: contextInfo.compiler,
issuerLayer: contextInfo.issuerLayer || ""
});
Here we will get the required loader rules
in the configuration file. In result
is
This will be followed by result
traversing generate useLoadersPost
, useLoaders
, useLoadersPre
.
Then call resolveRequestArray
get postLoaders, normalLoaders, preLoaders
.
this.resolveRequestArray(
contextInfo,
this.context,
useLoaders,
loaderResolver,
resolveContext,
(err, result) => {
normalLoaders = result;
continueCallback(err);
}
);
The current example does not have postLoaders
and preLoaders
, here only normalLoaders
. resolveRequestArray
internally calls loaderResolver.resolve
parse useLoaders
, and the final result is to result
with the corresponding real file address.
{
ident:undefined
loader:'/Users/csy/Code/webpack5/node_modules/babel-loader/lib/index.js'
options:undefined
}
Generate callback data
Finally, the data that has been generated under the processing of continueCallback
, the first is the merging loader
postLoaders, normalLoaders, preLoaders
these 0617551da430fa. Then assign
click data.createData
, this data
comes from the data passed in by the hook entry.
Object.assign(data.createData, {
layer:
layer === undefined ? contextInfo.issuerLayer || null : layer,
request: stringifyLoadersAndResource(
allLoaders,
resourceData.resource
),
userRequest,
rawRequest: request,
loaders: allLoaders,
resource: resourceData.resource,
context:
resourceData.context || getContext(resourceData.resource),
matchResource: matchResourceData
? matchResourceData.resource
: undefined,
resourceResolveData: resourceData.data,
settings,
type,
parser: this.getParser(type, settings.parser),
parserOptions: settings.parser,
generator: this.getGenerator(type, settings.generator),
generatorOptions: settings.generator,
resolveOptions
});
Here I will focus on getParser
and getGenerator
. These two methods return the parser of the corresponding file and the method of constructing the template. According to the current example, JavascriptParser
and JavascriptGenerator
.
Then this createData
will be used for createModule
.
In the complete execution NormalModuleFactory
of afterResolve
after hook
const createData = resolveData.createData;
this.hooks.createModule.callAsync(//something)
reslove is over, and the next step is about to start, create module
!
summary
- The module resolve process is used to obtain information such as the absolute path of each loader and module.
- In the
resolver
hook, first obtainloaderResolver
through enhanced-resolve and provide the resolve method - In the
defaultResolve
method, getnormalResolver
and provide the resolve method. - Parse
unresolvedResource
to get the absolute path of the file and other information - Get loader according to
rules
- Use
loaderResolver
get the absolute path of the loader and other information - Merging loader, splicing data,
- Call
NormalModuleFactory
ofafterResolve
hook, endingresolve
process.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。