对于已经在使用 Vue 3 的团队来说,Lyt.js 的吸引点在于更小的包体积(约 35KB vs Vue 3 的 44KB)、可选的 Signal 模式以及未来无 VDOM 的 Vapor 模式。Lyt.js 的 API 设计大量借鉴了 Vue 3,迁移成本比想象中低很多。以下从安装到路由的整套迁移流程,附带代码对比和注意事项。
## 一、核心 API 对比概览
| 概念 | Vue 3 | Lyt.js |
|---|---|---|
| 创建应用 | createApp(App) | createApp(App) |
| 定义组件 | defineComponent({...}) | defineComponent({...}) |
| 响应式数据 | reactive() / ref() | reactive() / signal() |
| 计算属性 | computed(() => ...) | computed(() => ...) |
| 侦听器 | watch() / watchEffect() | watch() / effect() |
| 生命周期 | onMounted() 等 | onMounted() 等 |
| 挂载 | app.mount('#app') | app.mount('#app') |
主要区别:ref() 在 Lyt.js 中对应 signal()(Signal 模式),如果使用 Proxy 模式则 reactive() 用法一致。
## 二、迁移步骤
### 1. 安装与卸载
- # 卸载 Vue 相关包
- npm uninstall vue @vue/compiler-sfc @vue/runtime-dom
- # 安装 Lyt.js(无需额外安装 SFC 编译器,框架内置)
- npm install @lytjs/core
复制代码
Lyt.js 包结构更简洁,不需要 @vue/compiler-sfc 等额外依赖。
### 2. 修改入口文件
将 import 来源从 'vue' 改为 '@lytjs/core',文件后缀从 .vue 改为 .lyt。
- // Vue 3 入口
- import { createApp } from 'vue'
- import App from './App.vue'
- createApp(App).mount('#app')
- // Lyt.js 入口
- import { createApp } from '@lytjs/core'
- import App from './App.lyt'
- createApp(App).mount('#app')
复制代码
### 3. 模板语法迁移
这是改动最大的部分,但模式统一:去掉 v- 前缀和 @ 符号,使用更统一的关键字。
| 功能 | Vue 3 | Lyt.js |
|---|---|---|
| 条件渲染 | v-if / v-else-if / v-else | if / else-if / else |
| 列表渲染 | v-for="item in list" | each="item in list" |
| 双向绑定 | v-model="value" | model="value" |
| 事件绑定 | @click="handle" | on:click="handle" |
| 属性绑定 | :class="cls" | :class="cls"(不变) |
| 插槽 | <slot /> | <slot />(不变) |
| 组件引用 | <MyComponent /> | <MyComponent />(不变) |
示例:
- <!-- Vue 3 写法 -->
- <div class="container">
- <input v-model="searchText" placeholder="Search..." />
- <button @click="search">Search</button>
- <ul v-if="results.length > 0">
- <li v-for="item in results" :key="item.id"
- :class="{ active: item.active }"
- @click="select(item)">
- {{ item.name }}
- </li>
- </ul>
- <p v-else>No results found.</p>
- </div>
- <!-- Lyt.js 写法 -->
- <div class="container">
- <input model="searchText" placeholder="Search..." />
- <button on:click="search">Search</button>
- <ul if="results.length > 0">
- <li each="item in results" :key="item.id"
- :class="{ active: item.active }"
- on:click="select(item)">
- {{ item.name }}
- </li>
- </ul>
- <p else>No results found.</p>
- </div>
复制代码
改动点:v-if → if,v-for → each,@click → on:click,v-model → model。
### 4. 组件定义(Options API)
唯一变化:data() 改为 state()。
- // Vue 3
- import { defineComponent } from 'vue'
- export default defineComponent({
- name: 'MyComponent',
- props: { title: String },
- emits: ['update'],
- data() { return { count: 0 } },
- computed: {
- double() { return this.count * 2 }
- },
- methods: {
- increment() { this.count++; this.$emit('update') }
- },
- mounted() { console.log('mounted') }
- })
- // Lyt.js
- import { defineComponent } from '@lytjs/core'
- export default defineComponent({
- name: 'MyComponent',
- props: { title: String },
- emits: ['update'],
- state() { return { count: 0 } }, // data → state
- computed: {
- double() { return this.count * 2 }
- },
- methods: {
- increment() { this.count++; this.$emit('update') }
- },
- mounted() { console.log('mounted') }
- })
复制代码
### 5. Composition API 迁移
使用 Proxy 模式时,只需将 ref() 换成 reactive(),并注意从 @lytjs/core 导入。
- // Vue 3 Composition API
- import { ref, computed, onMounted } from 'vue'
- export default {
- setup() {
- const count = ref(0)
- const double = computed(() => count.value * 2)
- const increment = () => count.value++
- onMounted(() => console.log('mounted'))
- return { count, double, increment }
- }
- }
- // Lyt.js (Proxy 模式)
- import { reactive, computed, onMounted } from '@lytjs/core'
- export default {
- setup() {
- const state = reactive({ count: 0 })
- const double = computed(() => state.count * 2)
- const increment = () => state.count++
- onMounted(() => console.log('mounted'))
- return { ...state, double, increment }
- }
- }
复制代码
若想使用 Lyt.js 提供的 Signal 模式(性能敏感场景推荐):
- // Lyt.js (Signal 模式)
- import { signal, computed, effect } from '@lytjs/reactivity/signal'
- export default {
- setup() {
- const count = signal(0)
- const double = computed(() => count() * 2)
- const increment = () => count.update(n => n + 1)
- effect(() => console.log('mounted'))
- return { count, double, increment }
- }
- }
复制代码
注意:Signal 模式下 count 是一个函数,调用 count() 获取值,通过 update 方法更新。
### 6. 路由迁移
Lyt.js 内置 router 模块,API 与 Vue Router 几乎一致。
- // Vue Router
- import { createRouter, createWebHistory } from 'vue-router'
- const router = createRouter({
- history: createWebHistory(),
- routes: [{ path: '/', component: Home }]
- })
- // Lyt.js Router
- import { createRouter, createWebHistory } from '@lytjs/router'
- const router = createRouter({
- history: createWebHistory(),
- routes: [{ path: '/', component: Home }]
- })
复制代码
## 三、迁移检查清单
- 入口文件:import 从 'vue' 改为 '@lytjs/core'
- 文件后缀:.vue → .lyt
- 模板指令:v-if → if, v-for → each, v-model → model, @click → on:click
- 组件选项:data() → state()
- Composition API:ref() → reactive() 或 signal()
- 路由:vue-router → @lytjs/router
- 构建工具:Vite 插件从 @vitejs/plugin-vue 改为 Lyt.js 编译器
- TypeScript:使用 Lyt.js VSCode 扩展获得 .lyt 文件类型支持
## 四、迁移后的收益
- 包体积减少约 20%(~35KB vs ~44KB,含编译器)
- 可切换到 Signal 模式提升性能敏感组件
- 未来可启用 Vapor Mode(无 VDOM 渲染)
- 零第三方依赖,降低安全风险
- 模板语法更简洁
## 五、常见问题解答
Q: Vuex/Pinia 状态管理怎么迁移?
A: Lyt.js 内置 provide/inject 结合 reactive/signal 即可实现全局状态管理。复杂场景参考官方文档中的状态管理最佳实践。
Q: Vue 生态 UI 库(如 Element Plus、Ant Design Vue)能用吗?
A: 目前不能直接使用。但 Lyt.js 模板语法与 HTML 完全兼容,可以使用任何原生 HTML/CSS 方案,或等待社区适配。
Q: SSR 怎么迁移?
A: Lyt.js 内置 SSR 渲染器,API 类似 Vue 3。主要调整服务端入口文件,客户端 hydrate 逻辑基本一致。
Q: 遇到问题怎么办?
A: Lyt.js 提供 VitePress 文档站,可以在 GitHub 或 Gitee 仓库提交 Issue。
## 六、总结
从 Vue 3 迁移到 Lyt.js 主要涉及三点修改:import 路径变更、模板指令简化(去掉 v- 前缀)、data() 改为 state()。其余 API、开发模式、组件化思想完全一致,熟悉 Vue 3 的开发者通常只需要几小时即可完成。迁移后获得零依赖架构和 Signal/Vapor 性能加成,对新建项目或需要精简体积的项目来说是值得的选择。 |