背景
前幾天在搞一個前端的新項目, 使用到webpack
中的一個alias(別名)可以避免引用路徑的混亂, 但是vscode
無法很好地支持別名的路徑提示
參考了網(wǎng)上某篇博客的介紹, 算是基本滿足了自身的要求
其中介紹使用了一個path-autocomplete
的插件, 簡單介紹就是可以設置好別名對應的實際路徑, 然后再推斷路徑提示的時候?qū)e名替換為設置好的路徑.
// src\features\PathAutocompleteProvider.ts
// configuration.data.pathMappings 即為一個 key為別名, value為真實路徑的對象
Object.keys(configuration.data.pathMappings || {})
.map((key) => {
var candidatePaths = configuration.data.pathMappings[key];
if (typeof candidatePaths == 'string') {
candidatePaths = [candidatePaths];
}
return candidatePaths.map(candidatePath => {
if (workspaceRootPath) {
candidatePath = candidatePath.replace('${workspace}', workspaceRootPath);
}
if (workspaceFolderPath) {
candidatePath = candidatePath.replace('${folder}', workspaceFolderPath);
}
candidatePath = candidatePath.replace('${home}', configuration.data.homeDirectory);
return {
key: key,
path: candidatePath
};
});
})
.some((mappings) => {
var found = false;
mappings.forEach(mapping => {
// 關(guān)鍵的地方在這里, insertedPath 為當前編輯器輸入的路徑
// 判斷輸入的路徑是否是以某個key值開頭的, 如果是則將key進行替換成設置好的路徑, 并返回
if (insertedPath.startsWith(mapping.key) || (mapping.key === '$root' && !insertedPath.startsWith('.'))) {
items.push({
// 該別名對應的路徑
currentDir: mapping.path,
// 從路徑中去掉別名
insertedPath: insertedPath.replace(mapping.key, '')
});
found = true;
}
});
// stop after the first mapping found
return found;
});
大部分情況下, 該插件是可以正常使用, 但是當配置中的key有相同前綴時, 就會出現(xiàn)問題了
比如我的設置是這樣
// .setting.json
"path-autocomplete.pathMappings": {
"@": "${folder}/src",
"@view": "${folder}/src/components"
},
而此時輸入insertedPath = '@view'
, 我的本意應該是去尋找"${folder}/src/components"
, 但是根據(jù)上述代碼, 因為Object.keys()
返回的順序是按照屬性創(chuàng)建的先后順序來的, 故@
排在@view
前面, 又因為@
滿足insertedPath.startsWith(mapping.key)
這個條件, 導致插件誤認為找到正確對應的路徑, 造成錯誤, 無法顯示正確路徑
解決
解決辦法很簡單, 只要讓路徑匹配到有最長的有相同前綴的key
就行了润讥, 即如果路徑是@view
, 則讓@view
排前面, 路徑是@
則讓key@
排前面, 只需在Object.keys()
后多加一個sort(), 按匹配前綴長度大小排列
// .src\features\PathAutocompleteProvider.ts
Object.keys(configuration.data.pathMappings || {})
// 插上這個即可
.sort((key1, key2) => {
const f1 = insertedPath.startsWith(key1) ? key1.length : 0;
const f2 = insertedPath.startsWith(key2) ? key2.length : 0;
return f2 - f1;
})
.map((key) => {
// ... 省略, 與前面一樣
})
.some((mappings) => {
// ... 省略, 與前面一樣
});