webpack定义的loader需要遵循单一功能原则,也就是一个loader只实现一个功能。在实现开发中,我们会直接使用诸如蓝湖等生成的样式,比如
button{background: rgb(255, 85, 46);
}
但为了考虑主题换肤,我们实现的想要的可能是
button{background: var(--jobb_primary_color);
}
所以在这里我们要实现一个vue文件中内容替换的loader。
首页,创建webpack-replace-loader.js
我们通过在loaders/webpack-replace-loader.js中定义一个函数(我们知道loader就是一个函数),实现代码如下:
module.exports = function (source) {//source就是读取文件的内容//可以在此处对source进行替换...this.callback(null, source);
}
使用loader,以vue.config.js配置为例
module.exports = {chainWebpack: (config) => {config.module.rule('vue').test(/\.vue/).use('webpack-replace-loader').loader('webpack-replace-loader').options(loader参数).end();},configureWebpack: (config) => { //加载本地loaderconfig.resolveLoader.modules.push('./loaders/'); }
}
loader传入参数考虑
内容替换实现方式,一般是通过正则
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)'}
步入正题,loader编写
//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);
}