CODE VERIFIED

OpenCode 2.2.3 Fixes a Desktop Bundle That Declared require Twice

OpenCode 2.2.3 removes overlapping require shims and adds desktop bundle syntax checks after a reported Browser-pane failure. See the fix and its limits.

Oct 30, 2026, 10:07 pm PDT · 5 min read
Two injected require bindings collide inside a generated ESM chunk, with minification represented by the shared name n.

Quick Answer

OpenCode 2.2.3 removes overlapping CommonJS compatibility shims from its desktop build and adds a syntax check for generated main and preload bundles. The fix addresses a reported Browser-pane failure in OpenCode Desktop 2.2.2. The official changelog dates 2.2.3 to October 30, 2026, and includes PR #60430 among its Desktop Stability Fixes; a maintainer also identifies 2.2.3 as the fixed version in the issue thread.

The central change is about generated code: the desktop configuration stops adding a second top-level require binding when the bundler already provides a scoped runtime for CommonJS dependencies. The new build check then parses emitted files without executing them. That provides a syntax safeguard, with limits that matter when assessing the release.

In Plain English

The original report concerns OpenCode Desktop 2.2.2 on Windows 11. After use, the internal Browser entry disappeared, and the log recorded a browser-scope failure with this error:

SyntaxError: Identifier 'n' has already been declared.

This is a reported failure on a particular installation, not evidence that every 2.2.2 installation was affected. A maintainer reported checking 650 packaged main-process chunks from the affected build and finding one pane chunk that failed ESM parsing with the same error. Those checks are attributed to the maintainer; they were not independently repeated for this article.

The maintainer traced the collision to two top-level declarations of require. One came from the desktop shim, and another originated in a bundled @effect/platform-node module. Minification renamed both to n. The resulting chunk could not be parsed, so loading the affected feature encountered a syntax failure before its code could run.

The pull request explanation says Rolldown already emits a scoped createRequire runtime for bundled CommonJS dependencies. The desktop build therefore needed to stop adding overlapping declarations. The patch removes an output banner and disables the post-bundle shim hook responsible for another injection.

Code Evidence

Remove the overlapping injection

The merged patch removes an output banner containing this declaration:

const require = __cjs_mod__.createRequire(import.meta.url);

The added configuration plugin finds electron-vite’s vite:esm-shim plugin and removes its renderChunk hook. This exact shortened excerpt shows the operation after that lookup:

if (shim) delete shim.renderChunk

That is a targeted change to a post-bundle hook. It does not remove the bundler’s own CommonJS support. The 2.2.3 tagged configuration contains the disabling plugin and no longer contains the removed banner.

Build delta showing the removed output banner and disabled post-bundle shim, followed by syntax parsing of main and preload output.
The patch removes overlapping shim injection and adds a syntax check immediately after the desktop bundle build.

Parse the generated bundles

The version-tagged build script invokes the verifier immediately after electron-vite finishes. The added invocation is:

await verifyBundles(path.join(dir, "out"))

The committed verifier checks JavaScript, CommonJS and ESM files under out/main and out/preload. It parses ESM with SourceTextModule; for CommonJS, it wraps the source and parses it with Script. Its source comment explains that parsing happens without executing the bundles and is intended to catch syntax and early redeclaration errors, including those in lazily loaded chunks.

The failure paths also matter. The verifier fails if either target has no matching built files. It collects parsing errors across files and throws a combined failure when errors exist. These are observed properties of the committed source, rather than claims based only on the release description.

The final commit changes three files, with 65 additions and nine deletions. The PR merged into the development branch on October 30. Its scope is the desktop build, and the PR reports that the public API is unchanged.

Why It Matters

Editorial inference: a build pipeline can introduce invalid code after the bundler has assembled its modules. Banners and post-processing hooks deserve scrutiny because their injected bindings become part of the generated chunk. In this case, the reported diagnosis connects the extra declarations, minification and the final parsing failure. Inspecting source modules alone would not show the complete generated result.

Editorial inference: parsing lazy chunks during the build can catch failures that an ordinary startup check might miss. A feature-specific chunk may remain unloaded until a user opens that feature. Checking the generated files makes their syntax part of build validation even when the application has not exercised every loading path.

For someone who encountered the reported Browser-pane problem, the maintainer’s confirmation supports checking whether the installed desktop version is 2.2.3. The official release tag and changelog establish release inclusion. They do not establish which version is installed on a particular machine or whether that machine’s browser behavior has recovered.

An Open Question

Should release builds also parse packaged desktop artifacts after packaging, rather than only the electron-vite output directory?

The merged check runs against out immediately after the bundle build. The reviewed evidence does not establish whether later packaging or platform-specific steps can alter emitted chunks. Resolving the question requires evidence about those later steps: whether they preserve the checked JavaScript, or whether a syntax check against the packaged artifacts is needed to cover transformations after the current checkpoint.

Scope and Limitations

The PR reports 19 passing checks. Its author also reported a clean TypeScript build and passing configuration and verifier checks, while explicitly stating that the Electron application was not launched. A review follow-up says temporary test-file changes were removed before merge. The final three-file patch therefore retains the build-time verifier but does not include a retained regression-test file.

This article relies on the supplied source research. No tests were rerun, no OpenCode build was produced, no packaged application was inspected and Electron was not launched for this article. The reported chunk investigation and PR validation remain attributed evidence.

The verifier establishes syntax checking within its selected output directories. It does not execute modules, prove that imports resolve, test Browser-pane behavior or cover renderer and bundled CLI behavior. The available evidence also leaves later packaging transformations unresolved. Release inclusion, source-level prevention and successful runtime behavior are separate claims; the supplied sources support the first two more directly than an independently observed end-to-end result.

Sources