Skip to content

perf: inline Supabase config to eliminate initial fetch delay - #6

Merged
lifeodyssey merged 2 commits into
mainfrom
perf/inline-config
Jun 16, 2026
Merged

lifeodyssey merged 2 commits into
mainfrom
perf/inline-config

Conversation

@lifeodyssey

@lifeodyssey lifeodyssey commented Jun 16, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Worker injects SUPABASE_URL and SUPABASE_PUBLISHABLE_KEY into HTML via <script> tag before </head>
  • Client fetchConfig() reads window.__APP_CONFIG__ first, skipping the /api/config round-trip
  • Eliminates the white-screen delay caused by sequential config fetch → Supabase init

Before

White screen → React mount → fetch /api/config → wait → init Supabase → render

After

White screen → React mount → config already available → immediate Supabase init → render

Summary by CodeRabbit

Release Notes

  • Refactor
    • Configuration loading has been optimized for improved application startup performance. The system now intelligently checks for pre-loaded configuration and falls back to API-based retrieval when necessary, enabling faster initialization while preserving backward compatibility and supporting multiple configuration delivery methods for flexible deployment.

Worker now injects SUPABASE_URL and SUPABASE_PUBLISHABLE_KEY into
the HTML response via a <script> tag, so the client can initialize
Supabase immediately without waiting for /api/config round-trip.
@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@coderabbitai

coderabbitai Bot commented Jun 16, 2026 •

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@lifeodyssey, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 53 minutes and 19 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fd37ca14-9349-4b03-992e-479e065133b5

📥 Commits

Reviewing files that changed from the base of the PR and between 1bb01f3 and fed4342.

📒 Files selected for processing (1)
  • src/worker/index.ts
📝 Walkthrough

Walkthrough

The worker's fetch handler now serves static assets from env.ASSETS and, for HTML GET responses, injects an inline <script> setting window.__APP_CONFIG__ with Supabase credentials before </head>. The client's fetchConfig reads globalThis.__APP_CONFIG__ and returns it immediately when both required fields are present, falling back to GET /api/config otherwise.

Changes

Config Injection via HTML Head

Layer / File(s) Summary
Worker: ASSETS fallback and injectConfig helper
src/worker/index.ts
Fetch handler falls back to env.ASSETS, detects text/html GET responses, and calls injectConfig to insert a window.__APP_CONFIG__ script block before </head>. injectConfig reads the body as text, performs the replacement, and returns a new Response preserving original status, statusText, and headers.
Client: fetchConfig reads injected global
src/client/api.ts
fetchConfig adds an early-return path that returns globalThis.__APP_CONFIG__ when supabaseUrl and supabasePublishableKey are both present; the existing GET /api/config path is retained as a fallback.

Sequence Diagram(s)

sequenceDiagram
  participant Browser
  participant Worker
  participant ASSETS
  participant ApiConfig as GET /api/config

  Browser->>Worker: GET /index.html
  Worker->>ASSETS: env.ASSETS.fetch(request)
  ASSETS-->>Worker: HTML Response
  Worker->>Worker: injectConfig — insert window.__APP_CONFIG__ script
  Worker-->>Browser: Modified HTML (with __APP_CONFIG__)

  Browser->>Browser: fetchConfig() — reads globalThis.__APP_CONFIG__
  alt __APP_CONFIG__ present and complete
    Browser->>Browser: return __APP_CONFIG__ immediately
  else missing or incomplete
    Browser->>ApiConfig: GET /api/config
    ApiConfig-->>Browser: AppConfig JSON
  end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐇 Hippity-hop, no fetch delay,
The worker hides config in the HTML today.
</head> gets a script, a secret tucked in,
The client just reads it — no request to begin!
One less round-trip, the rabbit hops free~ ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely describes the main optimization goal: inlining Supabase config to eliminate the initial fetch delay, which is the primary change across both files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch perf/inline-config

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/worker/index.ts`:
- Around line 163-167: The Response constructor is reusing the original
response.headers directly after mutating the HTML body with text replacement.
This causes stale entity metadata headers like content-length, content-encoding,
and etag to persist with the new payload, breaking decoding and caching
behavior. Create a new Headers object or clone the existing one and remove
entity headers (content-length, content-encoding, etag, and similar body-related
metadata) before passing it to the Response constructor on line 166. Keep other
safe headers like content-type, cache-control, and other directives that don't
depend on the original payload.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c147d39d-281c-42ec-afff-0528ac701f15

📥 Commits

Reviewing files that changed from the base of the PR and between 8db7912 and 1bb01f3.

📒 Files selected for processing (2)
  • src/client/api.ts
  • src/worker/index.ts

Comment thread src/worker/index.ts
Comment on lines +163 to +167
return new Response(injected, {
status: response.status,
statusText: response.statusText,
headers: response.headers
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Do not forward entity headers after mutating the HTML body.

After response.text() + replacement, reusing original headers can keep stale entity metadata (content-length, content-encoding, etag) for a different payload, which can break decoding/caching behavior on Line 166.

Suggested fix
 async function injectConfig(response: Response, env: Env): Promise<Response> {
@@
   const html = await response.text();
   const injected = html.replace("</head>", `${configScript}</head>`);
+  const headers = new Headers(response.headers);
+  headers.delete("content-length");
+  headers.delete("content-encoding");
+  headers.delete("etag");
   return new Response(injected, {
     status: response.status,
     statusText: response.statusText,
-    headers: response.headers
+    headers
   });
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return new Response(injected, {
status: response.status,
statusText: response.statusText,
headers: response.headers
});
const headers = new Headers(response.headers);
headers.delete("content-length");
headers.delete("content-encoding");
headers.delete("etag");
return new Response(injected, {
status: response.status,
statusText: response.statusText,
headers
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/worker/index.ts` around lines 163 - 167, The Response constructor is
reusing the original response.headers directly after mutating the HTML body with
text replacement. This causes stale entity metadata headers like content-length,
content-encoding, and etag to persist with the new payload, breaking decoding
and caching behavior. Create a new Headers object or clone the existing one and
remove entity headers (content-length, content-encoding, etag, and similar
body-related metadata) before passing it to the Response constructor on line
166. Keep other safe headers like content-type, cache-control, and other
directives that don't depend on the original payload.

@lifeodyssey
lifeodyssey merged commit 4b95943 into main Jun 16, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant