Front End

[FE] webpack v4.20.2 源码解析(三):插件的

2018-10-17  本文已影响1人  何幻

下面我们来介绍下webpack plugin的写法,顺便回答上一篇 this.hooks.make.callAsync的调用问题。

(1)test-plugin.js
在工程目录中,我们新建test-plugin.js文件,

module.exports = class TestPlugin {
    apply(compiler) {
        compiler.hooks.make.tapAsync('TestPlugin', (compilation, callback) => {
            compilation.hooks.buildModule.tap('TestPlugin', module => {
                console.log('module.resource', module.resource);
                console.log('module.loaders', module.loaders);
                console.time('TestPlugin');
            });

            compilation.hooks.succeedModule.tap('TestPlugin', module => {
                console.timeEnd('TestPlugin');
            });

            callback();
        });
    }
};

它导出了一个包含apply方法的类。

(2)webpack.config.js中使用该plugin

const path = require('path');
const TestPlugin = require('./test-plugin');

module.exports = {
    entry: {
        index: path.resolve(__dirname, 'src/index.js'),
    },
    output: {
        path: path.resolve(__dirname, 'dist/'),
    },
    module: {
        rules: [
            { test: /\.js$/, use: { loader: 'babel-loader', query: { presets: ['@babel/preset-env'] } } },
        ]
    },
    plugins:[
        new TestPlugin(),
    ],
};

我们在webpack.config.js中,引入了test-plugin模块,
然后为导出对象增加了plugins属性。

(3)执行结果

module.resource ~/Test/debug-webpack/src/index.js
module.loaders [ { options: { presets: [Array] },
    ident: 'ref--4',
    loader: '~/Test/debug-webpack/node_modules/_babel-loader@8.0.4@babel-loader/lib/index.js' } ]
TestPlugin: 213.301ms

我们使用test-plugin实现了监控,它能统计出文件的build时间。

其中,
compiler.hooks.make,在源代码webpack/lib/Compiler.js 第536行被调用,

this.hooks.make.callAsync(compilation, err => {
    ...
});

compilation.hooks.buildModule,在源代码webpack/lib/Compilation.js 第617行被调用,

this.hooks.buildModule.call(module);

compilation.hooks.succeedModule,在源代码webpack/lib/Compilation.js 第652行被调用,

this.hooks.succeedModule.call(module);

注:
hooks为CompilerCompilation对象实现了切面能力,
其中,CompilerCompilation都是Tapable类的子类。
Tapable是一个单独的库,位于github: tapable

hooks有很多不同的种类,不同种类的hooks实现与调用方式一一对应。
例如,compiler.hooks.make是一种AsyncParallelHook,源码位于Compiler.js 第73行

make: new AsyncParallelHook(["compilation"]),

实现方法如下,

compiler.hooks.make.tapAsync('TestPlugin', (compilation, callback) => {
    ...
    callback();    // 这里不用return而是用callback返回
});

而调用方式是,

this.hooks.make.callAsync(compilation, err => {
    ...
});

其中,make.tapAsyncmake.callAsync相对应。

又例如,compilation.hooks.buildModule是一种SyncHook,源码位于Compilation.js 第211行

buildModule: new SyncHook(["module"]),

实现方法如下,

compilation.hooks.buildModule.tap('TestPlugin', module => {
    ...
});

而调用方式是,

this.hooks.buildModule.call(module);

其中,hooks.buildModule.taphooks.buildModule.call相对应。


上文中我们提到了loader-runner是一个递归加载文件的过程,
下面我们改变一下src/index.js,增加一个src/a.js,
然后看下日志。

(1)src/index.js

import a from './a'; alert(1);

(2)src/a.js

alert(2);

(3)日志

debug-webpack webpack webpack.js cliPath: ~/.nvm/versions/node/v8.12.0/lib/node_modules/webpack-cli/bin/cli.js +0ms

debug-webpack webpack-cli cli.js start: compiler.run +0ms

