Skip to content

Vueで使う ​

@tuvix.js/vueはVue 3のルートコンポーネントをマイクロアプリに変換し、サーバーレンダリングされたマークアップをハイドレートし、サーバーでコンポーネントをHTMLにレンダリングします。

インストール ​

bash
pnpm add @tuvix.js/vue vue
# for renderVueToString on the server
pnpm add @vue/server-renderer

コンポーネントをマイクロアプリにする ​

ts
// src/main.ts
import { createVueMicroApp } from '@tuvix.js/vue';
import { createPinia } from 'pinia';
import { analytics } from './analytics-plugin';
import App from './App.vue';

export default createVueMicroApp({
  name: 'settings',
  App,
  plugins: [createPinia(), [analytics, { id: 'G-123' }]],
});
オプション型説明
namestring必須。登録したアプリ名と一致する必要があります。
AppComponent必須。ルートコンポーネント。
pluginsArray<Plugin | [Plugin, ...options]>マウントのたびにapp.use(plugin, ...options)でインストールされます。
bootstrap() => void | Promise<void>最初のマウントの前に1回実行されます。
ssrbooleanサーバーのマークアップをハイドレートします。createSsrVueMicroAppはこれを設定します。

コンテナごとに専用のVueアプリが作成されるため、マウントのたびに各プラグインのinstallが再度実行されます。createPinia()のようなプラグインのインスタンスは、そのモジュールのすべてのマウントで共有されます。マウントごとに専用のストアが必要な場合は、プラグイン関数の中でインスタンスを作成します。

すでにこのアプリを持つコンテナにマウントすると、まず古いインスタンスをアンマウントします。unmountはアプリを破棄し、コンテナを空にしてtuvix:unmountedをディスパッチします。

プロパティ ​

アダプターはプロパティをルートコンポーネントに渡し、さらに任意の子孫コンポーネント向けに'tuvixProps'(TUVIX_PROPS_KEY)としてprovideします。

vue
<!-- App.vue -->
<script setup lang="ts">
import { inject } from 'vue';
import { TUVIX_PROPS_KEY } from '@tuvix.js/vue';

defineProps<{ userId: string; theme?: 'light' | 'dark' }>();

const all = inject<Record<string, unknown>>(TUVIX_PROPS_KEY);
</script>

<template>
  <div :class="theme">User {{ userId }} ({{ Object.keys(all ?? {}).length }} props)</div>
</template>

update({ props })はshallowReactiveオブジェクト内のプロパティを置き換え、Vueの次のtickを待ちます。ルートコンポーネントは新しい値で再レンダリングされ、ローカルの状態は維持されます。新しいプロパティにないキーは削除されます。containerを指定しない場合、updateはモジュールのすべてのマウントを更新します。

ts
import { createOrchestrator } from '@tuvix.js/core';

const orchestrator = createOrchestrator();
await orchestrator.updateAppProps('settings', { theme: 'dark' });

サーバーレンダリングとハイドレーション ​

サーバーではrenderVueToStringでレンダリングし、クライアントではcreateSsrVueMicroAppでハイドレートします。

ts
// server-only module
import { renderVueToString } from '@tuvix.js/vue/server';
import Newsletter from './Newsletter.vue';

export async function renderNewsletter(list: string): Promise<string> {
  const ssrContext: { teleports?: Record<string, string> } = {};
  const html = await renderVueToString(Newsletter, { list }, [], ssrContext);
  return html; // ssrContext.teleports holds <Teleport> output
}
ts
// client
import { createSsrVueMicroApp } from '@tuvix.js/vue';
import Newsletter from './Newsletter.vue';

export const newsletter = createSsrVueMicroApp({ name: 'newsletter', App: Newsletter });
  • renderVueToString(App, props?, plugins?, ssrContext?)は、クライアントと同じルートでAppをラップします。そのため、サーバーでもinject('tuvixProps')が動作し、ハイドレーションが一致します。
  • サーバーのコード(サーバー関数、APIルート、またはサーバーエントリー)からのみ呼び出します。ブラウザーでは''を返します。アイソモーフィックなルートローダーはブラウザーでも実行されるため、その場合バンドラーはVueのサーバーレンダラーをクライアントに配布してしまいます。
  • ssr: trueでコンテナにサーバーのマークアップがある場合、アダプターはcreateSSRAppを呼び出し、サーバーのDOMノードを維持します。空のコンテナはcreateAppで新規にレンダリングされます。
  • HTMLにはCSSが含まれません。ViteはSFCの<style>ブロックをJavaScriptから注入し、それはハイドレーションの開始後になります。@tuvix.js/viteで<head>にスタイルシートをリンクします。SSRアイランドを参照してください。

Reactホスト内では、TuvixIslandでモジュールをマウントします。

コンポーザブル ​

useTuvixBus ​

vue
<script setup lang="ts">
import { ref } from 'vue';
import { getGlobalBus } from '@tuvix.js/event-bus';
import { useTuvixBus } from '@tuvix.js/vue';

const count = ref(0);
useTuvixBus<{ itemCount: number }>(getGlobalBus(), 'cart:updated', ({ itemCount }) => {
  count.value = itemCount;
});
</script>

<template>
  <span class="badge">{{ count }}</span>
</template>

onMountedで購読し、onUnmountedで購読を解除し、早期にクリーンアップするための関数を返します。

useTuvixProps ​

useTuvixProps(initialProps, bus?, updateEvent = 'tuvix:props:update')は、updateEventで発行された各ペイロードをマージするShallowRefを返します。Tuvix.jsにこのイベントを発行する処理はありません。アダプターを使う場合、updateAppPropsで渡したプロパティはすでにコンポーネントを再レンダリングするため、これが必要になることはほとんどありません。

エッジケース ​

  • ~/utilsのようなパスエイリアスは、.vueファイル内でも解決できる必要があります。エイリアスがvite-tsconfig-pathsから来ている場合は、そのtsconfigのincludeに**/*.vueを含めるか、Viteの設定でresolve.aliasを設定します。トラブルシューティングを参照してください。
  • マウント中のsetup、render、ライフサイクルフックのエラーは、本番ビルドでもmountをrejectし、tuvix:errorをディスパッチします。プラグイン自身のapp.config.errorHandlerも引き続き実行されます。
  • このモジュールがマウントしたことのないコンテナに対するunmountは何もしません。

API ​

エクスポート用途
createVueMicroApp({ name, App, plugins?, bootstrap?, ssr? })Vueマイクロアプリのモジュール
createSsrVueMicroApp({ name, App, plugins?, bootstrap? })ssr: trueを設定した同等のもの
TUVIX_PROPS_KEYリアクティブなプロパティのインジェクションキー('tuvixProps')
useTuvixBus(bus, event, handler)コンポーネントに紐づいたイベントバスの購読
useTuvixProps(initial, bus?, event?)バスのイベントからマージされるShallowRef
@tuvix.js/vue/serverのrenderVueToString(App, props?, plugins?, ssrContext?)サーバーHTML