webpack4.0之插件

插件

插件是webpack最重要的机制之一,默认情况下webpck做的是 模块加载、依赖分析、文件输出等基本工作。大部分的功能都需要使用插件来实现。
如果需要实压缩css代码,那就需要使用 MiniCssExtractPlugin 插件

1
2
3
new MiniCssExtractPlugin({
filename: "css/[name].[hash:8].css"
}),

如果需要使用html模块,那就需要使用HtmlWebpackPlugin插件

1
2
3
4
new HtmlWebpackPlugin({
filename: 'index.html',
template: './index.html',
})

插件的基本使用

一般插件都是第三方的库,所以在使用之前需要先安装,再使用。 使用时需要new一个新的插件实例。所以本质上插件就是我们预备好某一个功能代码,等待webpack去执行而且。插件的写法并不要求顺序,他们会准确的在对应的webpack生命周期中执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
entry: "./src/index.js",
plugins: [
new HtmlWebpackPlugin({
template: "./src/index.html",
filename: "index.html",
minify: {
collapseWhitespace: true
}
}),
new MiniCssExtractPlugin({
filename: "app.[hash:8].css"
})
// ...
],
};

插件的基本运行原理

webpack使用tapable(webpack4.0-tapable)管理自己的钩子。在webpack运行生命周期里布满了各种钩子,如在插件初始化之后会调用afterPlugins钩子、在处理好入口配置之后会调用entryOption钩子。
一个基本的插件框架如下:

1
2
3
4
5
class HelloWorldPlugin {
apply(compiler) {
// to do
}
}

  1. webpack初始化时会依次plugins列表中的 插件的apply方法。我们需要在这里挂载相应的钩子回调,比如entryOption
  2. webpack运行到相应的生命周期,调用钩子回调函数。

###实现自定义插件
实现一个插件,将打包完成后的静态文件上传到阿里云。

首先我们得确定我们的插件是在webpack生命周期的哪一步调用的,翻找官方hooks列表,生成文件应该是 afterEmit钩子。

第二步申请一个alioss存储服务并安装nodejs sdk.

1
yarn add ali-oss -D

第三步 程序逻辑很简单,将我们本地文件依次上传到阿里云oss,并设置headers

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
let aliOSS = require('ali-oss')
let path = require('path')
let colors = require('colors')
let mime = require('mime')
class AliOSSUploadPlugin{
constructor(options) {
this.ossPath = options.path || ''

this.options = options
this.client = new aliOSS({
region: options.region,
accessKeyId: options.accessKeyId,
accessKeySecret: options.accessKeySecret,
bucket: options.bucket,
})
}
apply(compiler) {
compiler.hooks.afterEmit.tapPromise('AliOSSUploadPlugin', (compiation) => {
return new Promise((resolve, rejeect)=>{
let assets = compiation.assets

Object.keys(assets).forEach((filename) => {
const localFilePath = assets[filename].existsAt
this.upload(path.join(this.ossPath, filename), localFilePath)
})
})
})
}
upload(ossFilePath ,localFilePath){
if (ossFilePath && localFilePath) {
this.client.put(ossFilePath, localFilePath,{
mime: mime.getType(localFilePath.split('.').pop()) || '',
headers: {
'Cache-Control': 'max-age=31536000'
}
})
.then(result => {
if (result.res && result.res.status === 200) {
console.log( `${result.name} upload success`.green)
} else {
console.log(`${result.name} upload fail, status: ${result.res.status}, message: ${result.res.statusMessage}`.red)
}

})
}
}
}

module.exports = AliOSSUploadPlugin