Preface

After webpack initialization is complete, it will pass through the options.watch to determine whether to open the watch, if open watch will be executed watch process, if it is run , will perform run process, focus only on the main line of this series, we directly from run start, watch interested students can study on their own research

compiler.run()

Look directly at the core code

const run = () => {
    this.hooks.beforeRun.callAsync(this, err => {
        if (err) return finalCallback(err);
        this.hooks.run.callAsync(this, err => {
            if (err) return finalCallback(err);
            this.readRecords(err => {
                if (err) return finalCallback(err);
                this.compile(onCompiled);
            });
        });
    });
};

To put it simply, it did just a few things.

  • Trigger the callback of beforeRun
  • Trigger the callback of run
  • Then adjust this.readRecords
  • In readRecords call a callback in this.compile(onCompiled) start the compilation

Let's see step by step
beforeRun before triggers in NodeEnvironmentPlugin registered in beforeRun hook, this plugin will determine inputFileSystem whether configured, if no configuration is performed purge clean-up methods.

readRecords reads some statistical information, because there is no configuration recordsInputPath , will here this.records initially {} .

Create a compilation instance

Then execute to the compiler.compiler() method.
compiler.compiler method runs through the entire compilation process. First, compiler instantiates a compilation .

compile(callback) {
    const params = this.newCompilationParams();
    this.hooks.beforeCompile.callAsync(params, err => {
        if (err) return callback(err);
        this.hooks.compile.call(params);
        const compilation = this.newCompilation(params);
        // do something
    }
}

Get parameters

newCompilationParams() {
    const params = {
        normalModuleFactory: this.createNormalModuleFactory(),
        contextModuleFactory: this.createContextModuleFactory()
    };
    return params;
}

There are two parameters, one is NormalModuleFactory example, one ContextModuleFactory instance. ContextModuleFactory in the compilation. I will skip it for the time being. Then I will make a break to see if I can walk in. Here we mainly look at NormalModuleFactory .

NormalModuleFactory

NormalModuleFactory look at the parameters of instantiating 0616982641093b

const normalModuleFactory = new NormalModuleFactory({
    context: this.options.context,
    fs: this.inputFileSystem,
    resolverFactory: this.resolverFactory,
    options: this.options.module,
    associatedObjectForCache: this.root,
    layers: this.options.experiments.layers
});

Pay attention to resolverFactory here, it will be used in the future.
Next, new NormalModuleFactory ’s look at what happened at 06169826410960

constructor({
    context,
    fs,
    resolverFactory,
    options,
    associatedObjectForCache,
    layers = false
}) {
    super();
    this.hooks = 定义了很多hooks
    this.resolverFactory = resolverFactory;
    this.ruleSet = ruleSetCompiler.compile([
            {
                rules: options.defaultRules
            },
            {
                rules: options.rules
            }
    ]);
    this.context = context || "";
    this.fs = fs;
    this._globalParserOptions = options.parser;
    this._globalGeneratorOptions = options.generator;
    /** @type {Map<string, WeakMap<Object, TODO>>} */
    this.parserCache = new Map();
    /** @type {Map<string, WeakMap<Object, Generator>>} */
    this.generatorCache = new Map();
    /** @type {Set<Module>} */
    this._restoredUnsafeCacheEntries = new Set();

    const cacheParseResource = parseResource.bindCache(
        associatedObjectForCache
    );
    this.hooks.factorize.tapAsync(
        // do something
    );
    this.hooks.resolve.tapAsync(
        // dosomething
    );
}

Maybe I think it’s too long to read, I’ll just translate it for everyone.

  • A lot of internal hooks are defined, such as the two reslover and factorize registered at the end
  • A lot of variables needed to build a module are defined, so I won't go into details here.
  • Two internal hooks of NormalModuleFactory are registered at the same time. Will be called by the compilation object at the right time

new NormalModuleFactory() after, triggering the Compiler normalModuleFactory hook

this.hooks.normalModuleFactory.call(normalModuleFactory);

Continue to trigger the hook callback

Then trigger the beforeCompile and compile hooks.

Start instantiating

newCompilation(params) {
    const compilation = this.createCompilation(params); //这里简单理解为new 了一下,
    compilation.name = this.name;
    compilation.records = this.records;
    this.hooks.thisCompilation.call(compilation, params);
    this.hooks.compilation.call(compilation, params);
    return compilation;
}

To classify it, this function does two things.

  • new Compilation, assign a little more value
  • Register two hooks

    new Compilation internal details

    The Compilation object represents the current module resources, compiled resources, changed files, and status information of the tracked dependencies, and represents the construction of a resource. There are too many constructor codes so I won't post it here, you can go and see by yourself.

To summarize briefly, it is

  • A lot of internal hooks are registered in compilation.
  • Initialized some of its own properties
  • Instantiate MainTemplate , ChunkTemplate , HotUpdateChunkTemplate , RuntimeTemplate , ModuleTemplate . Used to provide compiled templates

Hook call after instantiation

this.hooks.thisCompilation.call(compilation, params);
this.hooks.compilation.call(compilation, params);

compilation hook will call the method registered in entryplugin before.
Dependency modules will be added to dependencyFactories.

compilation.dependencyFactories.set(
        EntryDependency,
        normalModuleFactory
);
Maybe you are curious, why are there two hooks here? The reason is related to the sub-compiler. Create a child compiler in the createChildCompiler method of Compiler, where thisCompilation hook will not be copied, but compilation will be copied.
The sub-compiler has a complete module and chunk generation. Through the sub-compiler, a core build process can be executed independently of the parent compiler, and some required modules and chunks can be additionally generated.

Finish

So far, the description of the process of building objects compiler objects and describes the compilation process compilation object has been created. In the next article we enter the build process.


csywweb
232 声望8 粉丝

最担心的事不是写出ipcode,而是从不开始