Skip to content

perf(board): server-render board layout and deduplicate fetches#5770

Draft
ajnart wants to merge 9 commits into
devfrom
feat/static-board-ssr
Draft

perf(board): server-render board layout and deduplicate fetches#5770
ajnart wants to merge 9 commits into
devfrom
feat/static-board-ssr

Conversation

@ajnart
Copy link
Copy Markdown
Member

@ajnart ajnart commented May 22, 2026

Summary

  • Split board rendering into a static CSS Grid (view mode, SSR) and lazy-loaded GridStack (edit mode only), eliminating widget "pop-in" on page load
  • Server-side prefetch for weather and RSS feed widgets so content renders on first paint
  • Fallback dimensions for widgets during hydration to prevent layout shifts when useElementSize hasn't measured yet

How it works

  1. _dynamic-client.tsx no longer wraps ClientBoard in dynamic(..., { ssr: false }) — the board now renders on the server
  2. View mode uses a pure CSS Grid (static-grid.tsx) with container queries to match GridStack's square-cell sizing
  3. Edit mode lazy-loads GridStack via next/dynamic with ssr: false
  4. useEditMode() returns false during SSR, so the static grid always renders server-side

Test plan

  • Load a board page — widgets should appear instantly without pop-in
  • Toggle edit mode — GridStack should load and all widgets remain in correct positions
  • Verify category sections collapse/expand correctly in view mode
  • Verify dynamic (container) sections render at correct size without item stretching
  • Test responsive layouts — resize viewport and confirm layout switches work
  • Verify weather and RSS widgets show data on first paint (no loading spinner)

ajnart added 5 commits May 22, 2026 09:58
…cted

When adding a widget from the "Choose item to add" modal, the widget
edit modal now opens immediately after placement, allowing the user to
configure options and integrations before the widget renders.

All available integrations for the widget are selected by default.
Split board rendering into two modes: a static CSS Grid for view mode
(SSR-friendly, no JS required for layout) and a lazy-loaded GridStack
for edit mode. This eliminates widget "pop-in" on page load by rendering
the full grid layout server-side.
Add useOptionalSectionContext to gracefully handle rendering outside
GridStack (view mode). The item menu now uses optional chaining for
gridstack access instead of throwing when context is absent.
Provide estimated width/height to widgets before useElementSize
measures the DOM, preventing responsive breakpoint shifts during
hydration. Replace the Loader spinner with a Skeleton for widget
loading states.
Prefetch weather and RSS feed data during SSR so widgets render with
content on first paint instead of showing loading states.
@ajnart ajnart requested a review from a team as a code owner May 22, 2026 09:38
@ajnart ajnart added the needs-demo This PR needs a demo deployment label May 22, 2026
@dokploy-homarr-labs
Copy link
Copy Markdown

dokploy-homarr-labs Bot commented May 22, 2026

Dokploy Preview Deployment

Name Status Preview Updated (UTC)
homarr ✅ Done Preview URL 2026-05-22T09:43:01.475Z

@dokploy-homarr-labs
Copy link
Copy Markdown

dokploy-homarr-labs Bot commented May 22, 2026

Dokploy Preview Deployment

Name Status Preview Updated (UTC)
homarr ✅ Done Preview URL 2026-05-22T10:01:13.957Z

ajnart added 2 commits May 22, 2026 11:58
# Conflicts:
#	apps/nextjs/src/app/[locale]/boards/(content)/_client.tsx
Remove useIsBoardReady and LoadingOverlay from edit mode board,
aligning with the dev branch's perf improvement that shows the board
immediately without waiting for ready state.
@ajnart ajnart changed the title feat(board): SSR static grid for instant page loads perf(board): server-render board layout and deduplicate fetches May 22, 2026
ajnart added 2 commits May 22, 2026 12:52
Wrap getInitialBoardAsync in React cache() so the same board data is
fetched once per request instead of 3 times (layout, page, metadata).
This is the same pattern used for auth() in the codebase.
@Meierschlumpf
Copy link
Copy Markdown
Member

I see a few problems with these changes, especially regarding the server rendering. If you open the default board right now it loads with smaller texts and 11:45 as time because it uses the server local time and a predefined screen size, therefore we have to decide if we really want these changes or if we are okay with it loading on the client, but at least showing it without layout shift & wrong data

@ajnart
Copy link
Copy Markdown
Member Author

ajnart commented May 28, 2026

I see a few problems with these changes, especially regarding the server rendering. If you open the default board right now it loads with smaller texts and 11:45 as time because it uses the server local time and a predefined screen size, therefore we have to decide if we really want these changes or if we are okay with it loading on the client, but at least showing it without layout shift & wrong data

I agree there are some drawbacks, maybe it's more of a proof of concept stage right now. I do really like the idea of having the edit mode as a whole separate thing that loads up gridstack for re-organizing and then just having a simpler read-only dashboard in view mode

@Meierschlumpf
Copy link
Copy Markdown
Member

Yeah I also already though about spliting it even from an url standpoint. Similar to confluence where you go into edit mode and it sends you to a different url than the page you can view it

@ajnart
Copy link
Copy Markdown
Member Author

ajnart commented May 28, 2026

Yeah I also already though about spliting it even from an url standpoint. Similar to confluence where you go into edit mode and it sends you to a different url than the page you can view it

I wouldn't necessarily create another page, ideally it's possible to leverage dynamic imports like we did for integrations so that it only loads on demand

@Meierschlumpf Meierschlumpf marked this pull request as draft May 29, 2026 08:13
@Meierschlumpf
Copy link
Copy Markdown
Member

I'll convert it back to draft as it is currently a poc

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-demo This PR needs a demo deployment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants