Skip to content

refactor(v3): unify JS/CSS injection via runtime fetch#4888

Open
leaanthony wants to merge 14 commits intov3-alphafrom
refactor/runtime-init-scripts
Open

refactor(v3): unify JS/CSS injection via runtime fetch#4888
leaanthony wants to merge 14 commits intov3-alphafrom
refactor/runtime-init-scripts

Conversation

@leaanthony
Copy link
Copy Markdown
Member

@leaanthony leaanthony commented Jan 21, 2026

Description

This PR refactors how window-specific JS and CSS options from WebviewWindowOptions are injected into webviews. Instead of platform-specific execJS calls, the runtime now fetches /wails/init.js and /wails/init.css from the asset server.

This fixes the bug where JS/CSS options were not executed when using URL navigation (only worked when HTML option was also set). This is the same bug that PR #4876 attempted to fix, but this approach is cleaner and more maintainable.

How It Works

  1. Runtime JS fetches /wails/init.js and /wails/init.css after signaling ready (fire-and-forget)
  2. Backend middleware reads the x-wails-window-id header (already injected by webview request wrapper)
  3. Middleware looks up the window and serves its options.JS / options.CSS content
  4. Returns 204 No Content if empty (silently ignored by fetch)

Benefits

  • Single implementation - No platform-specific code for this feature
  • Consistent timing - Same behavior across Windows, Linux, macOS
  • Debuggable - Shows up in DevTools Network tab
  • Fixes the bug - JS/CSS now works regardless of whether HTML or URL is used

Changes

  • Add middleware handlers for /wails/init.js and /wails/init.css in application.go
  • Remove platform-specific JS/CSS injection from:
    • webview_window_windows.go
    • webview_window_linux.go
    • webview_window_darwin.go
  • Add init script loading to runtime JS (index.ts)
  • Rebuild runtime bundles

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • Refactoring (non-breaking change that improves code quality)

How Has This Been Tested?

  • Code compiles successfully
  • Windows - needs testing
  • macOS - needs testing
  • Linux - needs testing

Test plan

  1. Create a window with JS and CSS options set
  2. Navigate to a URL (not using HTML option)
  3. Verify the JS executes and CSS is applied
  4. Test with multiple windows having different JS/CSS
  5. Verify no errors when JS/CSS options are empty

🤖 Generated with Claude Code

Supersedes #4876

Summary by CodeRabbit

  • Bug Fixes

    • JS/CSS window options now execute when navigating to URLs as well as when loading HTML.
  • New Features

    • Runtime can optionally load per-window init stylesheets.
    • Window-specific init assets (init.js / init.css) can be served and loaded per window.
  • Documentation

    • Minor updates to generated docs and example asset data.

Move window-specific JS/CSS injection from platform-specific execJS calls
to a unified approach using the runtime. The runtime now fetches
/wails/init.js and /wails/init.css from the asset server after signaling
ready, and the backend identifies which window made the request via the
existing x-wails-window-id header.

This fixes the bug where JS/CSS options were not executed when using URL
navigation (only worked with HTML option), and provides a single,
consistent implementation across all platforms.

Changes:
- Add middleware handlers for /wails/init.js and /wails/init.css
- Remove platform-specific JS/CSS injection from Windows, Linux, macOS
- Add init script loading to runtime JS (fire-and-forget)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 21, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

JS/CSS injection was moved from platform-specific inline injections to centralized endpoints (/wails/init.js, /wails/init.css) served per-window; the desktop runtime loader now requires HTTP 200 to inject optional scripts and adds a stylesheet loader that requests and injects init.css.

Changes

