在开始React或者Vue新项目时,我们一般使用脚手架快速的搭建一个工程,脚手架帮我们省去了很多繁琐的配置,但同时也让webpack成了一个迷。在我之前几年的工作经验中,很少真的去了解webpack,遇到问题了网上找点资料复制粘贴一下配置,解决了问题也就没有再去管它,相信很多人应该跟我一样的情况。
webpack这样一个在前端广泛使用的一个工具,还是有必要学习的。loader和plugins是两个重要的核心概念,本文通过实现和应用来了解它们的工作原理。如果想全面的学习或了解webpack,推荐阅读 webpack官网。
编写一个loader
loader用来对源码进行编译转换,比如把ES6编译为ES5,把less编译为css等。一个loader就是一个function,接收一个source参数,对source进行一些处理后返回。
在开发调试时我们会写一些console.log,在生产环境中建议删除。我们可以实现这样一个loader,打包编译时自动删除console.log。如下图,npm init后写一个简单的方法,这样就实现了我们要的功能。
// 目录结构
loader-demo
├─index.js
└package.json
// index.js内容
module.exports = function(source) {
console.log('----------- loader -----------');
return source.replace(/console\.log\(.*?\)/, '');
}
使用这个loader
- 发布loader
可以用npm publish命令将loader-demo发布到npm仓库,为了方便测试,也可以使用npm link命令。进入loader-demo目录,执行npm link。 - 在另一个工程使用
我们新建一个npm+webpack工程,名为webpack-demo,在工程目录下执行npm link loader-demo。在配置文件里使用loader-demo如下,匹配js文件,使用loader-demo来处理,每个匹配的文件都会把源码传给我们的loader-demo方法进行处理。
// 目录结构
webpack-demo
├─package.json
├─webpack.config.js
├─src
├─index.js
└print.js
// webpack.config.js内容
const path = require('path');
module.exports = {
entry: './src/index',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'app.bundle.js'
},
module: {
rules: [
{
test: /\.js$/,
use: 'loader-demo'
}
]
}
}
- 看一下效果
使用loader-demo前,在打包后的文件里可以搜索到console.log,使用loader-demo后,在打包后的文件里搜索不到console.log,说明我们的loader起了效果。在本文的最开始处有附件,可以下载尝试。
编写一个plugin
插件能做的事情更多,这里实现一个简单的功能:在打包后的每个js文件头部加入版权信息。
// 目录结构
yo-plugin-demo
├─index.js
└package.json
// index.js内容
module.exports = class PloginDemo {
// 构造器,传入版权信息
constructor(crInfo) {
this.crInfo = crInfo;
}
// 必须,webpack运行时调用
apply(compiler) {
// webpack生命周期,生成资源到output目录之前执行
// 具体可以查看 https://www.webpackjs.com/api/compiler-hooks
compiler.hooks.emit.tap('YoPluginDemo', compilation => {
console.log('----------- plugin -----------');
// 遍历所有资源,以js结尾的文件,在头部加上版权信息
for(const fileName in compilation.assets) {
if(/\.js$/.test(fileName)) {
const asset = compilation.assets[fileName];
asset.source = () => {
return `/** Copyright © ${this.crInfo} */\r\n${asset._value}`
}
}
}
});
}
}
使用这个plugin
- 发布plugin(跟前面讲的loader一样)
npm link - 在另一个工程使用(使用前面说到的webpack-demo)
npm link yo-plugin-demo
// webpack.config.js内容
const path = require('path');
const YoPluginDemo = require('yo-plugin-demo');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'app.bundle.js'
},
module: {
rules: [
{
test: /\.js$/,
use: 'loader-demo'
}
]
},
plugins: [
new HtmlWebpackPlugin(),
new YoPluginDemo('2020 朽木'),
]
}
- 看一下效果
在打包后的js文件头部可以看到/** Copyright © 2020 朽木 */,表示插件使用成功。