SODA Engineering Blog
😊

Vueからの移行に最適な選択肢 [React][Svelte]

2024/12/05に公開

\スニダンを開発しているSODA inc.の Advent Calendar 2024 5日目の記事です!!!/

こんにちは、Mapleといいます。
「Vueからの移行に最適な選択肢」解説していきます!


Vue.jsから他のフレームワークへの移行を検討している開発者やチームにとって、その選択はプロダクトの今後を左右します。。。
一般的にはReactとそのフレームワークであるNext.jsが候補に挙がりますが、これらはエコシステムの複雑さ学習コストが高くなる可能性があります。
一方で、Svelte/SvelteKitは軽量でコスト効率の高い選択肢として注目を集めています。
RealWorldやjs-framework-benchmarkで、Lighthouseのスコア、サイズ、コード量の少なさでReactやVueより優れているという結果が出ています。
本記事では、具体的なコード例を交えながら、Svelte/SvelteKitとNext.jsを比較し、その利点を解説します!

1. 学習曲線の緩やかさ

Svelteのシンプルな構文

Vue.jsのコンポーネント例

<template>
  <div>
    <h1>{{ message }}</h1>
    <button @click="increment">カウントアップ</button>
    <p>カウント: {{ count }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: 'こんにちは、Vue!',
      count: 0
    };
  },
  methods: {
    increment() {
      this.count++;
    }
  }
};
</script>

Svelteへの移行後のコンポーネント例

<script>
  let message = 'こんにちは、Svelte!';
  let count = 0;

  function increment() {
    count += 1;
  }
</script>

<div>
  <h1>{message}</h1>
  <button on:click={increment}>カウントアップ</button>
  <p>カウント: {count}</p>
</div>

Next.js(React)のコンポーネント例

import { useState } from 'react';

export default function Home() {
  const [message] = useState('こんにちは、React!');
  const [count, setCount] = useState(0);

  function increment() {
    setCount(count + 1);
  }

  return (
    <div>
      <h1>{message}</h1>
      <button onClick={increment}>カウントアップ</button>
      <p>カウント: {count}</p>
    </div>
  );
}

ポイント:

  • テンプレート構文の類似性:VueからSvelteへの移行は構文が似ており、学習コストが低い。
  • React/Next.jsのJSX構文:HTMLとJavaScriptが混在するJSXを学ぶ必要があり、Vue開発者には新しい概念です。

2. 軽量で高速なパフォーマンス

バンドルサイズの比較

バンドルサイズの比較例(同等の機能を持つアプリケーションの場合):

  • Svelte/SvelteKit:5KB〜(アプリケーションコードのみ)

  • Next.js:50KB以上(ReactとNext.jsのコアライブラリ+アプリケーションコード)
    ポイント:)

  • 初期ロード時間の短縮:Svelteの方がバンドルサイズが小さく、UXが向上。

  • サーバーコストの削減:軽量なバンドルはサーバー帯域幅を節約。

3. コスト削減につながる要因

開発効率と学習コスト

Svelte/SvelteKit:

  • 直感的な開発:Vueに似た構文で、特殊な学習が不要。
  • 統合されたフレームワーク:ルーティングや状態管理がシンプル。

Next.js:

  • Reactの学習が必要:JSXやフックなど、新たな概念を理解する必要がある。
  • エコシステムの複雑さ:状態管理にReduxやZustandなどのライブラリを導入する場合が多い。

ポイント:

  • 開発時間の短縮:Svelte/SvelteKitはシンプルな構造で、学習と開発にかかる時間を削減。
  • ライブラリの削減:追加のライブラリが少なく、依存関係が減るため、メンテナンスコストも低下。

4. フルスタック機能の比較

ルーティングとページ生成

SvelteKitでのルート定義

src/routes/
├── +page.svelte        // '/'
├── about/
│   └── +page.svelte    // '/about'
└── blog/
    ├── +page.svelte    // '/blog'
    └── [slug]/
        └── +page.svelte // '/blog/[slug]'

