目的
了解webpack设计思路,手写一个压缩css plugin
什么是Webpack plugin?
webpack只能识别js,当打包非js文件时,就需要转化器loader对这些文件进行处理。loader所做的事是简单,单一的,loader做不了的事情就需要plugin进行“加工”。所以plugin所做的事就是负责扩展webpack的功能。
如何编写一个plugin?
- 非匿名 JavaScript 函数或 JavaScript 类
- 在其原型中定义一个apply方法
- 指定要运用的钩子函数
- 操作 webpack 内部实例特定数据
- 在功能完成后调用 webpack 提供的回调
class HelloWorldPlugin {
apply(compiler) {
compiler.hooks.done.tap('Hello World Plugin', (
stats /* stats is passed as an argument when done hook is tapped. */
) => {
console.log('Hello World!');
});
}
}
module.exports = HelloWorldPlugin;
// webpack.config.js
var HelloWorldPlugin = require('hello-world');
module.exports = {
// ... configuration settings here ...
plugins: [new HelloWorldPlugin({ options: true })],
};
? 以上是官方最简单的plugin例子,在 compilation 完成时打印出hello world字符串
compiler 和 compilation
上面例子中出现了 Compiler 和 Compilation,它们是 Plugin 和 Webpack 之间的桥梁,需要了解这两个对象的区别~
- Compiler(负责编译):Compiler 对象包含了当前运行Webpack的配置,包括entry、output、loaders等配置,这个对象在启动Webpack时被实例化,而且是全局唯一的。Plugin可以通过该对象获取到Webpack的配置信息进行处理。
- Compilation(负责创建bundles):Compilation对象代表了一次资源版本构建。当webpack 以开发模式运行时,每当检测到一个文件变化,就会创建一个新的 compilation,其中包含当前的模块资源、编译生成资源、变化的文件等。
简单来说,Compiler 代表了整个 Webpack 从启动到关闭的生命周期,而 Compilation 只是代表了一次新的编译,只要文件有改动,compilation就会被重新创建。
手写一个压缩css plugin
- 需要借助
mini-css-extract-plugincss提取插件辅助完成 - 参考
css-minimizer-webpack-plugin插件源码进行编写
未使用压缩css plugin时dist中的main.css

使用plugin后的main.css

最后的最后附上代码~
// ? webpack.config.js
const path = require('path');
const MinifyCssPlugin = require('./MinifyCssPlugin'); // 插件引用
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
entry: './index.js',
module: {
rules: [
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
}
],
},
plugins: [
new MinifyCssPlugin(),
new MiniCssExtractPlugin(),
],
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
},
};
// 手写的插件
const postcss = require('postcss');
const cssnano = require('cssnano');
async function cssnaoMinify({ input, name }) {
const result = await postcss([cssnano({
preset: 'default',
})]).process(
input,
{
to: name,
from: name,
}
);
return {
code: result.css
};
}
class MinifyCssPlugin {
constructor() {
}
apply(compiler) {
compiler.hooks.compilation.tap('MinifyCssPlugin', (compilation) => {
compilation.hooks.processAssets.tap('MinifyCssPlugin', async (assets) => {
const list = Object.keys(assets).map((name) => {
const { info, source } = compilation.getAsset(name);
return {
name,
info,
source,
};
}).filter((e) => e.name.includes('.css'));
const { RawSource } = compiler.webpack.sources;
for (const asset of list) {
const { name, source } = asset;
const { source: input } = source.sourceAndMap();
const options = {
name,
input,
}
const output = await cssnaoMinify(options);
output.source = new RawSource(output.code);
const newInfo = { minimized: true };
compilation.updateAsset(name, output.source, newInfo);
}
})
})
}
}
module.exports = MinifyCssPlugin;