likes
comments
collection
share

项目被二开了,我想修改组件路径怎么办?

作者站长头像
站长
· 阅读数 3

前端小玉儿一直喜欢解决问题,更喜欢的是帮同事处理好问题之后的成就感。多年开发中,遇到的问题很多,一直也没时间整理成文章。这周正好离开职场,时间自由了,今后可以做持续的分享或系列文章,将多年的实战经验分享给宝子们。

一、背景介绍

负责一个vue低代码平台,接手时已经被拿去进行二次开发了,里面的部分组件也被引用过了。但是,项目中某些核心组件,目录混乱,此时修改,势必会导致二次开发组件引用异常,而且,通知各组去修改组件引用路径也不现实。于是,前端小玉儿做了如下方案。废话少说,直接上干货。

二、解决方案

该解决方案的核心原理为:webpack支持配置别名,可将旧路径作为别名的key,新路径作为别名的value。

虽然原理很简单,但是在操作的过程中也遇到了种种问题。遇到的坑坑洼洼在代码备注内有所体现。而且,末尾会有个总结,供各位伙伴参考。

具体操作及代码见下文。

2.1 添加新旧路径映射

创建一个新旧路径文件目录映射关系的js文件pathMap.js,该文件返回一个json对象,其书写示例如下:

module.exports = {
    'src/components/custom': 'src/views/custom'  // key 为新路径,value为旧路径
}

2.2 读取文件生成别名对象

这部分操作均在vue.config.js中完成。

2.2.1 引入依赖包

脚手架的一系列依赖中已经包含了fs-extra以及path依赖,在vue.config.js中引入这两个依赖包

const fs = require('fs-extra')
const path = require('path')
const pathMap = require('./src/pathMap.js') // 新旧路径映射对象
const pathSep = path.sep // 不同操作系统下的路径分割符号

2.2.2 封装webpack配置别名对象获取方法

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 读取文件目录的递归方法

项目被二开了,我想修改组件路径怎么办?

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别名配置即可,示例代码如下:

configureWebpack: {
    resolve: {
        alias: {
            '@': resolve('src'),
            ...getTargetObj()
        }
    }
}

至此,这个解决方案已经配置完毕,即使更换了组件位置,只要正确配置了新旧路径关系,运行项目就可正常加载组件。前端小玉儿也算松了口气。

三、遇到的坑坑洼洼

  1. 别名配置中的key与value不支持直接书写路径字符串,需要使用path.resolve()后的结果
  2. 别名配置不支持直接使用文件夹的路径作为key或value,需要读取到文件级别,index.js或index.vue除外
  3. 遇到路径中存在index.vue或index.js时,需要读取到该文件的上级目录
  4. 不同操作系统下,路径的分隔符号存在差异,需要统一替换为path.sep
  5. 最重要的一点:

如果你的项目还处于萌芽阶段,可以提前配置别名指向各个文件夹的路径,引用时直接使用别名,以后如果优化目录,直接改这里就OK了,不用做映射了。

  1. 最后的最后,前端小玉儿提醒,修改一定要做好注释,否则,百年之后,优化掉了,系统瘫了,可能存在被刨坟的风险。
  2. 今天这个问题就处理到这里,宝子们觉得有用,辛苦您的小手点个赞,有问题也可以随时联系爱解决问题的前端小玉儿。