Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

vite: prerendering silently emits no HTML when the SSR entry is outside the auto-detected directories

クローズ
#4,591 コメント 0 件 リアクション 1 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

@TheForgivenOne がすでに取り組んでいます。

2026年9月28日 から。

  • #4612 @pengzh1 による — マージされずにクローズ
  • #4674 @TheForgivenOne による — オープン

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
55/100
issue の種類
バグ
明瞭さ
おおむね明確
活発さ
活発
技術スタック
node.js, react, typescript, vite

調査の方向性

まず src/build/vite/plugin.ts の 427-440 行目と 198-206 行目を確認し、次にリンクされた再現環境で npm ci && npm run repro を実行します。SSR エントリがないことで ctx.services.ssr が未設定のままになる仕組みと、prerendering が [404] をどのように処理するかを追跡します。非標準のエントリに対して選択した動作がカバーされ、ドキュメントまたは診断がその決定と一致すれば完了です。

索引モデルが issue の本文から書いたものです。

説明

v3 vite plugin
Environment
  • Nitro: 3.0.260903-beta
  • Vite: 8.2.2
  • React: 19.2.0, Node.js: v24.20.0
  • macOS: 26.6.2, arm64
  • Minimal React SSR app using nitro/vite with prerender.routes: ["/"]. No Nuxt or other framework.
  • Also inspected Nitro main at c5177e9218cdd113c6c6a6a74b2924b2354af120; the detection logic below is unchanged there. The reproduction was executed against the published beta listed above.
Reproduction

Ready-to-run repository: https://github.com/cprecioso/nitro-prerender-entry-repro

git clone https://github.com/cprecioso/nitro-prerender-entry-repro.git
cd nitro-prerender-entry-repro
npm ci
npm run repro

The check builds the same app three times, changing only the Vite config, and exits with code 1 while the behaviour reproduces.

The app is a trivial React SSR setup. The SSR entry is still named entry-server.tsx; the only variable is that it sits at src/ssr/ rather than src/.

Describe the bug

Nitro auto-detects the Vite SSR entry by probing for ./entry-server in <rootDir|scanDirs>/{app,src,}/. When the entry is anywhere else, no ssr service is registered and no renderer is wired up, but the build still exits 0. The prerenderer resolves every route to [404], emits no HTML at all, and prints no warning that the app has no renderer.

.output/public/ ends up containing only the client JS chunk, with no HTML entry point, while the build reports success and suggests npx vite preview. Moving the file up one directory, with no other change, prerenders correctly.

Expected: one of

  1. Nitro warns or errors when there is no renderer and no ssr service, rather than emitting a successful build with zero HTML.
  2. Every prerendered route resolving to [404] is treated as a build failure.
  3. There is a discoverable, documented way to point at an SSR entry in a non-standard location.

Workaround. Declaring the entry as the ssr environment input works:

environments: {
  ssr: {
    build: { rollupOptions: { input: "src/ssr/entry-server.tsx" } },
  },
  client: {
    build: { rollupOptions: { input: "src/entry-client.tsx" } },
  },
},

setupNitroContext skips auto-detection when userConfig.environments.ssr is defined and resolves the env's input as the ssr service instead, after which configResolved still auto-wires renderer.handler to the internal ssr-renderer.

This was hard to arrive at. environments.ssr does appear in the Solid and Vue Router examples, but always pointing at a file named entry-server, and it is introduced there as a framework requirement ("SolidJS requires explicit ssr and client environment configuration") rather than as the way to relocate the SSR entry. docs/1.docs/61.vite.md documents the auto-detection rule and environments.client.build.rollupOptions.input for the client entry, with no ssr counterpart mentioned.

Additional context

Secondary, and possibly the more useful fix: renderer.handler looks like the right option and fails confusingly.

The renderer docs describe renderer.handler as "Path to a custom renderer handler module", so it is the natural thing to reach for when the handler is not auto-detected. Setting renderer: { handler: "src/ssr/entry-server.tsx" } routes the file into Nitro's own rolldown bundle, which has no Vite plugins, so the ?assets= virtual modules (and JSX, and CSS imports) cannot be resolved. It fails identically regardless of where the file lives, including the auto-detected location. Logs below.

It would help if renderer.handler rejected a path belonging to a Vite environment with an explanatory error, or if the docs noted that under the Vite plugin the SSR entry is configured via environments.ssr and never via renderer.handler.

Relevant source:

Happy to open a PR for whichever direction you prefer.

Prepared with AI assistance; the reproduction was executed locally.

Logs
# npx vite build   (entry at src/ssr/entry-server.tsx, no environments.ssr)

[nitro] ◐ Building [Nitro] (preset: node-server, compatibility: 2026-09-07)
[nitro] ✔ Generated public .output/public
[nitro] ℹ Initializing prerenderer
[nitro] ℹ Prerendering 1 routes
[nitro]   ├─ / (109ms)
  │ └── [404]
[nitro] ℹ Prerendered 0 routes in 0.123 seconds

[nitro] ✔ You can preview this build using npx vite preview

$ echo $?
0
$ find .output/public -type f
.output/public/assets/entry-client-Ba_RLnZH.js


# npx vite build --config vite.config.renderer-handler.ts

error during build:
Error: Build failed with 2 errors:

[UNLOADABLE_DEPENDENCY] Could not load src/ssr/entry-server.tsx?assets=ssr
   ╭─[ src/ssr/entry-server.tsx:7:26 ]
   │
 7 │ import serverAssets from "./entry-server?assets=ssr";
   │                          ────────────┬────────────
   │                                      ╰──────────── No such file or directory (os error 2)
───╯

[UNLOADABLE_DEPENDENCY] Could not load src/entry-client.tsx?assets=client
   ╭─[ src/ssr/entry-server.tsx:6:26 ]
   │
 6 │ import clientAssets from "../entry-client?assets=client";
   │                          ───────────────┬───────────────
   │                                         ╰─────────────── No such file or directory (os error 2)
───╯

    at aggregateBindingErrorsIntoJsError (node_modules/rolldown/dist/shared/error-BP8lJHle.mjs:48:18)
    at async prerender (node_modules/nitro/dist/_chunks/nitro.mjs:743:2)
    at async buildEnvironments (node_modules/nitro/dist/vite.mjs:121:2)
主要言語
TypeScript
スター
11.3k
フォーク
936
平均マージ
1日 15時間
マージ済み PR(30日)
166

環境構築

Codespaces で開く

このプロジェクトの開発コンテナを、あなたの GitHub アカウントでブラウザ上に起動します。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

nitrojs/nitro のほかの issue

nitrojs/nitro の issue をすべて見る

似ている issue

TypeScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。