Skip to content

fix(whitelabeling): resolve FOUC by migrating branding injection to SSR#4753

Open
imrja8 wants to merge 1 commit into
Dokploy:canaryfrom
imrja8:fix/whitelabeling-fouc
Open

fix(whitelabeling): resolve FOUC by migrating branding injection to SSR#4753
imrja8 wants to merge 1 commit into
Dokploy:canaryfrom
imrja8:fix/whitelabeling-fouc

Conversation

@imrja8

@imrja8 imrja8 commented Jul 7, 2026

Copy link
Copy Markdown

What is this PR about?

For Enterprise users utilizing the custom branding features, the current implementation breaks the illusion of a fully whitelabeled platform. When clients or employees visit the public-facing pages, they are briefly shown the default Dokploy logo, Dokploy tab title, and Dokploy colors before the page abruptly "flashes" to their custom branding. This visual glitch makes the platform feel unpolished and unstable to end-users.

This PR fixes that completely. It migrates the branding logic entirely to Server-Side Rendering (SSR) to ensure the DOM is perfectly branded on the very first byte delivered to the browser.

How & Why

1. _document.tsx SSR Shell Injection

  • Moved the ownership of <title>, <link rel="icon">, and custom CSS out of _app.tsx and into _document.tsx.
  • CSS Improvement: Custom CSS is now injected directly into the initial HTML payload. This entirely eliminates the visual jump that occurred when styles were previously loaded and painted client-side. The page now loads immediately with the correct enterprise colors and layout overrides.
  • Favicon Optimization: Fetches the remote favicon on the server and converts it to a base64 data: URI, preventing the browser from needing to make a secondary network request on initial paint.

2. tRPC SSR Prefetching

  • Added createServerSideHelpers to getServerSideProps on all unauthenticated routes (index.tsx, register.tsx, invitation.tsx, send-reset-password.tsx) as well as getInitialProps in _error.tsx.
  • By prefetching whitelabeling.getPublic, the React Query trpcState is dehydrated into the page. When the client-side useWhitelabelingPublic hook mounts, it hits a warm cache synchronously. Result: Zero Dokploy logo flashing on mount.

Intentional Optimizations & Architecture Decisions

  • In-Memory Caching (Load Protection): To protect the database from being hammered by SSR requests on every page load, implemented a dual globalThis caching layer in _document.tsx:
    • __SETTINGS_CACHE: 1-minute TTL for whitelabeling JSON config.
    • __FAVICON_CACHE: 1-hour TTL for the base64 favicon buffer.
  • Immediate Cache Invalidation: Extracted clearBrandingSSRCache() in the whitelabeling.ts backend router so that the globalThis caches are instantly wiped the millisecond an admin saves or resets their settings in the dashboard.
  • Dead Code Removal: Entirely deleted whitelabeling-provider.tsx and removed the client-side <title> override from _app.tsx, successfully preventing React hydration mismatches.
  • Strict Scope Constraints: Intentionally avoided injecting og:image or meta:description tags, as those fields do not currently exist in the webServerSettings database schema. All changes strictly respect the existing codebase boundaries.

Checklist

Before submitting this PR, please make sure that:

  • You created a dedicated branch based on the canary branch.
  • You have read the suggestions in the CONTRIBUTING.md file https://github.com/Dokploy/dokploy/blob/canary/CONTRIBUTING.md#pull-request
  • You have tested this PR in your local instance. If you have not tested it yet, please do so before submitting. This helps avoid wasting maintainers' time reviewing code that has not been verified by you.

Issues related (if applicable)

closes #4750

Screenshots

Screenshots can't prove changes, since FOUC is a temporal loading flash and not a static layout bug. Reviewers can verify the instantaneous, flicker-free rendering of the custom branding by testing the public routes locally.

@imrja8 imrja8 requested a review from Siumauricio as a code owner July 7, 2026 03:36
@dosubot dosubot Bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Jul 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Enterprise: Default Dokploy branding flashes before custom white-labeling is applied (FOUC)

1 participant