トラブルシューティング
各項目は、目に見える症状から始まり、原因と修正方法が続きます。
Svelte:onMountが実行されない、またはmount()がlifecycle_function_unavailableを投げる
症状。 SvelteアイランドはレンダリングされるもののonMountのコールバックが一度も実行されない、またはSvelte 5のmount()がlifecycle_function_unavailableを投げます。
原因。 svelteは、同じimportの下にブラウザ用ランタイムとサーバー用ランタイムを持っています。クライアントバンドルがサーバー用のものを選んでいます。一部のSSR構成(Vinxi、カスタムのVite environment、jsdom上のVitest)は、browser export conditionなしでクライアントを解決するため、Viteの依存関係オプティマイザーがサーバー用ランタイムを事前バンドルします。ブラウザのdevtoolsでは、クライアント用ファイルの代わりにsvelte/src/index-server.js(Svelte 5)またはsvelte/src/runtime/ssr.js(Svelte 4)が表示されます。
修正。 クライアントのresolve conditionsにbrowserを戻し、最適化済みの依存関係を再ビルドするように--force付きでViteを再起動します。
// vite.config.ts (the client build or client environment)
import { defaultClientConditions, defineConfig } from 'vite';
export default defineConfig({
resolve: { conditions: ['browser', ...defaultClientConditions] },
});jsdomを使うVitestでは、conditionを追加し、ViteがSvelteを解決するようにインライン化します。
// vitest.config.ts
import { defineConfig } from 'vitest/config';
export default defineConfig({
resolve: { conditions: ['browser'] },
test: { environment: 'jsdom', server: { deps: { inline: [/svelte/] } } },
});svelteをoptimizeDepsから除外しないでください。除外するとesbuildが"The entry point "svelte" cannot be marked as external"で失敗します。
Vue:.vueファイルで~エイリアスが失敗する
症状。 本番ビルドがRollup failed to resolve import "~/utils/x" from ".../Card.vue?vue&type=script..."で失敗します。一方で、同じimportは.tsファイルでは動作し、.vueファイルでも~/からのimport typeは動作します。
原因。 vite-tsconfig-pathsは、tsconfigのincludeに含まれるファイルにのみエイリアスを適用します。**/*.tsと**/*.tsxをincludeするtsconfigでは、.vueファイルが対象外になります。型のみのimportは解決前に消去されるため、失敗しません。
修正。 そのtsconfigに.vueファイルを含めます。
{
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
}または、Vite自体でエイリアスを宣言します。
// vite.config.ts
import { fileURLToPath } from 'node:url';
import { defineConfig } from 'vite';
export default defineConfig({
resolve: { alias: { '~': fileURLToPath(new URL('./src', import.meta.url)) } },
});エディター拡張機能にはVue - Official(Volar)を使ってください。Veturは<script setup>のマクロやmoduleResolution: "Bundler"を理解しません。
Angular 15-17:クリックしてもビューが更新されない
症状。 Angularアイランドはレンダリングされますが、ボタンのハンドラーがフィールドを変更してもテンプレートが更新されません。
原因。 アダプターはAngularをzone.jsなしで実行します。Angular 18以降はzonelessモードで自ら変更検知をスケジュールしますが、15-17ではアダプターがNgZoneを何もしないzoneに置き換えるため、DOMイベントの後に変更検知を実行するものがありません。
修正。 変更の後にdetectChanges()を呼び出します。
import { ChangeDetectorRef, Component, inject } from '@angular/core';
@Component({
selector: 'app-like',
standalone: true,
template: `<button (click)="like()">{{ likes }}</button>`,
})
export class LikeComponent {
private readonly cdr = inject(ChangeDetectorRef);
likes = 0;
like(): void {
this.likes += 1;
this.cdr.detectChanges();
}
}または、クライアントエントリーの先頭でzone.jsをimportし、createAngularMicroAppにzone: trueを渡します。zone.jsはサーバーに含めないでください。グローバルのPromiseにパッチを当て、サーバー側のfetchを壊します。
日付によるハイドレーションの不一致
症状。 Reactがエラー#418を報告する(またはVueやSvelteがハイドレーションの不一致をログに出す)のが、一部のユーザーだけ、または深夜0時付近だけです。差分には、21 Mart 2026と22 Mart 2026のように1日ずれた日付が表示されます。
原因。 サーバーは自身のタイムゾーン(通常はUTC)で日付をフォーマットし、ブラウザはユーザーのタイムゾーンでフォーマットします。timeZoneを指定しないnew Intl.DateTimeFormat('tr-TR', { day: 'numeric', month: 'long' })は、両側で異なるテキストを生成します。
修正。 サーバーがレンダリングする日付をフォーマットするすべての箇所で、timeZoneを明示的に渡します。
const format = new Intl.DateTimeFormat('tr-TR', {
day: 'numeric',
month: 'long',
year: 'numeric',
timeZone: 'Europe/Istanbul',
});
console.log(format.format(new Date('2026-03-21T22:30:00Z'))); // 22 Mart 2026 on server and client同じことが、toLocaleString、相対時間(「3時間前」)、レンダリング中にDate.now()を使うものすべてに当てはまります。
あるリクエストのデータが別のリクエストに表示される
症状。 サーバーレンダリングされたアイランドが古いデータや別のユーザーのリクエストのデータを表示し、その後クライアントが異なる内容で再レンダリングします。
原因。 複数のマイクロアプリがimportするexport const queryClient = new QueryClient()のようなモジュールレベルのキャッシュは、サーバープロセスが存続する間ずっと存在します。すべてのリクエストが同じインスタンスを読み書きします。
修正。 サーバーではリクエストごとにキャッシュを作成し、アイランドが必要とするものをpropsとして渡します。モジュールレベルのクライアントを1つだけ持つのは、ブラウザのコードに限ってください。
import { QueryClient } from '@tanstack/query-core';
export function createRequestQueryClient(): QueryClient {
return new QueryClient({ defaultOptions: { queries: { staleTime: 60_000 } } });
}リクエストごとの状態を参照してください。
アンロード後にモジュールスクリプトのアプリがロードされない
症状。 orchestrator.unregister(name)またはloader.unload(name)の後、同じアプリを再び登録してマウントすると、Module "<name>" loaded but no exports foundで失敗します。
原因。 ブラウザはモジュールスクリプトをURLごとに1回しか実行しません。同じURLに対する2つ目の<script type="module" src="...">は何もしないため、アプリがregisterModuleを再び呼び出すことはありません。
修正。 バンドラーのモジュールキャッシュにモジュールを保持するローダー関数のエントリーを使うか、URLを変更します(たとえばバージョンのクエリ文字列を付けます)。
import { createOrchestrator } from 'tuvix.js';
const orchestrator = createOrchestrator();
orchestrator.register({
name: 'editor',
entry: () => import('./apps/editor'),
container: '#editor',
});"loaded but no exports found"
症状。 [Tuvix Loader] Module "dashboard" loaded but no exports found.
原因と修正(確認する順に):
- バンドルが登録する名前が、登録した名前と異なります。
createReactMicroApp({ name: 'Dashboard' })とregister({ name: 'dashboard' })は一致しません。同じ文字列を使ってください。 - ES moduleのバンドルがクラシックスクリプトとしてロードされています。ViteのES出力は
.jsで終わります。エントリーにtype: 'module'を追加してください。 - バンドルはモジュールをエクスポートしていますが、登録していません。アダプターか
defineMicroAppを使うか、自分でregisterModule(name, module)を呼び出してください。
コンテナが見つからない
症状。 [Tuvix] Container "#app" not found in DOM.
原因。 オーケストレーターは、アプリをマウントする時点でコンテナを検索します。外部ルーターのルートコンポーネントが、まだそれをレンダリングしていない可能性があります。
修正。 コンテナをナビゲーションより前に存在するレイアウトに置くか、ルートコンポーネント内でTuvixIslandを使ってそのアプリをホストします。外部ルーターを参照してください。
最初の描画でスタイルが適用されない
症状。 JavaScriptが無効な場合、または低速な接続で一瞬だけ、サーバーレンダリングされたアイランドがCSSなしで表示されます。
原因。 ViteはCSS Modules、Vueの<style>、SvelteのスタイルをJavaScriptから注入します。サーバーのHTMLはそれらを1つもリンクしていません。
修正。 Viteの設定に@tuvix.js/viteのtuvix()を追加し、renderAssetTags(await getAssets([...]))を<head>に出力します。SSRアイランドを参照してください。