Vue 3 组件开发中的"双脚本"困境

一目拾贝

  1. 缘起:一个真实的开发困扰
  2. 背景:Vue 3 的两种组件写法
  3. 核心问题:为什么想要"双脚本"?
  4. 技术现状:不同构建工具的差异
  5. 解决方案:因地制宜的选择
  6. 最佳实践:推荐的工作流
  7. 小结与总结

缘起:一个真实的开发困扰

最近在 Vue 3 项目中遇到一个有趣的问题:想要在同一个 .vue 文件中同时使用 <script setup> 的简洁语法和普通 <script> 的组件选项,就像这样:

js 复制代码
<script setup>
// 响应式数据、方法等逻辑
const count = ref(0)
const increment = () => count.value++
</script>
<script>
export default {
  name: 'MyComponent',
  components: {
    CustomButton: () => import('./CustomButton.vue')
  }
}
</script>

这个想法听起来很美好,但现实却给了我们当头一棒。

背景:Vue 3 的两种组件写法

Vue 3 为我们提供了两种组件编写方式:

选项式 API(Options API)

js 复制代码
<script>
export default {
  name: 'MyComponent',
  data() {
    return { count: 0 }
  },
  methods: {
    increment() {
      this.count++
    }
  }
}
</script>

组合式 API + <script setup>

js 复制代码
<script setup>
import { ref } from 'vue'
const count = ref(0)
const increment = () => count.value++
</script>

核心问题:为什么想要"双脚本"?

开发者们想要"双脚本"的原因其实很实际:

  1. 组件命名需求<script setup> 默认无法设置组件名,而组件名在调试、DevTools 中很重要
  2. 组件注册:某些场景下需要手动注册子组件,如别名 或 变量命名组件
js 复制代码
import { Select, SelectOption, PageHeader, Tag, Button } from 'ant-design-vue'
...
components: {
    // 别名
    'a-select': Select,
    'a-select-option': SelectOption,
    // 变量命名组件
    [PageHeader.name]: PageHeader,
    [Tag.name]: Tag,
    [Button.name]: Button
  }
  1. 渐进式迁移:从选项式 API 迁移到组合式 API 时的过渡需求
  2. 团队协作:不同开发者习惯不同写法

技术现状:不同构建工具的差异

这里有个关键问题:你的构建工具决定了能否实现"双脚本"

Vite 项目:有解决方案

如果你用的是 Vite,恭喜你!有一个专门的插件:vite-plugin-vue-setup-extend

arduino 复制代码
npm install vite-plugin-vue-setup-extend --save-dev

vite.config.ts 中配置:

js 复制代码
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueSetupExtend from 'vite-plugin-vue-setup-extend'

export default defineConfig({
  plugins: [
    vue(),
    vueSetupExtend()
  ]
})

然后你就可以愉快地写"双脚本"了:

js 复制代码
<script setup>
const count = ref(0)
</script>
<script>
export default {
  name: 'MyComponent'
}
</script>

Vue CLI 项目:无解

如果你用的是 Vue CLI(基于 Webpack),很遗憾😭,目前没有官方或社区插件支持这种写法

Vue CLI 项目只能二选一:

  • 要么用 <script setup>
  • 要么用普通 <script>

解决方案:因地制宜的选择

方案一:升级到 Vue 3.3+ 使用 defineOptions

如果你的 Vue 版本是 3.3 及以上,可以使用 defineOptions

js 复制代码
<script setup>
defineOptions({
  name: 'MyComponent',
  components: {
    CustomButton: () => import('./CustomButton.vue')
  }
})

const count = ref(0)
</script>

方案二:迁移到 Vite

如果项目允许,考虑从 Vue CLI 迁移到 Vite:

  1. 安装 Vite 相关依赖
  2. 创建 vite.config.ts
  3. 配置 vite-plugin-vue-setup-extend
  4. 享受"双脚本"的便利

方案三:统一使用一种写法

最稳妥的方案是统一团队代码风格:

推荐:纯 <script setup>

js 复制代码
<script setup>
// 组件名通过文件名或目录结构体现
// 子组件直接 import 使用,无需注册
import CustomButton from './CustomButton.vue'
const count = ref(0)
</script>

最佳实践:推荐的工作流

基于实际项目经验,我推荐这样的工作流:

  1. 新项目 :直接使用 Vite + <script setup> + defineOptions
  2. 老项目 :逐步迁移到 <script setup>,统一代码风格
  3. 团队规范:制定明确的组件编写规范,避免混用

小结

要点梳理:

  • Vue 3 的"双脚本"需求源于实际开发中的命名和注册需求
  • Vite 项目可以通过 vite-plugin-vue-setup-extend 实现
  • Vue CLI 项目目前无法实现,需要选择单一写法
  • Vue 3.3+ 的 defineOptions 提供了官方解决方案
  • 统一代码风格比追求"双脚本"更重要

总结

Vue 3 的"双脚本"需求反映了开发者对灵活性的追求,但技术实现受限于构建工具。与其纠结于语法糖的混用,不如专注于代码的可维护性和团队协作效率。

在实际项目中,统一的代码风格和清晰的组件结构往往比语法糖的便利性更重要。选择适合你项目的方案,保持代码的一致性,这才是真正的最佳实践。

记住:技术是为了解决问题,而不是制造问题。选择简单有效的方案,往往比追求复杂的"完美"解决方案更实用。

相关推荐
咬人喵喵18 小时前
CSS Flexbox:拥有魔法的排版盒子
前端·css
LYFlied18 小时前
TS-Loader 源码解析与自定义 Webpack Loader 开发指南
前端·webpack·node.js·编译·打包
yzp011218 小时前
css收集
前端·css
暴富的Tdy18 小时前
【Webpack 的核心应用场景】
前端·webpack·node.js
遇见很ok18 小时前
Web Worker
前端·javascript·vue.js
风舞红枫18 小时前
前端可配置权限规则案例
前端
前端不太难18 小时前
RN Navigation vs Vue Router:从架构底层到工程实践的深度对比
javascript·vue.js·架构
zhougl99618 小时前
前端模块化
前端
暴富暴富暴富啦啦啦18 小时前
Map 缓存和拿取
前端·javascript·缓存
天问一18 小时前
前端Vue使用js-audio-plugin实现录音功能
前端·javascript·vue.js