前端小玉儿一直喜欢解决问题,更喜欢的是帮同事处理好问题之后的成就感。多年开发中,遇到的问题很多,一直也没时间整理成文章。这周正好离开职场,时间自由了,今后可以做持续的分享或系列文章,将多年的实战经验分享给宝子们。
一、背景介绍
负责一个vue低代码平台,接手时已经被拿去进行二次开发了,里面的部分组件也被引用过了。但是,项目中某些核心组件,目录混乱,此时修改,势必会导致二次开发组件引用异常,而且,通知各组去修改组件引用路径也不现实。于是,前端小玉儿做了如下方案。废话少说,直接上干货。
二、解决方案
该解决方案的核心原理为:webpack支持配置别名,可将旧路径作为别名的key,新路径作为别名的value。
虽然原理很简单,但是在操作的过程中也遇到了种种问题。遇到的坑坑洼洼在代码备注内有所体现。而且,末尾会有个总结,供各位伙伴参考。
具体操作及代码见下文。
2.1 添加新旧路径映射
创建一个新旧路径文件目录映射关系的js文件pathMap.js,该文件返回一个json对象,其书写示例如下:
java
module.exports = {
'src/components/custom': 'src/views/custom' // key 为新路径,value为旧路径
}
2.2 读取文件生成别名对象
这部分操作均在vue.config.js中完成。
2.2.1 引入依赖包
脚手架的一系列依赖中已经包含了fs-extra以及path依赖,在vue.config.js中引入这两个依赖包
javascript
const fs = require('fs-extra')
const path = require('path')
const pathMap = require('./src/pathMap.js') // 新旧路径映射对象
const pathSep = path.sep // 不同操作系统下的路径分割符号
2.2.2 封装webpack配置别名对象获取方法
csharp
function getTargetObj() {
const newPathArr = Object.keys(pathMap) // 获取新路径列表
const targetObj = {}
for (var i = 0; i < newPathArr.length; i++) {
const newPathKey = newPathArr[i]
const newPath = newPathKey.split('/').join(pathSep)
try {
const stat = fs.statSync(newPath)
const targetPath = fileMap[newPathKey].split('/').join(pathSep)
if (stat.isDirectory()) { // 如果新路径是个文件夹
readDir(newPath, targetObj, targetPath, newPath)
} else { // 如果新路径直接是个文件
targetObj[path.resolve(__dirname, targetPath)] = path.resolve(__dirname, newPath)
}
} catch (error) { // 如果新路径报错,直接是一个不带后缀的文件
console.info('文件匹配错误信息:', '您重定向的文件路径既不是文件夹也不是带有扩展名的文件')
}
}
return targetObj
}
特别注意:生成的别名对象的key值与value值必须是path.resolve(__dirname, path)的结果,否则无法使用。
2.2.3 读取文件目录的递归方法
ini
function readDir(dirPath, configJson, oldPath, newPath) {
const files = fs.readdirSync(dirPath)
const result = {}
files.forEach(function(file) {
const newDirPath = dirPath
const filePath = path.join(newDirPath, file)
const stat = fs.statSync(filePath)
if (stat.isDirectory()) { // 判断是否为文件夹
result[file] = readDir(filePath, configJson, oldPath, newPath)
} else {
const oldFilePath = filePath.replace(newPath, oldPath)
configJson[path.resolve(__dirname, oldFilePath)] = path.resolve(__dirname, filePath)
// index.vue或index.js时需特殊处理,否则webpack无法正确重定向
if (filePath.includes(pathSep + 'index.vue') || filePath.includes(pathSep + 'index.js')) {
const targetStr = filePath.includes(pathSep + 'index.vue') ? pathSep + 'index.vue' : pathSep + 'index.js'
const oldFilePath_ = oldFilePath.replace(targetStr, '')
const newFilePath_ = filePath.replace(targetStr, '')
configJson[path.resolve(__dirname, oldFilePath_)] = path.resolve(__dirname, newFilePath_)
}
}
})
return configJson
}
2.3 配置别名
在vue.config.js中添加webpack别名配置即可,示例代码如下:
css
configureWebpack: {
resolve: {
alias: {
'@': resolve('src'),
...getTargetObj()
}
}
}
至此,这个解决方案已经配置完毕,即使更换了组件位置,只要正确配置了新旧路径关系,运行项目就可正常加载组件。前端小玉儿也算松了口气。
三、遇到的坑坑洼洼
- 别名配置中的key与value不支持直接书写路径字符串,需要使用path.resolve()后的结果
- 别名配置不支持直接使用文件夹的路径作为key或value,需要读取到文件级别,index.js或index.vue除外
- 遇到路径中存在index.vue或index.js时,需要读取到该文件的上级目录
- 不同操作系统下,路径的分隔符号存在差异,需要统一替换为path.sep
- 最重要的一点:
如果你的项目还处于萌芽阶段,可以提前配置别名指向各个文件夹的路径,引用时直接使用别名,以后如果优化目录,直接改这里就OK了,不用做映射了。
- 最后的最后,前端小玉儿提醒,修改一定要做好注释,否则,百年之后,优化掉了,系统瘫了,可能存在被刨坟的风险。
- 今天这个问题就处理到这里,宝子们觉得有用,辛苦您的小手点个赞,有问题也可以随时联系爱解决问题的前端小玉儿。