Cohort / File(s) Summary
Server Init Endpoints
v3/pkg/application/application.go
Add middleware to serve /wails/init.js and /wails/init.css, reading x-wails-window-id, returning 204 for missing/invalid window or empty content, and serving per-window JS/CSS with Cache-Control: no-store and appropriate Content-Type.
Runtime Loaders & Init
v3/internal/runtime/desktop/@wailsio/runtime/src/index.ts
Tighten loadOptionalScript to require HEAD status 200; add loadOptionalStylesheet(url: string): Promise<void> (HEAD then inject <link rel="stylesheet">); init sequence now attempts /wails/init.js and /wails/init.css.
Platform Webview Handlers
v3/pkg/application/webview_window_darwin.go, v3/pkg/application/webview_window_linux.go, v3/pkg/application/webview_window_windows.go
Remove per-platform inline injection of user JS/CSS on navigation/load events; retain visibility/topmost/shadow logic and core runtime flag injection only.
Bundled Runtime Exports
v3/internal/assetserver/bundledassets/runtime.js
Add loadOptionalStylesheet to public exports and remap several runtime export identifiers.
Docs & Changelog
v3/UNRELEASED_CHANGELOG.md, v3/internal/runtime/desktop/@wailsio/runtime/docs/...
Add changelog entry; add generated docs for loadOptionalStylesheet; multiple generated HTML/doc asset updates and base64 asset replacements.
Doc Assets / Minor HTML Edits
v3/internal/runtime/desktop/@wailsio/runtime/docs/assets/*, .../classes/*.html, .../modules.html
Update base64 content and minor generated HTML structural/ID tweaks in documentation assets (no API behavior changes).

Sequence Diagrams

sequenceDiagram
    participant Browser as WebView/Browser
    participant Runtime as Desktop Runtime
    participant Server as App Server
    participant WindowStore as Window Store

    Note over Browser,WindowStore: Centralized per-window init asset flow
    Browser->>Runtime: Start init
    Runtime->>Server: HEAD /wails/init.js (x-wails-window-id)
    Server->>WindowStore: Lookup window by ID
    WindowStore-->>Server: 200 or 204
    Server-->>Runtime: 200 or 204
    alt 200
      Runtime->>Server: GET /wails/init.js
      Server-->>Runtime: JS payload (application/javascript)
      Runtime->>Browser: Inject <script> tag
    end
    Runtime->>Server: HEAD /wails/init.css (x-wails-window-id)
    Server->>WindowStore: Lookup window by ID
    WindowStore-->>Server: 200 or 204
    Server-->>Runtime: 200 or 204
    alt 200
      Runtime->>Server: GET /wails/init.css
      Server-->>Runtime: CSS payload (text/css)
      Runtime->>Browser: Inject <link rel="stylesheet">
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Possibly related PRs

Suggested labels

v3-alpha, runtime, Windows, MacOS, Linux, size:L

Poem

🐇 I hop where init endpoints sing,

Scripts and styles fetched on a string.
No platform snares beneath my fur,
One tidy path — a happy purr.
I nibble code and do a little spring.

🚥 Pre-merge checks | ✅ 3 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.04% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main refactoring: unifying JS/CSS injection through runtime fetch instead of platform-specific approaches.
Description check ✅ Passed The description is comprehensive and well-structured, covering motivation, implementation details, benefits, and changes. However, it is missing the required 'Fixes # (issue)' reference and the changelog update checklist item is not marked.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into v3-alpha

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/runtime-init-scripts

No actionable comments were generated in the recent review. 🎉

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 OpenGrep (1.16.0)
v3/internal/assetserver/bundledassets/runtime.js

┌──────────────┐
│ Opengrep CLI │
└──────────────┘

�[32m✔�[39m �[1mOpengrep OSS�[0m
�[32m✔�[39m Basic security coverage for first-party code vulnerabilities.

�[1m Loading rules from local config...�[0m

v3/internal/runtime/desktop/@wailsio/runtime/docs/assets/hierarchy.js

┌──────────────┐
│ Opengrep CLI │
└──────────────┘

�[32m✔�[39m �[1mOpengrep OSS�[0m
�[32m✔�[39m Basic security coverage for first-party code vulnerabilities.

�[1m Loading rules from local config...�[0m

v3/internal/runtime/desktop/@wailsio/runtime/docs/assets/navigation.js

┌──────────────┐
│ Opengrep CLI │
└──────────────┘

�[32m✔�[39m �[1mOpengrep OSS�[0m
�[32m✔�[39m Basic security coverage for first-party code vulnerabilities.

�[1m Loading rules from local config...�[0m

  • 1 others

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.

Comment thread v3/pkg/application/application.go Fixed
Address code scanning alert about incorrect integer conversion.
Using strconv.Atoi (which returns int) matches the platform's native
integer size and is consistent with how other code in the repo parses
window IDs (e.g., transport_http.go).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Jan 21, 2026

Deploying wails with  Cloudflare Pages  Cloudflare Pages

Latest commit: 6b989d8
Status: ✅  Deploy successful!
Preview URL: https://e1764cbd.wails.pages.dev
Branch Preview URL: https://refactor-runtime-init-script.wails.pages.dev

View logs

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@v3/internal/runtime/desktop/`@wailsio/runtime/src/index.ts:
- Around line 80-95: Replace the eval-based runtime loader for '/wails/init.js'
with injecting a script element: when the fetch for '/wails/init.js' returns
non-empty text (the current fetch(...).then(js => { if (js) eval(js); })),
create a HTMLScriptElement, set its textContent to the fetched JS (or set src to
'/wails/init.js' and let the browser load it), append it to document.head to
execute it, and then optionally remove the node; keep the fire-and-forget async
pattern and existing error swallowing. Target the fetch('/wails/init.js')
handling in this file (the block that currently calls eval(js)) and leave the
init.css logic unchanged.

Comment thread v3/internal/runtime/desktop/@wailsio/runtime/src/index.ts Outdated
@popaprozac
Copy link
Copy Markdown
Contributor

@leaanthony this is great. Only note is agreeing with the review to remove eval and instead add a script tag to load the JS

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
v3/internal/runtime/desktop/@wailsio/runtime/src/index.ts (1)

84-104: CSS is never applied (loaded as a <script>).
loadOptionalScript('/wails/init.css') injects a script tag, so the stylesheet won’t load. This breaks CSS options for window init.

✅ Suggested fix (add a style loader and use it for init.css)
 export function loadOptionalScript(url: string): Promise<void> {
     return fetch(url, { method: 'HEAD' })
         .then(response => {
             if (response.ok) {
                 const script = document.createElement('script');
                 script.src = url;
                 document.head.appendChild(script);
             }
         })
         .catch(() => {}); // Silently ignore - script is optional
 }
+
+export function loadOptionalStyle(url: string): Promise<void> {
+    return fetch(url, { method: 'HEAD' })
+        .then(response => {
+            if (response.ok) {
+                const link = document.createElement('link');
+                link.rel = 'stylesheet';
+                link.href = url;
+                document.head.appendChild(link);
+            }
+        })
+        .catch(() => {}); // Silently ignore - style is optional
+}
@@
 loadOptionalScript('/wails/custom.js');
 loadOptionalScript('/wails/init.js');
-loadOptionalScript('/wails/init.css');
+loadOptionalStyle('/wails/init.css');

leaanthony and others added 2 commits January 28, 2026 08:35
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@v3/internal/assetserver/bundledassets/runtime.js`:
- Line 1: The runtime currently uses the ne(n) / loadOptionalScript helper to
fetch a URL then always inject a <script> tag (see ne function and exported
loadOptionalScript), which is wrong for CSS; change ne (in
v3/internal/runtime/desktop/@wailsio/runtime/src/index.ts — exported as
loadOptionalScript) to detect the file extension (e.g., endsWith(".css") or
content-type) and branch: for CSS create a LINK element with rel="stylesheet"
and href=n and append to document.head, otherwise keep the existing SCRIPT
creation behavior; preserve the existing fetch check and overall promise/failure
handling.

Comment thread v3/internal/assetserver/bundledassets/runtime.js Outdated
@leaanthony
Copy link
Copy Markdown
Member Author

@popaprozac - updated 👍

@leaanthony leaanthony force-pushed the refactor/runtime-init-scripts branch from 5455d4f to ab57d0f Compare January 28, 2026 19:16
Add loadOptionalStylesheet function that properly loads CSS files using
<link> tags instead of <script> tags. The init.css is now loaded correctly
as a stylesheet.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@leaanthony leaanthony force-pushed the refactor/runtime-init-scripts branch from ab57d0f to 1aaa50a Compare January 28, 2026 19:16
Copy link
Copy Markdown
Contributor

@popaprozac popaprozac left a comment

Choose a reason for hiding this comment

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

This looks good to me!

Copilot AI review requested due to automatic review settings February 1, 2026 00:10
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Refactors window-specific WebviewWindowOptions.JS/CSS injection to be served via the asset server (/wails/init.js and /wails/init.css) and fetched by the runtime, replacing platform-specific injection paths and fixing missing injection when using URL navigation.

Changes:

  • Add asset-server middleware endpoints to serve per-window init JS/CSS using the x-wails-window-id header.
  • Remove platform-specific JS/CSS injection logic on Windows/Linux/macOS.
  • Update runtime to load optional init script and stylesheet; rebuild runtime bundle and generated docs.

Reviewed changes

Copilot reviewed 17 out of 19 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
v3/pkg/application/webview_window_windows.go Removes Windows-specific JS/CSS injection during Chromium setup.
v3/pkg/application/webview_window_linux.go Removes Linux-specific post-load JS/CSS injection hook.
v3/pkg/application/webview_window_darwin.go Removes macOS-specific post-navigation JS/CSS injection and updates comment.
v3/pkg/application/application.go Adds middleware to serve /wails/init.js and /wails/init.css per window based on request headers.
v3/internal/runtime/desktop/@wailsio/runtime/src/index.ts Adds loadOptionalStylesheet() and triggers init JS/CSS loading at runtime startup.
v3/internal/runtime/desktop/@wailsio/runtime/package-lock.json Updates lockfile metadata associated with runtime rebuild.
v3/internal/runtime/desktop/@wailsio/runtime/docs/modules.html Regenerates runtime docs (module index).
v3/internal/runtime/desktop/@wailsio/runtime/docs/hierarchy.html Regenerates runtime docs (hierarchy page).
v3/internal/runtime/desktop/@wailsio/runtime/docs/functions/loadOptionalStylesheet.html Adds generated docs page for loadOptionalStylesheet.
v3/internal/runtime/desktop/@wailsio/runtime/docs/classes/CancelledRejectionError.html Regenerated docs formatting/anchors.
v3/internal/runtime/desktop/@wailsio/runtime/docs/classes/CancellablePromise.html Regenerated docs formatting/anchors.
v3/internal/runtime/desktop/@wailsio/runtime/docs/classes/CancelError.html Regenerated docs formatting/anchors.
v3/internal/runtime/desktop/@wailsio/runtime/docs/classes/Call.RuntimeError.html Regenerated docs formatting/anchors.
v3/internal/runtime/desktop/@wailsio/runtime/docs/assets/search.js Regenerated docs asset bundle.
v3/internal/runtime/desktop/@wailsio/runtime/docs/assets/navigation.js Regenerated docs asset bundle.
v3/internal/runtime/desktop/@wailsio/runtime/docs/assets/hierarchy.js Regenerated docs asset bundle.
v3/internal/assetserver/bundledassets/runtime.js Updates bundled runtime to load init JS/CSS and export stylesheet loader.
v3/UNRELEASED_CHANGELOG.md Adds changelog entry for the JS/CSS URL-navigation fix.
Files not reviewed (1)
  • v3/internal/runtime/desktop/@wailsio/runtime/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread v3/internal/runtime/desktop/@wailsio/runtime/src/index.ts
Comment thread v3/internal/runtime/desktop/@wailsio/runtime/src/index.ts
Comment thread v3/pkg/application/application.go Outdated
Comment thread v3/internal/runtime/desktop/@wailsio/runtime/docs/modules.html
leaanthony and others added 4 commits February 3, 2026 06:04
- Treat HTTP 204 as "not present" instead of loading empty resources
- Add Vary header for window-id to prevent cache issues across windows
- Change Cache-Control from no-cache to no-store for init assets

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Feb 2, 2026

Quality Gate Failed Quality Gate failed

Failed conditions
B Reliability Rating on New Code (required ≥ A)
C Maintainability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

…init-scripts

# Conflicts:
#	v3/UNRELEASED_CHANGELOG.md
#	v3/internal/assetserver/bundledassets/runtime.debug.js
#	v3/internal/assetserver/bundledassets/runtime.js
#	v3/internal/runtime/desktop/@wailsio/runtime/docs/assets/hierarchy.js
#	v3/internal/runtime/desktop/@wailsio/runtime/docs/assets/navigation.js
#	v3/internal/runtime/desktop/@wailsio/runtime/docs/classes/CancelError.html
#	v3/internal/runtime/desktop/@wailsio/runtime/docs/classes/CancellablePromise.html
#	v3/internal/runtime/desktop/@wailsio/runtime/docs/classes/CancelledRejectionError.html
#	v3/internal/runtime/desktop/@wailsio/runtime/docs/hierarchy.html
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.

4 participants