昨天闲来无事,逛逛 GitHub,突然发现有人 star 了我的项目 vue-mixins-loader,可给我激动坏了。本着有一个人用,就要维护到底的原则,我准备给这个 Loader 做一次优化。在实际用的过程中发现一个问题:使用时,会把项目中所有 .vue 文件都给注入 mixins 。比如有些外部引入的 .vue 组件,这就完全没有必要去注入 mixins 。所以,计划再新增一个 options 属性
exclude
,由用户自己去定义哪些文件可以排除掉,不注入 Loader 提供的 mixins 。想法有了,这就开搞!(其实这个问题在第一版发布的时候,就发现了,当时手头有点忙就给搁置了,刚好这次给完善一下)
属性设计
这次需要在 Loader 的 options 中新增一个属性 exclude ,由于 Loader 的 options 的特殊性(会进行 JSON 的序列化和反序列化处理),所以,属性的数据类型就设计成 string
或者 string[]
,这两种类型分别对应单个或者多个。值为一个正则表达式字符串,用这个去判断当前 .vue 文件是否在 Loader 的处理之外。
也就是现在的 options 可以写成下面这样:
options: {
exclude: 'element-ui',
// 或者
exclude: ['components/', 'view-design'],
// 之前的配置
tools3: '@/utils/tools3.js',
custom: stringify({
mounted() {
console.log("this is custom mixins's mounted")
}
})
}
把
exclude
与之前的混入属性放在一起,总感觉怪怪的。最好还是把混入的属性归纳在一个字段里比较合适,比如 mixin 什么的。OK,下一个版本的功能迭代有啦!嘿嘿!
功能实现
获取配置中提供的 exclude
参数,借助 loader-utils
提供的 getOptions 方法。
const { getOptions } = require("loader-utils")
function callback(source, sourceMaps) {
const originOptions = getOptions(this)
const { exclude } = originOptions
}
获取当前文件路径,同样借助 loader-utils
提供的 getCurrentRequest 方法。
const { getCurrentRequest } = require("loader-utils")
function callback(source, sourceMaps) {
const currentRequest = getCurrentRequest(this)
}
校验当前文件是否需要排除,写一个方法 validateExclude
专门去判断这个。如果返回值是 true
,那么直接返回源文件内容即可。不需要再走下面注入 mixins 的逻辑。
const { getOptions, getCurrentRequest } = require("loader-utils")
function callback(source, sourceMaps) {
const originOptions = getOptions(this)
const { exclude } = originOptions
const currentRequest = getCurrentRequest(this)
// 校验是否排除当前文件
if (validateExclude(exclude, currentRequest)) {
return source
}
}
validateExclude
的具体内容如下:
const validate = (rule, targetStr) => {
const pattern = new RegExp(rule, "g")
return pattern.test(targetStr)
}
// 获取 vue 文件的路径,并将反斜杠转为斜杠
const getFilePath = str => {
const start = str.indexOf("!")
const end = str.indexOf(".vue", start)
const path = str.slice(start + 1, end + 4)
return path.replace(/\\/g, "/")
}
/**
* 校验当前文件是否排除
* @param {string|string[]} rules 排除的规则
* @param {string} currentRequest 当前文件路径
* @returns {boolean}
*/
function validateExclude(rules, currentRequest) {
if (!rules) {
return false
}
// 统一转为 Array 类型,方便处理
if (typeof rules === "string") {
rules = [rules]
}
const filePath = getFilePath(currentRequest)
for (const rule of rules) {
if (validate(rule, filePath)) {
return true
}
}
return false
}
这里有一个路径转换的操作,这是因为不同操作系统文件路径不一致:
所以,统一将反斜杠 \
转为了斜杠 /
,也比较符合操作习惯。
如何使用
exclude
同样是配置在 options 对象下,提供一个字符串,或者字符串数组。
const path = require("path")
const { stringify } = require("vue-mixins-loader")
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.vue$/,
use: [
"vue-loader",
{
loader: "vue-mixins-loader",
options: {
exclude: ["components/", "view-design"], // v1.0.2 new add
tools: path.resolve("./src/utils/tools.js"),
tools2: path.resolve("./src/utils/tools2.js"),
tools3: "@/utils/tools3.js",
custom: stringify({
props: {
block: {
type: Object,
default: () => ({})
}
},
mounted() {
console.log("this is custom mixins's mounted")
}
})
}
}
]
}
]
}
}
从昨天下午 4 点半开始准备写这个功能,到凌晨 1 点完成。写功能其实也就用了 2 小时左右,其余的时间都在优化测试的代码,之前的测试用例是 rollup 写的,测试 Loader 需要用 loader-runner 去实现。当时是为了偷懒,Loader 打包用的 rollup ,所以测试也顺带用 rollup 了,测试过程极其繁琐。于是就想着整改一下,直接改用 webpack + webpack-dev-server 去测试。整改完后,果然,测试轻松多啦,美滋滋~~~
整完之后,顺带发布 v1.0.2 !赶紧来试试吧!