AI取名大师 | 使得 uni-app 兼容 vue3 同名简写语法糖的 vite 插件

101 阅读2分钟

关于 AI 取名大师

借助豆包通义千问DeepSeek 等 AI 大模型,为您的宝宝、宠物、店铺、网名、笔名、项目、产品、服务、文章等取一个专业、有意义的名字😄。


开源地址:👉GitCode(国内友好)👈、👉GitHub👈 技术组合:Bun.jsElysia.jsuni-app 体验地址:AI取名大师(H5版)、小程序搜索取名大师


特别注明:本系列文章仅为实战经验分享,并记录开发过程中碰到的问题😄,如有不足之处欢迎随时留言提出。


📣 同名简写语法

这是 vue 3.4+ 后更新的语法糖,如果属性名变量名完全一致,Vue 允许你简写,详见官方文档

写法等价
v-bind:text="text"完整写法
:text="text"v-bind 简写
:text同名简写(implicit value)

示例:

<script setup>
	const message = "Hello";
	const active = true;
</script>

<template>
  	<Comp :message :active />
	<!--甚至可以这样写-->
	<Comp v-bind="{ message, active }" />
</template>

😔 在小程序中不支持

同名简写语法,用过就觉得很香,习惯后怎么舍得改回来。可惜小程序(尤其是微信小程序)不支持该语法糖,使得编译不通过,只能一个个把同名简写改成传统模式😔。

🔧 搞一个插件

功能

专门为 uni-app 修补 Vue3 同名简写,就是 Vue SFC 进入 uni-app 小程序编译之前,用一个自定义 Vite 插件把 :text 自动转换为 :text="text"

原理简介

  • Vue 编译器对 :text 是合法的,因为它是 Vue3 的同名简写;
  • uni-app 的小程序编译器(特别是微信)不支持,会报错;
  • 我们可以在 Vite 阶段 预处理 .vue 文件的 template 源码:
    • 找到所有 :<attr> 且没有 = 的情况;
    • 转换成 :<attr>="<attr>"

设计原则

  • ✔ 只处理 <template> 部分,绝不误伤 <script><style>
  • ✔ 兼容 Vue SFC、uni-app 的编译链
  • ✔ 兼容 Vite 5.x+(用 enforce: 'pre' 和新插件格式)
  • ✔ 支持各种属性写法(kebab-case、camelCase、数字、下划线)
  • ✔ 绝不匹配已有 = 的属性(如 :text="xxx" 不会变)
  • ✔ 支持自闭合标签 <Comp :xx />

代码实现

import pc from 'picocolors'

export default function UniExpandVueBind(debug=true) {
    debug && console.debug(`使用 vue3 ${pc.magenta("同名简写")}扩展插件 ^.^`)
    return {
        name: 'uni-expand-vue-bind',
        enforce: 'pre', // 在其它处理前执行,避免被 Vue 编译器提前处理

        transform(code, id) {
            if (!id.endsWith('.vue')) return

            // 提取 <template> 内容
            const templateMatch = code.match(/<template[^>]*>([\s\S]*?)<\/template>/)
            if (!templateMatch) return

            const template = templateMatch[1]

            // 匹配同名简写的 :prop
            // 条件:
            //   1. 以 :prop 开头
            //   2. prop 支持字母、数字、下划线、短横线
            //   3. 后面紧接空白或 > 或 />
            //   4. 不能有等号(不处理 :prop="xxx")
            const pattern = /:([a-zA-Z_][\w-]*)\s*(?=[\s>/])/g

            let count = 0
            // 替换同名简写
            const expanded = template.replace(pattern, (match, attr) => {
                count ++
                return `:${attr}="${attr}"`
            })

            // 把展开后的 template 写回原代码
            const newCode = code.replace(
                /<template[^>]*>[\s\S]*?<\/template>/,
                `<template>\n${expanded}\n</template>`
            )
            if(debug && count){
                console.debug(`处理 ${pc.gray(id)} 替换 ${pc.magenta(count)} 个绑定...`)
            }

            return {
                code: newCode,
                map: null
            }
        }
    }
}

如何使用

// vite.config.js
import UniExpandVueBind from './script/plugin-expand-vue3-blind.js'

export default {
  plugins: [
  		//仅当非 h5 编译时才启用
  		process.env.UNI_PLATFORM != 'h5' && UniExpandVueBind(),
  		Uni(),
  ]
};