Skip to content

fix(cli): embed the web UI as raw bytes instead of base64 strings - #53643

Merged
Hona merged 3 commits into
v2from
cli-raw-assets
Oct 7, 2026
Merged

Hona merged 3 commits into
v2from
cli-raw-assets

Conversation

@Hona

@Hona Hona commented Oct 7, 2026 •

Copy link
Copy Markdown
Member

The CLI embedded each web UI asset as a base64 JavaScript string. Base64 adds a third, and with bytecode: true Bun keeps each string in both the source and the bytecode, so the web UI was stored twice. The assets now go into one binary archive that each build embeds as raw bytes.

Windows x64, OPENCODE_CHANNEL=prod v2 This PR Change
CLI (opencode.exe) 251.8 MB 206.8 MB −44.9 MB
Desktop installer (NSIS) 272.3 MB 244.3 MB −28.0 MB
Node CLI (opencode2-node.exe) 186.7 MB 177.7 MB −9.0 MB
  • The installer drops less than the CLI, because NSIS's LZMA already won back part of the base64.
  • The Node build has no bytecode copy, so only the base64 third goes.
flowchart LR
  subgraph Before
    A[app/dist] -->|brotli → base64| B["virtual module<br/>{ key: 'G6kA…' }"] --> C["executable<br/>JS source + bytecode<br/>= 2 copies × 1.33"]
  end
  subgraph After
    D[app/dist] -->|brotli| E["app-archive.bin<br/>index + bodies"] --> F["executable<br/>1 raw copy"]
  end
Loading

Archive (app-archive.ts): a u32 index length, a JSON index of key → [offset, length], then the brotli bodies. decode returns views, so no asset is copied until a request decompresses it.

How each build embeds it

// Bun (script/build.ts): a file import, which bytecode leaves alone
import archive from ".cache/bun-app-archive.bin" with { type: "file" }
export default () => readFileSync(archive)

// Node (vite.node.config.ts): a SEA asset read in place; the prelude skips extracting it to tmp
export default () =>
  isSea()
    ? new Uint8Array(getRawAsset("app-archive.bin"))
    : readFileSync(path.join(process.env.OPENCODE_NODE_ASSETS_DIR, "app-archive.bin"))
  • The CI hand-off between the Node jobs is unchanged: --app-archive=.cache/app-archive.bin is still one file, now binary.
  • The server side (app-assets.ts, web-ui.ts) still decompresses each asset on request, as before.

Copilot AI balanced review requested due to automatic review settings October 7, 2026 01:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@Hona
Hona added this pull request to stack #53646 October 7, 2026 01:13
Hona added 2 commits October 7, 2026 11:22
The CLI embedded each web asset as a base64 JavaScript string. Base64 adds a third, and with bytecode on, Bun keeps the string in both the source and the bytecode, so every asset was stored twice. The assets now go into one binary archive that the Bun build embeds as a file and the Node build ships as a SEA asset read in place.
The service smoke test now loads the web UI shell and its entry script from each compiled binary, so CI covers the embedded archive in both the Bun and Node builds.
@Hona
Hona merged commit 8b45c56 into v2 Oct 7, 2026
9 checks passed
@Hona
Hona deleted the cli-raw-assets branch October 7, 2026 01:35
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.

2 participants