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