fix(desktop-electron): fix resource loading under file:// protocol (#17125)

This commit is contained in:
Luke Parker
2026-03-12 14:19:44 +10:00
committed by GitHub
parent 1d7fcd40b4
commit 54e7baa6cf
6 changed files with 86 additions and 22 deletions

View File

@@ -0,0 +1,62 @@
import { describe, expect, test } from "bun:test"
import { join, dirname, resolve } from "node:path"
import { existsSync } from "node:fs"
import { fileURLToPath } from "node:url"
const dir = dirname(fileURLToPath(import.meta.url))
const root = resolve(dir, "../..")
const html = async (name: string) => Bun.file(join(dir, name)).text()
/**
* Electron loads renderer HTML via `win.loadFile()` which uses the `file://`
* protocol. Absolute paths like `src="/foo.js"` resolve to the filesystem root
* (e.g. `file:///C:/foo.js` on Windows) instead of relative to the app bundle.
*
* All local resource references must use relative paths (`./`).
*/
describe("electron renderer html", () => {
for (const name of ["index.html", "loading.html"]) {
describe(name, () => {
test("script src attributes use relative paths", async () => {
const content = await html(name)
const srcs = [...content.matchAll(/\bsrc=["']([^"']+)["']/g)].map((m) => m[1])
for (const src of srcs) {
expect(src).not.toMatch(/^\/[^/]/)
}
})
test("link href attributes use relative paths", async () => {
const content = await html(name)
const hrefs = [...content.matchAll(/<link[^>]+href=["']([^"']+)["']/g)].map((m) => m[1])
for (const href of hrefs) {
expect(href).not.toMatch(/^\/[^/]/)
}
})
test("no web manifest link (not applicable in Electron)", async () => {
const content = await html(name)
expect(content).not.toContain('rel="manifest"')
})
})
}
})
/**
* Vite resolves `publicDir` relative to `root`, not the config file.
* This test reads the actual values from electron.vite.config.ts to catch
* regressions where the publicDir path no longer resolves correctly
* after the renderer root is accounted for.
*/
describe("electron vite publicDir", () => {
test("configured publicDir resolves to a directory with oc-theme-preload.js", async () => {
const config = await Bun.file(join(root, "electron.vite.config.ts")).text()
const pub = config.match(/publicDir:\s*["']([^"']+)["']/)
const rendererRoot = config.match(/root:\s*["']([^"']+)["']/)
expect(pub).not.toBeNull()
expect(rendererRoot).not.toBeNull()
const resolved = resolve(root, rendererRoot![1], pub![1])
expect(existsSync(resolved)).toBe(true)
expect(existsSync(join(resolved, "oc-theme-preload.js"))).toBe(true)
})
})

View File

@@ -4,20 +4,19 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>OpenCode</title>
<link rel="icon" type="image/png" href="/favicon-96x96-v3.png" sizes="96x96" />
<link rel="icon" type="image/svg+xml" href="/favicon-v3.svg" />
<link rel="shortcut icon" href="/favicon-v3.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-v3.png" />
<link rel="manifest" href="/site.webmanifest" />
<link rel="icon" type="image/png" href="./favicon-96x96-v3.png" sizes="96x96" />
<link rel="icon" type="image/svg+xml" href="./favicon-v3.svg" />
<link rel="shortcut icon" href="./favicon-v3.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="./apple-touch-icon-v3.png" />
<meta name="theme-color" content="#F8F7F7" />
<meta name="theme-color" content="#131010" media="(prefers-color-scheme: dark)" />
<meta property="og:image" content="/social-share.png" />
<meta property="twitter:image" content="/social-share.png" />
<script id="oc-theme-preload-script" src="/oc-theme-preload.js"></script>
<meta property="og:image" content="./social-share.png" />
<meta property="twitter:image" content="./social-share.png" />
<script id="oc-theme-preload-script" src="./oc-theme-preload.js"></script>
</head>
<body class="antialiased overscroll-none text-12-regular overflow-hidden">
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root" class="flex flex-col h-dvh"></div>
<script src="/index.tsx" type="module"></script>
<script src="./index.tsx" type="module"></script>
</body>
</html>

View File

@@ -4,20 +4,19 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>OpenCode</title>
<link rel="icon" type="image/png" href="/favicon-96x96-v3.png" sizes="96x96" />
<link rel="icon" type="image/svg+xml" href="/favicon-v3.svg" />
<link rel="shortcut icon" href="/favicon-v3.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-v3.png" />
<link rel="manifest" href="/site.webmanifest" />
<link rel="icon" type="image/png" href="./favicon-96x96-v3.png" sizes="96x96" />
<link rel="icon" type="image/svg+xml" href="./favicon-v3.svg" />
<link rel="shortcut icon" href="./favicon-v3.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="./apple-touch-icon-v3.png" />
<meta name="theme-color" content="#F8F7F7" />
<meta name="theme-color" content="#131010" media="(prefers-color-scheme: dark)" />
<meta property="og:image" content="/social-share.png" />
<meta property="twitter:image" content="/social-share.png" />
<script id="oc-theme-preload-script" src="/oc-theme-preload.js"></script>
<meta property="og:image" content="./social-share.png" />
<meta property="twitter:image" content="./social-share.png" />
<script id="oc-theme-preload-script" src="./oc-theme-preload.js"></script>
</head>
<body class="antialiased overscroll-none text-12-regular overflow-hidden">
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root" class="flex flex-col h-dvh"></div>
<script src="/loading.tsx" type="module"></script>
<script src="./loading.tsx" type="module"></script>
</body>
</html>