为何我们前端从Vue 2迁移到Svelte?


在使用 Vue 2 作为我们的前端框架将近两年之后,宣布不再维护此支持,因此我们决定迁移到一个新的框架。但是选择哪一个:Vue 3 还是 Svelte?

请注意,我们迁移后的目标也是为了改善我们的开发者体验,特别是类型检查、性能和构建时间。我们没有考虑React,因为它需要花费太多时间来学习,而且与Vue和Svelte相比,它没有提供一个开箱即用的解决方案。
Vue和Svelte两者都有相同的单文件组件的概念:逻辑(JavaScript)、结构(HTML)和样式(CSS)在同一个文件中。

因此,我们进行了一些研究,最终选择了Svelte。下面是对原因和方法的解释。

Svelte与Vue 3的比较
Svelte的保留率更好。对于我们的新前端,我们不得不从市场上的两个框架中选择,即Svelte和Vue 3。下面是过去五年中不同框架的保留率(会再次使用/(会再次使用+不会再次使用))的说明。数据是在JS调查领域的开发者中收集的,我们可以看到,Svelte排在第二位,而Vue 3只排在第四位。

这表明,过去使用过Svelte的开发者中,愿意再次使用它的人要比不愿意的人多。

Better typing for Svelte.

                    Vue2    Vue3    Svelte
Component-level typing    Yes    Yes    Yes
Cross-component typing    No    Yes    Yes
Typed events           No    No    Yes

Svelte提供了更好的类型体验,更简单的组件设计过程和内置的类型事件,使其对我们非常友好。

限制性的全局访问。在Svelte中,可以从其他文件中导入枚举,并在模板中使用它们,而Vue 3则没有这样的功能。


语法
就个人而言,我觉得Svelte的语法比Vue更优雅,更方便用户。你可以查看下面的代码块,自己看一下。

Svelte:

<script>
    let firstName = "";
    let town =
"";
    $: fullName =
"Full name: " + firstName + ' ' + lastName;
    const reset = () => {
        firstName =
"";
        lastName =
"";
    }
</script>
<main>
    <div>
        <label>First name</label>
        <input type=
"text" bind:value={firstName}>
        <label>Last name</label>
        <input type=
"text" bind:value={lastName}>
        <button on:click={reset}>Reset</button>
    </div>
    <div>
        {fullName}
    </div>
</main>
<style>
  main{
    background-color: white;
  }
</style>

Vue:

<template>
  <main>
    <label>First name </label>
    <input type="text" v-model="firstName"/>
    <label>Last name </label>
    <input type=
"text" v-model="lastName"/>
    <div>
        Full name: {{fullName}} 
    </div>
    <button @click=
"handleReset">Reset</button>
  </main>
</template>
<script setup>
import { ref, computed } from 'vue'
const firstName = ref('')
const lastName = ref('')

const fullName = computed(() => { return firstName.value +
" " + lastName.value; })

function handleReset() {
    firstName.value =
""
    lastName.value =
""
}
</script>
<style scoped>
main{
  background-color: white;
}
</style>

没有额外的HTML div <template>。在Svelte中,你可以直接编写你自己的HTML。

样式在Svelte中是自动作用域化的,这对维护性来说是个好点,有助于避免CSS的副作用。每个组件的样式都是孤立的,只影响该组件,不影响其父级或子级。

不需要计算属性来更新数据,在Svelte中,感觉更像是用纯javascript编码,你只需要专注于编写一个箭头函数。

const reset = () => {firstName = "";lastName = "";}

在Svelte中,只有单括号是必要的:

//Svelte
{fullName}

//Vue
{{fullName}}

请注意,这个分析是基于上述具体的代码模板,并不打算对框架的差异进行详细解释。如需进一步信息,请随时上网查询。

添加纯js插件更简单。下面是一个使用Svelte和Prism.js的语法高亮集成用例。

// Prism.svelte
<script>
    import Prism from 'prismjs';

    export let code;
    export let lang = 'javascript';
</script>

<pre><code class=
"language-{lang}">{@html
    Prism.highlight(code, Prism.languages[lang], lang)
}</code></pre>
// App.svelte
<script>
    import Prism from './Prism.svelte';
    let code = 'export const hello =\n\t(name) => {console.log(`Hello ${name}!`)};';
</script>

<link rel=
"stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.28.0/themes/prism-dark.min.css" integrity="sha512-Njdz7T/p6Ud1FiTMqH87bzDxaZBsVNebOWmacBjMdgWyeIhUSFU4V52oGwo3sT+ud+lyIE98sS291/zxBfozKw==" crossorigin="anonymous" referrerpolicy="no-referrer" />

<Prism {code} />

编译代码时没有虚拟DOM。Svelte和Vue的主要区别在于减少了浏览器和应用程序之间的层数,这使得任务的完成更加优化和快速。

自动更新。在声明变量的帮助下,Svelte可以自动更新你的数据。这样一来,你就不需要等待变化反映在你的虚拟结构中,从而获得更好的用户体验。

Svelte也有其缺点
当然,Svelte也有缺点,比如说社区相对较小,因为它是在2019年才出现的。但是,随着越来越多的开发者可能会接受它的品质和用户友好的内容,支持以及社区在未来可能会发展和壮大。在Github上已经有定期的和非常好的解释的更新,可以很容易地访问。

因此,在回顾了这一分析结果后,我们决定继续使用Svelte和Svelte Kit,尽管在迁移时SvelteKit仍在积极开发中。(见下文)


我们选择哪种方法来处理迁移?
时间:我们选择在8月进行迁移,当时使用该应用程序的人较少。

时间长度:我们花了两周时间将所有文件从Vue迁移到Svelte。

开发人员的数量:两名前端开发者全职工作了两周,另一名开发者全职工作了一周,所以有三名开发者参与。

工作流程:首先,我们使用Notion工具将我们的票据归属给团队的开发人员。然后,我们开始在Storybook中创建我们的新组件,最后,每个开发人员被赋予一些页面,在Svelte中重写。

作为一家初创公司,迁移比较简单,因为我们没有一千多份文件需要重写,所以我们可以快速执行。然而,我们冒着风险,在SvelteKit还在积极开发的时候就开始迁移,这导致我们在迁移后一个月才不得不做出重大的改变。但是SvelteKit专业的知识团队为我们提供了一个命令(npx svelte-migrate routes)和一个解释得非常清楚的迁移指南,真正帮助我们快速适应新的更新。

此外,在9月份,SvelteKit团队宣布,该框架终于进入了候选发布阶段,这意味着它的稳定性得到了保证。