debug-webpack webpack Compiler.js start: this.hooks.make.callAsync +0ms
debug-webpack webpack SingleEntryPlugin.js in: compiler.hooks.make.tapAsync +0ms
debug-webpack webpack SingleEntryPlugin.js start: compilation.addEntry +0ms
debug-webpack webpack Compilation.js in: addEntry +0ms
debug-webpack webpack Compilation.js start: this._addModuleChain +0ms
debug-webpack webpack Compilation.js in: _addModuleChain +0ms
debug-webpack webpack Compilation.js start: moduleFactory.create +0ms
debug-webpack webpack Compilation.js end: moduleFactory.create +39ms
debug-webpack webpack Compilation.js module.resource: ~/Test/debug-webpack/src/index.js +0ms
debug-webpack webpack Compilation.js module.loaders: [{"options":{"presets":["@babel/preset-env"]},"ident":"ref--4","loader":"~/Test/debug-webpack/node_modules/_babel-loader@8.0.4@babel-loader/lib/index.js"}] +0ms
debug-webpack webpack Compilation.js start: this.buildModule +1ms
debug-webpack webpack Compilation.js in: buildModule +0ms
debug-webpack webpack Compilation.js start: module.build +0ms
debug-webpack webpack NormalModule.js in: build +0ms
debug-webpack webpack NormalModule.js start: this.doBuild +0ms
debug-webpack webpack NormalModule.js in: doBuild +1ms
debug-webpack webpack NormalModule.js start: runLoaders +0ms

debug-webpack loader-runner LoaderRunner.js in: runLoaders +0ms
debug-webpack loader-runner LoaderRunner.js start: iteratePitchingLoaders +1ms
debug-webpack loader-runner LoaderRunner.js in: iteratePitchingLoaders +0ms
debug-webpack loader-runner LoaderRunner.js start: loadLoader +0ms
debug-webpack loader-runner loadLoader.js in: loadLoader +0ms
debug-webpack loader-runner loadLoader.js loader.path: ~/Test/debug-webpack/node_modules/_babel-loader@8.0.4@babel-loader/lib/index.js +0ms
debug-webpack loader-runner LoaderRunner.js end: loadLoader +38ms
debug-webpack loader-runner LoaderRunner.js start: 1. iteratePitchingLoaders +0ms
debug-webpack loader-runner LoaderRunner.js in: iteratePitchingLoaders +0ms
debug-webpack loader-runner LoaderRunner.js start: 2. iteratePitchingLoaders +0ms
debug-webpack loader-runner LoaderRunner.js in: iteratePitchingLoaders +0ms
debug-webpack loader-runner LoaderRunner.js start: processResource +0ms
debug-webpack loader-runner LoaderRunner.js in: processResource +0ms
debug-webpack loader-runner LoaderRunner.js start: iterateNormalLoaders +0ms
debug-webpack loader-runner LoaderRunner.js in: iterateNormalLoaders +1ms
debug-webpack loader-runner LoaderRunner.js start: runSyncOrAsync +0ms
debug-webpack loader-runner LoaderRunner.js in: runSyncOrAsync +0ms
debug-webpack loader-runner LoaderRunner.js start: LOADER_EXECUTION +0ms
debug-webpack loader-runner LoaderRunner.js in: async +0ms

debug-webpack babel-loader index.js in: loader +0ms
debug-webpack babel-loader index.js this.resourcePath: ~/Test/debug-webpack/src/index.js +1ms
debug-webpack babel-loader index.js start: transform +112ms
debug-webpack babel-loader index.js source: import a from './a'; alert(1); +1ms
debug-webpack babel-loader index.js end: transform +72ms
debug-webpack babel-loader index.js result: {"ast":null,"code":"import a from './a';\nalert(1);","map":null,"metadata":{},"sourceType":"module"} +0ms

debug-webpack loader-runner LoaderRunner.js in: innerCallback +187ms
debug-webpack loader-runner LoaderRunner.js end: LOADER_EXECUTION +0ms
debug-webpack loader-runner LoaderRunner.js end: runSyncOrAsync +0ms
debug-webpack loader-runner LoaderRunner.js start: 1. iterateNormalLoaders +0ms
debug-webpack loader-runner LoaderRunner.js in: iterateNormalLoaders +0ms
debug-webpack loader-runner LoaderRunner.js start: 2. iterateNormalLoaders +0ms
debug-webpack loader-runner LoaderRunner.js in: iterateNormalLoaders +0ms
debug-webpack loader-runner LoaderRunner.js end: iteratePitchingLoaders +0ms

debug-webpack webpack NormalModule.js end: runLoaders +228ms
debug-webpack webpack NormalModule.js end: this.doBuild +0ms
debug-webpack webpack Compilation.js end: module.build +237ms
debug-webpack webpack Compilation.js end: this.buildModule +0ms
debug-webpack webpack Compilation.js in: buildModule +43ms
debug-webpack webpack Compilation.js start: module.build +0ms
debug-webpack webpack NormalModule.js in: build +51ms
debug-webpack webpack NormalModule.js start: this.doBuild +0ms
debug-webpack webpack NormalModule.js in: doBuild +0ms
debug-webpack webpack NormalModule.js start: runLoaders +0ms

