2

Preface

As mentioned above, webpack prepared the parameters, and it is time to create the compiler object.
After creation, it will execute compiler.run to start compiling. This article will explain the process from new Compiler to compiler.run()
The whole process takes place in the function body createCompiler

/**
 * @param {WebpackOptions} rawOptions options object
 * @returns {Compiler} a compiler
 */
const createCompiler = rawOptions => {

new Compiler

  • Before new, webpack will complete the initialization of the basic parameters, here only the log output format and context are assigned.

    applyWebpackOptionsBaseDefaults(options);
  • webpack/lib/Compiler.js is the core process of compiling the entire webpack.
  • new Compiler , first register a bunch of hooks Tapable watch-run , run , before-run , and so on. More hooks can be here at .

Initialization file operation

new NodeEnvironmentPlugin({
    infrastructureLogging: options.infrastructureLogging
}).apply(compiler);

Here is the expansion of the compiler object, adding some operations on the file, such as input, output, monitoring, caching and other methods. At the same time, a callback for the beforeRun

apply(compiler) {
        const { infrastructureLogging } = this.options;
        compiler.infrastructureLogger = createConsoleLogger({
            level: infrastructureLogging.level || "info",
            debug: infrastructureLogging.debug || false,
            console:
                infrastructureLogging.console ||
                nodeConsole({
                    colors: infrastructureLogging.colors,
                    appendOnly: infrastructureLogging.appendOnly,
                    stream: infrastructureLogging.stream
                })
        });
        compiler.inputFileSystem = new CachedInputFileSystem(fs, 60000);
        const inputFileSystem = compiler.inputFileSystem;
        compiler.outputFileSystem = fs;
        compiler.intermediateFileSystem = fs;
        compiler.watchFileSystem = new NodeWatchFileSystem(
            compiler.inputFileSystem
        );
        compiler.hooks.beforeRun.tap("NodeEnvironmentPlugin", compiler => {
            if (compiler.inputFileSystem === inputFileSystem) {
                compiler.fsStartTime = Date.now();
                inputFileSystem.purge();
            }
        });
    }
The fs here is not the file system of nodejs, it uses a third-party package graceful-fs

Register the plugin

if (Array.isArray(options.plugins)) {
    for (const plugin of options.plugins) {
        if (typeof plugin === "function") {
            plugin.call(compiler, compiler);
        } else {
            plugin.apply(compiler);
        }
    }
}

Next, webpack will register all plug-ins registered by options. compiler object to the plug-in for internal use. The plug-in can register the hook's callback function in the entire compilation process compiler At the same time, some compiler hooks pass in the compilation compilation hook callback can be registered when the resource is constructed.

How to write a webpack plugin

environment ready

After the plug-in is registered, webpack assigns default parameters to options again. Why is it with the previous applyWebpackOptionsBaseDefaults ?
Called here

applyWebpackOptionsDefaults(options);

Added another wave of default values.
After the addition, the two hooks environment and afterEnvironment

compiler.hooks.environment.call();
compiler.hooks.afterEnvironment.call();

Register the built-in plugin

After the environment is initialized, webpack also needs to execute its own internal default plugin.

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

Here, the corresponding plug-in will be executed according to your configuration.
Pick a few things that have something to do with hooks,

Parse entry

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

Here is the entry data structure needed to generate the build

/** @type {EntryOptions} */
        const options = {
            name,
            filename: desc.filename,
            runtime: desc.runtime,
            layer: desc.layer,
            dependOn: desc.dependOn,
            publicPath: desc.publicPath,
            chunkLoading: desc.chunkLoading,
            wasmLoading: desc.wasmLoading,
            library: desc.library
        };

Then call EntryPlugin to register the Compiler.hooks:compilation, make hook functions in the applay In the future, when the make hook is compiler object, the callback registered EntryPlugin complition.addEntry(context, dep, options) start compilation
This is the key point, otherwise the entrance to the beginning cannot be found

compiler.hooks.make.tapAsync("EntryPlugin", (compilation, callback) =>        {
        compilation.addEntry(context, dep, options, err => {
            callback(err);
        });
    }
);

Register the resloverFactory hook

After some of the plugins of webpack itself are called, the hook afterPlugin

compiler.hooks.afterPlugins.call(compiler);

Next, webpack registered the resolveOptions hook on compiler.resolverFactory

compiler.resolverFactory.hooks.resolveOptions
    .for("normal")
    .tap("WebpackOptionsApply", resolveOptions => {
        resolveOptions = cleverMerge(options.resolve, resolveOptions);
        resolveOptions.fileSystem = compiler.inputFileSystem;
        return resolveOptions;
});
compiler.resolverFactory.hooks.resolveOptions
    .for("context")
    .tap("WebpackOptionsApply", resolveOptions => {
        resolveOptions = cleverMerge(options.resolve, resolveOptions);
        resolveOptions.fileSystem = compiler.inputFileSystem;
        resolveOptions.resolveToContext = true;
        return resolveOptions;
    });
compiler.resolverFactory.hooks.resolveOptions
        .for("loader")
        .tap("WebpackOptionsApply", resolveOptions => {
            resolveOptions = cleverMerge(options.resolveLoader, resolveOptions);
                resolveOptions.fileSystem = compiler.inputFileSystem;
                return resolveOptions;
        });

The purpose here is to Factory.createResolver (containing the relevant resolve project configuration items).
Then call the afterResolvers hook

compiler.hooks.afterResolvers.call(compiler);

loading finished

So far, there are enough things on the compiler object to start our compilation, and we will tell the outside world that the initialization is complete. With the tonality of webpack, there must be a hook trigger.

compiler.hooks.initialize.call();

Concluding remarks

All the things before webpack compilation have been explained clearly, the next article will start the compilation.
Please note the registration of various hooks mentioned in the article. In the subsequent compilation process, some of the hooks registered before will often be triggered in the places you missed. This is also a pain point in the process of debugging webpack.


csywweb
232 声望8 粉丝

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