背景
Vueベースのローコードプラットフォームの開発を担当し、既に二次開発が行われている状況で、一部のコンポーネントのパスを変更する必要がありました。しかし、その変更により二次開発されたコンポーネントの参照が壊れる可能性があり、各チームにパスの変更を通知することも現実的ではありませんでした。
解決策
この問題を解決するための主なアプローチは、Webpackのエイリアス機能を使用して、古いパスを新しいパスにマッピングすることです。
1. 新旧パスのマッピングファイルを作成する
まず、新旧パスの対応関係を記述したJavaScriptファイルを作成します。以下の例では、`pathMap.js`という名前で作成します。
module.exports = {
'src/views/custom': 'src/components/custom' // key は新しいパス, value は古いパス
}
2. ファイルからエイリアスオブジェクトを生成する
この処理は `vue.config.js` で行います。
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 Webpackのエイリアス設定オブジェクトの取得メソッドを定義する
function getTargetObj() {
const newPathArr = Object.keys(pathMap) // 新しいパスのリストを取得
const targetObj = {}
for (let i = 0; i < newPathArr.length; i++) {
const newPathKey = newPathArr[i]
const newPath = newPathKey.split('/').join(pathSep)
try {
const stat = fs.statSync(newPath)
const targetPath = pathMap[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
}
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の場合は特別な処理が必要
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
}
3. Webpackのエイリアス設定を行う
`vue.config.js` に以下のようにエイリアス設定を追加します。
configureWebpack: {
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
...getTargetObj()
}
}
}
これで、コンポーネントのパスを変更しても、正しいエイリアス設定によってプロジェクトが正常に動作します。
注意点
- エイリアス設定のkeyとvalueは、`path.resolve()`を使用して絶対パスに変換する必要があります。
- エイリアス設定では、ディレクトリのパスを直接使用することはできません。ただし、`index.js`や`index.vue`は例外です。
- `index.vue`や`index.js`がある場合、それらの上位ディレクトリまで読み込む必要があります。
- 異なるオペレーティングシステム間でパスのセパレータが異なるため、`path.sep`を使用して統一します。
- プロジェクトが初期段階であれば、あらかじめ各ディレクトリへのエイリアスを設定しておくと、後々のディレクトリ構造の最適化時に便利です。