咱们在使用webpack配置项目时会使用过各类各样的loader和plugin,例如less-loader、file-loader、html-webpack-plugin、clean-webpack-plugin等等。可是咱们是否想过这些loader或plugin是如何编写的呢?今天咱们就来了解一下如何实现的loader和plugin.也方便咱们之后编写本身的loader或者pluginjavascript
loader是文件加载器,可以加载资源文件,并对这些文件进行一些处理,诸如编译、压缩等,最终一块儿打包到指定的文件中html
其实loader简单来讲就是一个函数,经过一个函数参数接受到源代码,并在函数内部对源代码做出变动,并最终返回源代码前端
咱们就来实现一个能够接受txt文件并对其进行首字母大写的loader,由于这个没啥用,咱们就单纯的用做了解laoder编写的过程。
第一步:新建项目并配置好webpackjava
npm init
npm install -D webpack webpack-cli
复制代码
webpack.config.jsnode
const path = require('path');
module.exports = {
mode: 'development',
entry: {
main: './src/index.js'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js'
}
}
复制代码
src文件夹下index.js与index.txtwebpack
// index.js
import './index.txt';
// index.txt
复制代码
第二步:编写loader
新建一个loader文件夹存放本身编写的loader,这里咱们新建一个uppercaseLoader.js文件。web
module.exports = function (source) {
// 这里的source表明的是源代码
}
复制代码
咱们是要将txt中字符串进行首字符大写的转换,接下来直接完善uppercaseLoader.js便可npm
module.exports = function(source) {
return result = source.charAt(0).toUpperCase() + source.slice(1)
}
复制代码
第三步:使用loader
要使用咱们本身编写的loader,不是像其余的loader同样直接在module里面配置就好了,还须要配合resolveLoader来使用。这样配置的意义是在module中只用写loader名称,webpack会先到node_modules里面找,找不到就去当前目录下的loaders中去找。json
const path = require('path');
module.exports = {
mode: 'development',
entry: {
main: './src/index.js'
},
resolveLoader: {
modules: ['node_modules', './loaders']
},
module: {
rules: [{
test: /\.txt$/, // 专门处理txt文件
use: [
{
loader: 'uppercaseLoader',
},
]
}]
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js'
}
}
复制代码
package.json添加以下配置: "script: { "build": "webpack"}"api
接下来运行npm run build,会生产一个dist文件,在dist文件下main.js中你会看到已经对txt文件下的字符串进行了首字母大写转换。
第四步:loader参数配置
loader一般还可使用参数,可使用loader-utils来读取loader的参数,例如咱们如今只对首字母为a的字符串进行大写转换,咱们能够这么作。
npm install --save-dev loader-utils
复制代码
改写webpack.config.js
...
rules: [{
test: /\.txt$/,
use: [
{
loader: 'uppercaseLoader',
options: {
initial: 'a'
}
},
]
}]
复制代码
uppercaseLoader.js
const loaderUtils = require('loader-utils');
module.exports = function(source) {
const options = loaderUtils.getOptions(this); // 读取配置
if (options.initial === source.charAt(0)) {
return result = source.charAt(0).toUpperCase() + source.slice(1)
}
return source
}
复制代码
有时候咱们不止要return一个resource,若是想要返回err, 处理后源代码,source,或者其余内容,那么可使用this.callback.
this.callback( err: Error | null, content: string | Buffer, sourceMap?: SourceMap, meta?: any );
module.exports = function (source) {
// ...
this.callback(null, result);
}
复制代码
若是想要在函数内部作异步处理那么可使用this.async()
module.exports = function (source) {
const options = loaderUtils.getOptions(this);
const callback = this.async(); // 声明一下内部有异步操做
setTimeout(() => {
let result = source
if (options.initial === source.charAt(0)) {
return result = source.charAt(0).toUpperCase() + source.slice(1)
}
callback(null, result);
}, 1000);
}
复制代码
编写loader须要注意的是不要使用箭头函数,会致使this指向错误
plugin是一个类,使用时plugins(插件包)中单独配置,每一项是一个 plugin 的实例,参数都经过构造函数传入。在 Webpack 运行的生命周期中会广播出许多事件,Plugin 能够监听这些事件,在合适的时机经过 Webpack 提供的 API 改变输出结果,plugin让 webpack 具备更多的灵活性,提高开发效率.
咱们来实现一个向打包文件中添加一个md说明文档功能的addMdWebpackPlugin
第一步:新建项目并配置好webpack
webpack.config.js
const path = require('path');
module.exports = {
mode: 'development',
entry: {
main: './src/index.js'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js'
}
}
复制代码
第二步:编写plugin
plugin由于是一个类,那么他的基本结构以下:
// addMdWebpackPlugin.js
class addMdWebpackPlugin {
constructor(options){
console.log(options) // options是插件传入的参数
}
apply(compiler) { // compiler是webpack的实例}
}
module.exports = addMdWebpackPlugin;
复制代码
compiler是在 Webpack 启动时候被实例化的,做为webpack的实例compiler包含了Webpack 环境全部的的配置信息,包含 options,loaders,plugins 这些信息。
结构写好以后接下来完善plugin,由于咱们要在打包的文件中添加一个md文档,那么咱们就要用到compiler的hooks,由于hooks表明着钩子函数,是webpack在执行过程当中必经的过程,在hooks里面又定义了一些具体的时刻值。咱们这里用到的是emit时刻,官网这样描述emmit:Executed right before emitting assets to output dir.意思是在打包输出dist以前执行。而且要注意的是emit是一个异步的时刻值。那么咱们能够这样来写:
class addMdWebpackPlugin {
constructor(options){
console.log(options) // options是插件传入的参数
}
apply(compiler) { // compiler是webpack的实例
compiler.hooks.emit.tapAsync('addMdWebpackPlugin', (compilation, cb) => {
compilation.assets['describe.md']= { // compilation.assets是打包生成的文件,能够向其中添加内容
source: function() {
return 'hello word'
},
size: function() {
return 21;
}
};
cb();
})
}
}
module.exports = addMdWebpackPlugin;
复制代码
更多关于compiler的知识请看这里webpack.js.org/api/compile…
第三步:使用plugin
plugin写好以后,须要webpack中引入并使用插件
const addMdWebpackPlugin = require('./addMdWebpackPlugin');
module.exports = {
...// 省略
plugins: [
new addMdWebpackPlugin()
],
}
复制代码
执行npm run build,便可在打包完成的dist目录中看到一个md文档。这个过程进行了以下步骤:
经过上述的两个例子,尽管两个例子没有什么大的用处,编写都也很是简单,可是我也学习到了应该如何编写loader和plugin,但愿也能够打开你们编写loader和plugin的大门。webpack博大精深,若是想要写出更加有效和实用的loader或plugin,咱们仍是须要不断的学习。但这也让咱们在之后遇到须要编写本身的loader或者plugin的状况下,不至于无从下手。
仍是那句话,学习中分享,分享中学习,欢迎关注无畏前端!!