debug-webpack loader-runner LoaderRunner.js in: runLoaders +52ms
debug-webpack loader-runner LoaderRunner.js start: iteratePitchingLoaders +0ms
debug-webpack loader-runner LoaderRunner.js in: iteratePitchingLoaders +0ms
debug-webpack loader-runner LoaderRunner.js start: loadLoader +0ms
debug-webpack loader-runner loadLoader.js in: loadLoader +278ms
debug-webpack loader-runner loadLoader.js loader.path: ~/Test/debug-webpack/node_modules/_babel-loader@8.0.4@babel-loader/lib/index.js +0ms
debug-webpack loader-runner LoaderRunner.js end: loadLoader +0ms
debug-webpack loader-runner LoaderRunner.js start: 1. iteratePitchingLoaders +1ms
debug-webpack loader-runner LoaderRunner.js in: iteratePitchingLoaders +0ms
debug-webpack loader-runner LoaderRunner.js start: 2. iteratePitchingLoaders +0ms
debug-webpack loader-runner LoaderRunner.js in: iteratePitchingLoaders +0ms
debug-webpack loader-runner LoaderRunner.js start: processResource +0ms
debug-webpack loader-runner LoaderRunner.js in: processResource +0ms
debug-webpack loader-runner LoaderRunner.js start: iterateNormalLoaders +0ms
debug-webpack loader-runner LoaderRunner.js in: iterateNormalLoaders +0ms
debug-webpack loader-runner LoaderRunner.js start: runSyncOrAsync +0ms
debug-webpack loader-runner LoaderRunner.js in: runSyncOrAsync +0ms
debug-webpack loader-runner LoaderRunner.js start: LOADER_EXECUTION +0ms
debug-webpack loader-runner LoaderRunner.js in: async +0ms

debug-webpack babel-loader index.js in: loader +53ms
debug-webpack babel-loader index.js this.resourcePath: ~/Test/debug-webpack/src/a.js +0ms
debug-webpack babel-loader index.js start: transform +0ms
debug-webpack babel-loader index.js source: alert(2); +0ms
debug-webpack babel-loader index.js end: transform +3ms
debug-webpack babel-loader index.js result: {"ast":null,"code":"alert(2);","map":null,"metadata":{},"sourceType":"module"} +0ms

debug-webpack loader-runner LoaderRunner.js in: innerCallback +3ms
debug-webpack loader-runner LoaderRunner.js end: LOADER_EXECUTION +0ms
debug-webpack loader-runner LoaderRunner.js end: runSyncOrAsync +0ms
debug-webpack loader-runner LoaderRunner.js start: 1. iterateNormalLoaders +0ms
debug-webpack loader-runner LoaderRunner.js in: iterateNormalLoaders +0ms
debug-webpack loader-runner LoaderRunner.js start: 2. iterateNormalLoaders +0ms
debug-webpack loader-runner LoaderRunner.js in: iterateNormalLoaders +0ms
debug-webpack loader-runner LoaderRunner.js end: iteratePitchingLoaders +0ms

debug-webpack webpack NormalModule.js end: runLoaders +4ms
debug-webpack webpack NormalModule.js end: this.doBuild +0ms
debug-webpack webpack Compilation.js end: module.build +5ms
debug-webpack webpack Compilation.js end: this._addModuleChain +1ms
debug-webpack webpack Compiler.js end: this.hooks.make.callAsync +327ms

(4)插件的日志

module.resource ~/Test/debug-webpack/src/index.js
module.loaders [ { options: { presets: [Array] },
    ident: 'ref--4',
    loader: '~/Test/debug-webpack/node_modules/_babel-loader@8.0.4@babel-loader/lib/index.js' } ]
TestPlugin: 353.712ms
module.resource ~/Test/debug-webpack/src/a.js
module.loaders [ { options: { presets: [Array] },
    ident: 'ref--4',
    loader: '~/Test/debug-webpack/node_modules/_babel-loader@8.0.4@babel-loader/lib/index.js' } ]
TestPlugin: 3.883ms
上一篇 下一篇

猜你喜欢

热点阅读