SunShinewyf/webpack-demo

webpack中的插件以及如何编写一个插件

SunShinewyf opened this issue · 0 comments

webpack中的插件

webpack中的插件主要是为webpack添加功能的,webpack中的每个插件都会在webpack启动时被安装一次,webpack主要是通过调用插件的apply方法来安装它们,插件可以完成更多loader不能完成的功能。
插件的使用一般是在webpack的配置信息plugins选项中指定。下面是一个简单的使用webpack插件的配置代码:

const webpack = require('webpack');
const extractTextPlugin = require('extract-text-webpack-plugin');
const WebpackMd5Hash = require('webpack-md5-hash')

module.exports = {
    entry: {
        'a': './a',
        'b': './b'
    },

    output:{
        filename:'[name]-[chunkhash].js'
    },
    module: {
        loaders: [
            {
                test: /\.css$/,
                loader: extractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader' })
            },
            {
                test:  /\.(png|jpg)$/,
                loader:'url-loader?limit=1000&name=images/[name].[hash].[ext]'
            }
        ],
    },
    plugins: [
        new extractTextPlugin('[name].[contenthash:4].css'),
        new WebpackMd5Hash()
    ],
}

如上面的配置信息所示,该配置文件使用了extractTextpluginWebpackMd5Hash这两个插件。关于webpack的更多插件信息可以移步这里.

怎么样编写一个插件

关于如何开发一个新的webpack插件,通过搜索可以发现,基本上很少有这方面的资料。除了官方文档里面的寥寥数语就只有几篇博客稍微介绍了一下。原因是编写webpack插件需要首先去通读compile
compilation的源码,有一定的门槛。这里是官方的how to write a plugin的介绍。并且给出了一个插件的基本结构如下:

function HelloWorldPlugin(options) {
  // Setup the plugin instance with options...
}

HelloWorldPlugin.prototype.apply = function(compiler) {
  compiler.plugin('done', function() {
    console.log('Hello World!');
  });
};

module.exports = HelloWorldPlugin;

也就是需要定义一个含有apply的原型方法的对象并将其导出。原因是这个apply方法在安装插件时将被webpack编译器调用一次,apply方法提供了一个对应的编译器对象的引用,从而可以在回调函数中访问到
compile对象。但是这个文档也是写得很简单,所以笔者在接触和实践的时候还是花了很多时间去看已经有的webpack 插件的源码。
编写webpack插件的关键部分是要在compilecompilation对象的构建流程中进行提供回调函数来进行拓展处理。关于compilecompilation的回调和信息,以及一些重要的对象,可以参考这里
下面就根据下面这个例子来讲解:

function FileListPlugin(options) {}

FileListPlugin.prototype.apply = function(compiler) {
  compiler.plugin('emit', function(compilation, callback) {
    // Create a header string for the generated file:
    var filelist = 'In this build:\n\n';

    // Loop through all compiled assets,
    // adding a new line item for each filename.
    for (var filename in compilation.assets) {
      filelist += ('- '+ filename +'\n');
    }

    // Insert this list into the Webpack build as a new file asset:
    compilation.assets['filelist.md'] = {
      source: function() {
        return filelist;
      },
      size: function() {
        return filelist.length;
      }
    };

    callback();
  });
};

module.exports = FileListPlugin;

上面这个例子主要是将compilation生成的assets模块写进filelist.md这个文件中。上面是在compile对象的emit构建阶段提供来一个回调函数来进行拓展处理。查阅官方文档可以知道,emit流程时,
编译器开始输出生成资源。这里是插件向 c.assets 数组添加生成资源的最后机会,这样的话就会在指定目录中生成一个filelist.md文件,而不用自己去写fs.writeFileSync去生成该文件,而是借助于
webpack帮我们生成。

当然根据开发人员不同的业务需求,对插件的要求不一样,所以可以在compilecompilation的不同构建流程来提供一些拓展的回调函数,从而可以达到自己的业务需求。

下面是笔者通过阅读源码而总结的从命令行敲入命令后,webpack编译器执行的一系列流程:
image

参考资料: