FEAT: Switch default frontend to Next.js app - #5111
Conversation
There was a problem hiding this comment.
Code Review
This pull request migrates the Xinference Web UI to a separate Next.js application in the frontend/ directory, updating the build process, Dockerfiles, and documentation accordingly. Feedback points out a critical bug where the Switch component's state handler was incorrectly changed to onChange, and suggests several improvements: defaulting the backend redirect to the local frontend port, removing the web build step from standard Python installations to save time, excluding Next.js build artifacts from MANIFEST.in, and stripping trailing slashes from API URLs to prevent routing issues.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Rework the frontend switch to a single-process deployment, following the approach used in xagent#732: - next.config: env-driven output (default static export; NEXT_OUTPUT=standalone keeps the Node server; dev mode sets none). Rewrites are dev/standalone only. - Dynamic routes split into server wrappers (generateStaticParams __shell__ placeholder) + client pages reading params from the URL. - layout drops request-time cookies()/headers() and server-side cluster auth fetch; AppInit resolves cluster auth client-side, I18nProvider falls back to the browser language. - New xinference/api/frontend_static.py serves the export from FastAPI: /_next assets, SPA catch-all with __shell__ route table, RSC .txt payloads, JSON 404 for unmatched API prefixes, /ui legacy redirect, and ensure_spa_fallback_last() so runtime Gradio mounts are not shadowed. - Packaging: npm postbuild stages the export at xinference/ui/web/dist, which ships in the wheel/sdist; build_web hooks restored for install/develop/sdist. - Tests: synthetic-export unit tests plus real-export integration tests; CI lint job builds the export, verifies its shape, and serves it through the backend.
ecd0c23 to
88bd676
Compare
|
/gemini review |
|
Warning Gemini encountered an error creating the review. You can try again by commenting |
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request transitions the web UI to a Next.js static export served directly by the FastAPI backend, moving the source code to the frontend/ directory and updating build scripts, Dockerfiles, and documentation. It introduces a backend module to handle SPA routing, dynamic route shells, and static assets. The review feedback identifies three key issues: a bug in launch-dialog.tsx where using onChange instead of onCheckedChange on the Switch component breaks state updates, a routing issue in frontend_static.py where trailing slashes can cause 404 errors, and a potential build-time exception in i18n-context.tsx from accessing navigator during static pre-rendering.
- frontend_static: strip trailing slash before route lookup so /running-model/<uid>/ and /launch-model/ resolve like their no-slash form instead of 404ing. - i18n-context: guard the browser-language fallback with a typeof navigator check instead of relying on the try/catch. The other gemini comments (Switch onChange, frontend_endpoint default, CustomInstall/CustomDevelop build_web hooks, MANIFEST.in artifacts, trailing-slash stripping in next.config/getApiUrl) target the pre-rework code and no longer apply.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request restructures the Xinference web UI into a Next.js static export under the frontend/ directory, which is staged at xinference/ui/web/dist and served directly by the FastAPI backend, removing the Node.js runtime dependency in production. It adds SPA routing fallback logic in the backend, updates Dockerfiles to Node.js 20.19.0, and transitions server-side layout logic to client-side initialization. The review feedback correctly identifies a bug in launch-dialog.tsx where changing onCheckedChange to onChange on a Radix UI Switch component will cause TypeScript compilation errors and break functionality.
…fault The old xinference/ui/web/ui frontend was fully superseded by the Next.js app under frontend/ (xorbitsai#5111), which is already wired into the build, packaging, and serving pipeline. Removing the unused directory and updating AGENTS.md to point at the current frontend.
What & why
Switch the default web UI to the Next.js app under
frontend/, shipped as a static export bundled into thexinferencepackage and served by the backend itself — single process, no Node runtime needed at runtime.pip install xinferencegives the full product again, same as the old CRA UI. This follows the approach used in xagent#732.How it works
Frontend (static export)
next.config.ts: output mode is env-driven — builds default toexport;NEXT_OUTPUT=standalonekeeps the Node server;next devsets none (export would break dynamic routes in dev). Rewrites (the dev API proxy) only apply outside export mode; in production the UI is same-origin with the API.launch-model/[modelType],register-model/[modelType],register-model/[modelType]/[modelName],running-model/[modelUid]) are split into a server wrapper (generateStaticParamsemits a__shell__placeholder page) + a client page that reads real params from the URL (useParams/useSearchParamsin Suspense).layout.tsxdrops request-timecookies()/headers()and the server-side cluster-auth fetch;AppInitnow resolves/v1/cluster/authclient-side, andI18nProviderfalls back to the browser language on first visit./redirects to/launch-modelclient-side (serverredirect()/config redirects are unsupported in export).Backend (
xinference/api/frontend_static.py)mount_frontend()serves/_nextassets plus a SPA catch-all that reconstructs the route table from the export's__shell__files, serves RSC.txtprefetch payloads, guards path traversal, returns JSON 404 for unmatched API prefixes (derived from the live route table), and redirects legacy/ui/to/. No-op when the export is absent (API-only).ensure_spa_fallback_last()keeps the catch-all at the end of the route table so runtime Gradio mounts at/{model_uid}are not shadowed.XINFERENCE_FRONTEND_ENDPOINTredirect; override the export location withXINFERENCE_FRONTEND_DIST_DIRif needed.Packaging
npm run buildstages the export atxinference/ui/web/distvia a postbuild hook;setup.py build_web(hooked on install/develop/sdist, as before) runs npm and asserts the staged output. MANIFEST grafts the staged dist, so wheels/sdists are self-contained. Docker flows are unchanged (python setup.py build_webstill works; the staged dist is untracked sogit restore .keeps it).CI & tests
next build(static export) → verifyout/shape (index.html,404.html,__shell__pages) → serve the real export through FastAPI and run the routing tests.xinference/api/tests/test_frontend_static.py: unit tests on a synthetic export (no Node needed) — shell pattern building, backend-prefix 404s, RSC payloads, traversal rejection, Gradio-mount reordering.xinference/api/tests/test_frontend_static_real_export.py: integration tests against the realfrontend/out(skipped when not built).Verification
__shell__shells; postbuild staging works.--noconftest, as the CI lint job runs them).xinference/ui/web/dist.pre-commit(black/flake8/isort/mypy/codespell) passes; ESLint 0 errors.Notes
xinference/ui/web/uiis untouched here; it can be removed in a follow-up.next@15.2.3has a published advisory (CVE-2025-66478); worth bumping in a follow-up.