目前 vite 還不是很成熟,因為他的啟動速度快,以至於我們想在開發環境使用它,生產還是繼續使用webpack,也就是vite + webpack 共存的情況下:
vite 有個插件 vite-plugin-require-transform 會自動把 require() 函數轉化為 import ...from 的方式,但是有一種情況他忽略了,就是 require() 函數里面的路徑是變量拼成的,而且該插件也不支持我現在說的這種格式。例如 require("../../assets/img/" + _vm.filePath + ".png") ,這種情況,它就是沒有處理的,所以我們自己寫一個插件來解決這個問題
1. 插件定義
const path = require('path')
const glob = require('glob')
export const replaceRequireVariable = (includes = []) => {
return {
name: 'replaceRequireVariable',
apply: 'serve',
transform(code, id) {
let result = code
if (includes.some(item => id.includes(item))) {
result = replaceRequrieDynamic(code, id)
}
return result
}
}
}
/**
* 替換包含變量的require函數
* @param {*} code
* @param {*} id
* @returns
*/
const replaceRequrieDynamic = function(code, id) {
// node_modules排除
if (/\/node_modules\//g.test(id)) return code
const regex = /require\(\(\s*(["].*["])\s*\)\)/g
const requireMatches = code.matchAll(regex)
let importString = ''
let constObjString = ''
for (const item of requireMatches) {
/**
* item[0] 匹配出來的選項 例如:require(("../../assets/img/" + _vm.filePath + ".png"))
* item[1] 匹配出來的路徑 例如:"../../assets/img/" + _vm.filePath + ".png"
* */
const arr = item[1].split('+')
// 組裝獲取文件夾下邊文件的全部路徑
let allFilePath = ''
arr.forEach((itemStr, index) => {
// 去除”和多余的空格
itemStr = itemStr.replace(/"/g, '').trim()
if (index === 0) {
const lastIndex = itemStr.lastIndexOf('/')
allFilePath = insertStr(itemStr, lastIndex + 1, '**/')
} else if (index === arr.length - 1 && itemStr.startsWith('.')) {
allFilePath += itemStr
} else {
allFilePath += '*'
}
})
// 獲取最后一個/的位置
const lastIndex = id.lastIndexOf('/')
// 獲取Id最后一個/之前的全路徑
const absoluteDir = id.substr(0, lastIndex + 1)
// 根絕id的全路徑和相對路徑獲取要去獲取文件的全路徑
// /mnt/c/Users/yangyanhui/projects/huiyan-manage-static/src/assets/img/**/icon_*.png
const readAbsoluteDir = path.join(absoluteDir, allFilePath)
// 拿到所有的指定文件
const allFile = glob.sync(readAbsoluteDir)
const fileObj = `_$_file_obj_${randomString(6)}`
let fileObjectStr = ''
if (allFile.length) {
// 拼接文件常量
fileObjectStr = `const ${fileObj} = {`
allFile.forEach((file, index) => {
// 獲取引入文件的相對路徑
const relativePath = path.relative(absoluteDir, file)
const tempFile = `_$_img_${randomString(6)}`
fileObjectStr += `'${relativePath}': ${tempFile},`
if (index === allFile.length - 1) fileObjectStr += '}'
importString += `import ${tempFile} from '${file}';\n`
})
constObjString += `${fileObjectStr};\n`
// require(("../../assets/img/" + _vm.filePath + ".png")) 用 fileObj 對象替換
code = code.replace(item[0], `${fileObj}[${item[1]}]`)
}
}
code = importString + constObjString + code
return code
}
/**
*
* @param {必填,數字} length
* @returns hash串
*/
function randomString(length) {
const code = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890'
let result = ''
for (let index = 0; index < length; index++) {
result += code[Math.floor(Math.random() * code.length)]
}
return result
}
function insertStr(source, start, newStr) {
return source.slice(0, start) + newStr + source.slice(start)
}
2. 使用插件
import { replaceRequireVariable } from './plugins.js'
export default defineConfig({
plugins: [
replaceRequireVariable(['hyFileStyle.vue?vue&type=template&lang.js']) // 替換 組件里面require加變量的內容
],
})
該插件需要優化,轉發請注明出處。