Next.jsでのルート定義

pages/
├── index.js            // '/'
├── about.js            // '/about'
└── blog/
    ├── index.js        // '/blog'
    └── [slug].js       // '/blog/[slug]'

ポイント:

  • ファイルベースのルーティング:どちらも対応しており、直感的にページを追加可能。
  • 動的ルーティングの簡易性:両者ともに[slug]のようなシンタックスで動的パラメータを扱える。

データフェッチとサーバーサイドレンダリング

SvelteKitでのデータフェッチ

<script>
  export let data;
</script>

<svelte:head>
  <title>{data.title}</title>
</svelte:head>

<div>
  <h1>{data.title}</h1>
  <p>{data.content}</p>
</div>

<script context="server">
  export async function load({ params }) {
    const res = await fetch(`https://api.example.com/posts/${params.slug}`);
    const data = await res.json();
    return { props: { data } };
  }
</script>

Next.jsでのデータフェッチ

export async function getServerSideProps({ params }) {
  const res = await fetch(`https://api.example.com/posts/${params.slug}`);
  const data = await res.json();
  return { props: { data } };
}

export default function Post({ data }) {
  return (
    <>
      <Head>
        <title>{data.title}</title>
      </Head>
      <div>
        <h1>{data.title}</h1>
        <p>{data.content}</p>
      </div>
    </>
  );
}

ポイント:

  • データフェッチの類似性:両者ともサーバーサイドでデータを取得し、ページに渡す仕組みがある。
  • コードの複雑さ:SvelteKitはサーバーコードとクライアントコードを同一ファイル内で明確に区別できる。

5. 状態管理の比較

グローバルな状態管理

Svelteのストアを使用した状態管理

// store.js
import { writable } from 'svelte/store';

export const count = writable(0);
<!-- 任意のコンポーネント -->
<script>
  import { count } from './store.js';

  function increment() {
    count.update(n => n + 1);
  }
</script>

<button on:click={increment}>カウントアップ</button>
<p>カウント: {$count}</p>

Next.js(React)の状態管理(useContextとuseReducerの使用)

// CountContext.js
import { createContext, useReducer } from 'react';

const CountContext = createContext();

function countReducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    default:
      throw new Error();
  }
}

export function CountProvider({ children }) {
  const [state, dispatch] = useReducer(countReducer, { count: 0 });
  return (
    <CountContext.Provider value={{ state, dispatch }}>
      {children}
    </CountContext.Provider>
  );
}

export default CountContext;
// 任意のコンポーネント
import { useContext } from 'react';
import CountContext from './CountContext';

export default function Counter() {
  const { state, dispatch } = useContext(CountContext);

  function increment() {
    dispatch({ type: 'increment' });
  }

  return (
    <>
      <button onClick={increment}>カウントアップ</button>
      <p>カウント: {state.count}</p>
    </>
  );
}

ポイント:

  • Svelteの方がシンプル:組み込みのストア機能で状態管理が容易。
  • React/Next.jsは複雑:状態管理のためにContextやReducerなどを理解し、実装する必要がある。

まとめ

Vue.jsからの移行を考える際、Svelte/SvelteKitとNext.jsはそれぞれに強みがあります。しかし、学習コスト、開発効率、パフォーマンス、を考慮するとSvelteに軍配があがるのではないかと考え始めている今日この頃です。

特に、Vueに似た構文やシンプルな状態管理、軽量なバンドルサイズなどは良いですね。
一方で、Next.jsのエコシステムや豊富なリソースも魅力的ですが、その複雑さがデメリットとなる場合もあります。

プロジェクトの要件やチームのスキルセットを考慮し、Svelte/SvelteKitへの移行を検討してみてはいかがでしょうか!!

SODA Engineering Blog
SODA Engineering Blog

Discussion