目录
前言
一、关于loader
二、确认需求
三、loader编写
1.初始化
2.loader编写
3.增加可配置化代码
四、代码调试
本文默认读者对前端工程化有一定的认识,对webpack有一定的裂解并且知道怎么使用webpack,本文会一步一步带领读者手动编写一个webpack的loader,以此加深对webpack的理解
loader是webpack里面一个相当重要的一个组成部分,用于将现有的代码转化成目标代码,最为人所知的就是babel,他能够将es6的代码,转化成大部分浏览器浏览器能够执行的es5代码,接下来,我们尝试着通过自己手动编写一个loader,来看清loader是什么
首先,我们确认一下我们这个简单的loader能做什么,日常中我们应该会有这样的需求,开发环境和生产环境相同的接口api地址是不同的,运行阶段我们可以通过process.env来区分不同的环境使用不同的链接,那么有没有办法在编译阶段就把这件事给做了呢,我们这个loader就可以实现这个功能
首先我们新建一个文件夹loader-example,目录结构如下
src/index.js
const content = {{ __path__ }};
console.log(content);
document.getElementsByTagName('body')[0].innerHTML = content
package.json
{
"name": "loader-example",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack",
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"html-webpack-plugin": "^4.5.0",
"loader-utils": "^2.0.0",
"open": "^7.3.0",
"path": "^0.12.7",
"webpack": "^5.7.0"
},
"devDependencies": {
"webpack-cli": "^4.2.0"
}
}
webpack.config.js
module.exports = {
mode: 'development', // 先设置为development,不压缩代码,方便调试
entry: {
main: './src/index.js'
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist'),
},
}
我们的目标是,写一个loader,在编译阶段,把index.js里面的{{ __path__ }}转化为我们真正需要的路径。所以,执行npm install安装所有依赖,然后npm run build,果不其然,报错了,没有办法处理{{ __path__ }},提示我们可能需要一个loader,接下来我们开始loader的编写
其实loader说白了,就是一个函数,我们所需要做的,就是定义一个函数,然后在webpack.config.js里面正确的引入就可以了,我们在根目录下新增目录loaders和文件replaceLoader.js,文件路径为loaders/replaceLoader.js,我们先来一个最简单的
module.exports = function (source) {
const result = source.replace("{{ __path__ }}", "测试");
//this.callback 也是官方提供的API,替代return
this.callback(null, result);
}
我们导出一个函数,这个函数的入参就是原始js的文本,我们可以对它进行任意的操作,现在我们把它替换成测试两个字,最后切记调用一下this.callback将对应的值返回,只有这样,打包之后的内容才会是新的内容,callback遵循error first原则,第一个参数是报错的值,第二个参数是转化后的结果,然后我们更新一下webpack.config.js,在webpack.config.js里面添加module属性如下
module: {
rules: [{
test: /\.js$/,
use: {
loader: path.resolve(__dirname, './loaders/replaceLoader.js'),
}
}]
},
在module里面将对应的loader引入,再次运行npm run build,观察一下dist文件夹下的main.js,你就会发现,模板代码已经被替换成 测试 这两个字了
但是,如果我们还有更高的追求呢,例如我们希望这个插件能实现可配置化呢
我们修改index.js如下
const loaderUtils = require('loader-utils');
module.exports = function (source) {
//拿到options 配置
const options = loaderUtils.getOptions(this);
//回头options里面配置个value参数
const { value } = options;
//将源文件内容替换成value
const result = source.replace("{{ __path__ }}", JSON.stringify(value));
//this.callback 也是官方提供的API,替代return
this.callback(null, result);
}
我们引入loader-utils这个工具包,让我们能够获取到webpack.config.js上的配置内容,然后我们更新webpack.config.js的module
module: {
rules: [{
test: /\.js$/,
use: {
loader: path.resolve(__dirname, './loaders/replaceLoader.js'),
options: {
value: 'http://www.baidu.com' //参数传入到loader里面,方便getOptions接收到
}
}
}]
},
我们在options里面配置对应的参数,这样我们在loader里面就能够取到参数,至此,我们完成了一个很简单的loader
对于很简单的loader,我们基本可以不怎么调试直接打包就能看到我们的结果对不对,那么,如果对于一些比较复杂的loader,我们应该怎么在编写的过程中进行调试呢?
我们可以直接用命令开启webpack的调试模式,首先我们在我们想要调试的代码里面打上debugger,然后在命令行中输入如下命令进行打包
node --inspect-brk ./node_modules/webpack/bin/webpack.js
这时我们就可以看到监听已经打开
然后我们可以在chome里面打开下面的地址:chrome://inspect/#devices,就会看到以下界面
猛戳红框里面的文字,就可以愉快的调试了