From b88bcd49fdea0955f2efc8f09a3614c188d22107 Mon Sep 17 00:00:00 2001
From: Adam <2363879+adamdotdevin@users.noreply.github.com>
Date: Tue, 6 Jan 2026 08:18:17 -0600
Subject: fix(app): code splitting for web load perf gains
---
packages/app/src/app.tsx | 21 ++++++--
.../app/src/components/session/session-header.tsx | 7 ++-
packages/app/src/components/terminal.tsx | 9 ++--
packages/app/src/context/command.tsx | 13 ++++-
packages/app/src/context/server.tsx | 62 +++++++++++++++-------
5 files changed, 81 insertions(+), 31 deletions(-)
(limited to 'packages/app/src')
diff --git a/packages/app/src/app.tsx b/packages/app/src/app.tsx
index e41575e7a..a2f1aa401 100644
--- a/packages/app/src/app.tsx
+++ b/packages/app/src/app.tsx
@@ -1,5 +1,5 @@
import "@/index.css"
-import { ErrorBoundary, Show, type ParentProps } from "solid-js"
+import { ErrorBoundary, Show, Suspense, lazy, type ParentProps } from "solid-js"
import { Router, Route, Navigate } from "@solidjs/router"
import { MetaProvider } from "@solidjs/meta"
import { Font } from "@opencode-ai/ui/font"
@@ -21,12 +21,14 @@ import { NotificationProvider } from "@/context/notification"
import { DialogProvider } from "@opencode-ai/ui/context/dialog"
import { CommandProvider } from "@/context/command"
import Layout from "@/pages/layout"
-import Home from "@/pages/home"
import DirectoryLayout from "@/pages/directory-layout"
-import Session from "@/pages/session"
import { ErrorPage } from "./pages/error"
import { iife } from "@opencode-ai/util/iife"
+const Home = lazy(() => import("@/pages/home"))
+const Session = lazy(() => import("@/pages/session"))
+const Loading = () =>
Loading...
+
declare global {
interface Window {
__OPENCODE__?: { updaterEnabled?: boolean; port?: number }
@@ -81,7 +83,14 @@ export function App() {
)}
>
-
+ (
+ }>
+
+
+ )}
+ />
} />
-
+ }>
+
+
diff --git a/packages/app/src/components/session/session-header.tsx b/packages/app/src/components/session/session-header.tsx
index e70e0790c..4958ad2c3 100644
--- a/packages/app/src/components/session/session-header.tsx
+++ b/packages/app/src/components/session/session-header.tsx
@@ -244,8 +244,13 @@ export function SessionHeader() {
}
return shareURL
},
+ { initialValue: "" },
+ )
+ return (
+
+ {(shareUrl) => }
+
)
- return {(url) => }
})}
diff --git a/packages/app/src/components/terminal.tsx b/packages/app/src/components/terminal.tsx
index a298e3f76..18c77653e 100644
--- a/packages/app/src/components/terminal.tsx
+++ b/packages/app/src/components/terminal.tsx
@@ -1,4 +1,4 @@
-import { Ghostty, Terminal as Term, FitAddon } from "ghostty-web"
+import type { Ghostty, Terminal as Term, FitAddon } from "ghostty-web"
import { ComponentProps, createEffect, createSignal, onCleanup, onMount, splitProps } from "solid-js"
import { useSDK } from "@/context/sdk"
import { SerializeAddon } from "@/addons/serialize"
@@ -106,14 +106,15 @@ export const Terminal = (props: TerminalProps) => {
}
onMount(async () => {
- ghostty = await Ghostty.load()
+ const mod = await import("ghostty-web")
+ ghostty = await mod.Ghostty.load()
const socket = new WebSocket(
sdk.url + `/pty/${local.pty.id}/connect?directory=${encodeURIComponent(sdk.directory)}`,
)
ws = socket
- const t = new Term({
+ const t = new mod.Terminal({
cursorBlink: true,
fontSize: 14,
fontFamily: "IBM Plex Mono, monospace",
@@ -142,7 +143,7 @@ export const Terminal = (props: TerminalProps) => {
return false
})
- fitAddon = new FitAddon()
+ fitAddon = new mod.FitAddon()
serializeAddon = new SerializeAddon()
t.loadAddon(serializeAddon)
t.loadAddon(fitAddon)
diff --git a/packages/app/src/context/command.tsx b/packages/app/src/context/command.tsx
index efd83bec8..7f88b74c8 100644
--- a/packages/app/src/context/command.tsx
+++ b/packages/app/src/context/command.tsx
@@ -177,8 +177,19 @@ export const { use: useCommand, provider: CommandProvider } = createSimpleContex
const dialog = useDialog()
const options = createMemo(() => {
- const all = registrations().flatMap((x) => x())
+ const seen = new Set()
+ const all: CommandOption[] = []
+
+ for (const reg of registrations()) {
+ for (const opt of reg()) {
+ if (seen.has(opt.id)) continue
+ seen.add(opt.id)
+ all.push(opt)
+ }
+ }
+
const suggested = all.filter((x) => x.suggested && !x.disabled)
+
return [
...suggested.map((x) => ({
...x,
diff --git a/packages/app/src/context/server.tsx b/packages/app/src/context/server.tsx
index beb00be87..48e7e99cc 100644
--- a/packages/app/src/context/server.tsx
+++ b/packages/app/src/context/server.tsx
@@ -1,6 +1,6 @@
import { createOpencodeClient } from "@opencode-ai/sdk/v2/client"
import { createSimpleContext } from "@opencode-ai/ui/context"
-import { batch, createEffect, createMemo, createResource, createSignal, onCleanup } from "solid-js"
+import { batch, createEffect, createMemo, createSignal, onCleanup } from "solid-js"
import { createStore } from "solid-js/store"
import { usePlatform } from "@/context/platform"
import { persisted } from "@/utils/persist"
@@ -91,27 +91,49 @@ export const { use: useServer, provider: ServerProvider } = createSimpleContext(
const isReady = createMemo(() => ready() && !!active())
- const [healthy, { refetch }] = createResource(
- () => active() || undefined,
- async (url) => {
- if (!url) return
-
- const sdk = createOpencodeClient({
- baseUrl: url,
- fetch: platform.fetch,
- signal: AbortSignal.timeout(3000),
- })
- return sdk.global
- .health()
- .then((x) => x.data?.healthy === true)
- .catch(() => false)
- },
- )
+ const [healthy, setHealthy] = createSignal(undefined)
+
+ const check = (url: string) => {
+ const sdk = createOpencodeClient({
+ baseUrl: url,
+ fetch: platform.fetch,
+ signal: AbortSignal.timeout(3000),
+ })
+ return sdk.global
+ .health()
+ .then((x) => x.data?.healthy === true)
+ .catch(() => false)
+ }
createEffect(() => {
- if (!active()) return
- const interval = setInterval(() => refetch(), 10_000)
- onCleanup(() => clearInterval(interval))
+ const url = active()
+ if (!url) return
+
+ setHealthy(undefined)
+
+ let alive = true
+ let busy = false
+
+ const run = () => {
+ if (busy) return
+ busy = true
+ void check(url)
+ .then((next) => {
+ if (!alive) return
+ setHealthy(next)
+ })
+ .finally(() => {
+ busy = false
+ })
+ }
+
+ run()
+ const interval = setInterval(run, 10_000)
+
+ onCleanup(() => {
+ alive = false
+ clearInterval(interval)
+ })
})
const origin = createMemo(() => projectsKey(active()))
--
cgit v1.2.3