webpack定义的loader需要遵循单一功能原则,也就是一个loader只实现一个功能。在实现开发中,我们会直接使用诸如蓝湖等生成的样式,比如
button{
background: rgb(255, 85, 46);
}
但为了考虑主题换肤,我们实现的想要的可能是
button{
background: var(--jobb_primary_color);
}
所以在这里我们要实现一个vue文件中内容替换的loader。
我们通过在loaders/webpack-replace-loader.js中定义一个函数(我们知道loader就是一个函数),实现代码如下:
module.exports = function (source) {
//source就是读取文件的内容
//可以在此处对source进行替换
...
this.callback(null, source);
}
module.exports = {
chainWebpack: (config) => {
config.module
.rule('vue')
.test(/\.vue/)
.use('webpack-replace-loader')
.loader('webpack-replace-loader')
.options(loader参数)
.end();
},
configureWebpack: (config) => {
//加载本地loader
config.resolveLoader.modules.push('./loaders/');
}
}
内容替换实现方式,一般是通过正则
new RegExp(pattern[, flags])
// eg.
str.replace(new RegExp('rgb(255, 85, 46', 'ig'), 'var(--jobb_primary_color)');
所以,我们需要设置三个参数
let options = {search: '正则表达式的文本', flags: '标志', replace: '替换结果'}
考虑到会存在多个变量替换,因此
let options = [{search: 'rgb(255, 85, 46', flags: 'ig', replace: 'var(--jobb_primary_color)'}]
而loader参数只支持string | object, 因此我们需要支持两个写法
//1.考虑多个变量
let options = {
multi: [{search: 'rgb(255, 85, 46', flags: 'ig', replace: 'var(--jobb_primary_color)'}]
}
//2.单个变量
let options = {search: 'rgb(255, 85, 46', flags: 'ig', replace: 'var(--jobb_primary_color)'}
//loaders/webpack-replace-loader.js
const { getOptions } = require('loader-utils');
module.exports = function (source) {
//通过loader-utils获取参数
let options = getOptions();
//分情况考虑
if(Array.isArray(options.multi)){
options.multi.forEach(item)=> {
//替换
source = replaceFunction(item, source)
}
}else{
//替换
source = replaceFunction(options, source)
}
this.callback(null, source);
}
//错误提示
const errTip = '[webpack-replace-loader: Error] The property "search" and "replace" is essential';
const replaceFunction = (data, source)=>{
let { search, flags, replace} = data;
if(!search || !replace){
throw new Error(errTip);
}
return source.replace(new RegExp(search, flags), replace);
}