You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
136 lines
4.3 KiB
136 lines
4.3 KiB
3 days ago
|
// Vue Add Attribute Loader
|
||
|
// 用于在构建时为Vue文件的button标签添加name属性和权限控制属性
|
||
|
|
||
|
const { parse, compileTemplate } = require('@vue/compiler-sfc')
|
||
|
|
||
|
module.exports = function(source) {
|
||
|
const callback = this.async()
|
||
|
|
||
|
|
||
|
try {
|
||
|
// 解析Vue文件
|
||
|
const { descriptor } = parse(source, { filename: this.resourcePath })
|
||
|
|
||
|
|
||
|
if (!descriptor.template || !descriptor.template.ast) {
|
||
|
// 如果没有template,直接返回原内容
|
||
|
return callback(null, source)
|
||
|
}
|
||
|
|
||
|
let modified = false
|
||
|
|
||
|
// 遍历AST,找到button节点并添加属性
|
||
|
const addAttributesToButton = (node) => {
|
||
|
if (node.type === 1 && node.tag === 'button') {
|
||
|
// 检查是否已经有name属性
|
||
|
const hasNameAttr = node.props.some(prop =>
|
||
|
prop.type === 6 && prop.name === 'name'
|
||
|
)
|
||
|
|
||
|
if (!hasNameAttr) {
|
||
|
// 生成唯一的name值
|
||
|
const componentName = this.resourcePath.split('/').pop().replace('.vue', '').toLowerCase()
|
||
|
const uniqueSuffix = Math.random().toString(36).substr(2, 6)
|
||
|
const nameValue = `${componentName}-${uniqueSuffix}`
|
||
|
|
||
|
// 添加name属性
|
||
|
node.props.push({
|
||
|
type: 6,
|
||
|
name: 'name',
|
||
|
value: {
|
||
|
type: 2,
|
||
|
content: nameValue,
|
||
|
loc: node.loc
|
||
|
},
|
||
|
loc: node.loc
|
||
|
})
|
||
|
|
||
|
// 检查是否已经有v-permission-control指令
|
||
|
const hasPermissionControl = node.props.some(prop =>
|
||
|
prop.type === 7 && prop.name === 'v-permission-control'
|
||
|
)
|
||
|
|
||
|
if (!hasPermissionControl) {
|
||
|
// 添加v-permission-control指令(不添加:disabled,避免重复)
|
||
|
node.props.push({
|
||
|
type: 7,
|
||
|
name: 'v-permission-control',
|
||
|
exp: {
|
||
|
type: 4,
|
||
|
content: 'true',
|
||
|
isStatic: false,
|
||
|
loc: node.loc
|
||
|
},
|
||
|
loc: node.loc
|
||
|
})
|
||
|
}
|
||
|
|
||
|
modified = true
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 递归处理子节点
|
||
|
if (node.children) {
|
||
|
node.children.forEach(addAttributesToButton)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 开始遍历AST
|
||
|
addAttributesToButton(descriptor.template.ast)
|
||
|
|
||
|
// 如果修改了AST,重新生成Vue文件
|
||
|
if (modified) {
|
||
|
// 由于Vue编译器没有直接的AST到字符串转换,我们使用字符串替换的方式
|
||
|
// 先找到template部分
|
||
|
const templateMatch = source.match(/(<template[^>]*>)([\s\S]*?)(<\/template>)/)
|
||
|
if (templateMatch) {
|
||
|
let templateContent = templateMatch[2]
|
||
|
|
||
|
// 为每个button添加属性(使用字符串替换)
|
||
|
templateContent = templateContent.replace(
|
||
|
/<button([^>]*?)(\s*\/?>)/g,
|
||
|
(match, attrs, closing) => {
|
||
|
// 检查是否已经有name属性
|
||
|
if (attrs.includes('name=')) {
|
||
|
return match // 已经有name属性,不修改
|
||
|
}
|
||
|
|
||
|
// 生成唯一的name值
|
||
|
const componentName = this.resourcePath.split('/').pop().replace('.vue', '').toLowerCase()
|
||
|
const uniqueSuffix = Math.random().toString(36).substr(2, 6)
|
||
|
const nameValue = `${componentName}-${uniqueSuffix}`
|
||
|
|
||
|
// 检查是否已经有v-permission-control指令
|
||
|
const hasPermissionControl = attrs.includes('v-permission-control')
|
||
|
|
||
|
// 构建新的属性字符串
|
||
|
let newAttrs = attrs
|
||
|
newAttrs += ` name="${nameValue}"`
|
||
|
if (!hasPermissionControl) {
|
||
|
newAttrs += ` v-permission-control`
|
||
|
}
|
||
|
|
||
|
|
||
|
return `<button${newAttrs}${closing}`
|
||
|
}
|
||
|
)
|
||
|
|
||
|
// 替换原文件中的template部分
|
||
|
const newSource = source.replace(
|
||
|
templateMatch[0],
|
||
|
`${templateMatch[1]}${templateContent}${templateMatch[3]}`
|
||
|
)
|
||
|
return callback(null, newSource)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 如果没有修改,返回原内容
|
||
|
callback(null, source)
|
||
|
|
||
|
} catch (error) {
|
||
|
console.warn(`[Vue Add Attr Loader] 处理文件时出错:`, error.message)
|
||
|
// 出错时返回原内容
|
||
|
callback(null, source)
|
||
|
}
|
||
|
}
|