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.
 
 
 
 
 
 

135 lines
4.3 KiB

// 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)
}
}