Conversation
Shrink the initial HTML payload by keeping the table shell server-rendered and filling rows client-side. This preserves the current UI while removing the giant SSR table from the document.
There was a problem hiding this comment.
Pull request overview
Moves the model table from server-rendered HTML to client-side rendering backed by a /api.json endpoint, substantially reducing initial HTML payload while preserving the existing table UX (search/sort/copy).
Changes:
- Add
/api.jsonroute to serve generated provider/model data with caching. - Update SSR to render only the table shell plus a loading row, letting the client populate rows.
- Implement client-side fetch/render pipeline (including logo
<img>usage) and keep existing interactions working.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| packages/web/src/server.ts | Adds /api.json route to serve provider/model data with cache headers. |
| packages/web/src/render.tsx | Removes server-rendered table rows; renders a small <tbody> placeholder with loading state. |
| packages/web/src/index.ts | Fetches /api.json, renders rows client-side, and preserves sorting/search/copy behaviors. |
| packages/web/src/index.css | Styles new provider logo <img> usage and loading/error rows. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| <tbody id="table-body"> | ||
| <tr class="loading-row"> | ||
| <td colspan={25}>Loading models...</td> | ||
| </tr> |
There was a problem hiding this comment.
colspan is hard-coded to 25 here; the same count is also duplicated in the client code for loading/error rows. To reduce the chance of future mismatches when table columns change, consider deriving the colspan from the number of <th> elements (or sharing a single constant used by both render and client code).
| const COLUMN_COUNT = 25; | ||
| const modal = document.getElementById("modal") as HTMLDialogElement; | ||
| const modalClose = document.getElementById("close")!; | ||
| const help = document.getElementById("help")!; | ||
| const search = document.getElementById("search")! as HTMLInputElement; | ||
| const tableBody = document.getElementById("table-body")! as HTMLTableSectionElement; |
There was a problem hiding this comment.
The column count is hard-coded here and needs to stay in sync with the rendered table header and the server-rendered loading row’s colspan. Consider deriving this dynamically from the DOM (eg, document.querySelectorAll('table thead th').length) to avoid future drift when columns are added/removed.
| const COLUMN_COUNT = 25; | |
| const modal = document.getElementById("modal") as HTMLDialogElement; | |
| const modalClose = document.getElementById("close")!; | |
| const help = document.getElementById("help")!; | |
| const search = document.getElementById("search")! as HTMLInputElement; | |
| const tableBody = document.getElementById("table-body")! as HTMLTableSectionElement; | |
| const tableBody = document.getElementById("table-body")! as HTMLTableSectionElement; | |
| const COLUMN_COUNT = tableBody.closest("table")?.querySelectorAll("thead th").length ?? 0; | |
| const modal = document.getElementById("modal") as HTMLDialogElement; | |
| const modalClose = document.getElementById("close")!; | |
| const help = document.getElementById("help")!; | |
| const search = document.getElementById("search")! as HTMLInputElement; |
Normalize built and served logo SVGs so currentColor resolves to the themed gray used before provider logos moved to external images.
Summary
/api.json/logos/{provider}.svgimages instead, and show a loading/error row while data loadsTesting
bun run build