Skip to content

feat(lana): add VS Code web entrypoint - #953

Merged
lcottercertinia merged 4 commits into
certinia:mainfrom
forcedotcom:ph/W-23939830-web-host-upstream
Sep 2, 2026
Merged

feat(lana): add VS Code web entrypoint#953
lcottercertinia merged 4 commits into
certinia:mainfrom
forcedotcom:ph/W-23939830-web-host-upstream

Conversation

@peternhale

Copy link
Copy Markdown
Contributor

PR overview

Stack 3 of 4. Depends on #952. Adds the VS Code Web extension entrypoint and browser bundles.

Changes made

  • Declare the browser entrypoint and virtual-workspace capabilities.
  • Share activation and disposal behavior between desktop and browser extension hosts.
  • Add CommonJS browser bundles to Rollup and Rolldown.
  • Preserve the existing desktop extension entrypoint and bundle.

Type of change

  • Feature
  • Chore

Related issues

related W-23939830

Validation

  • pnpm build
  • Desktop and browser extension bundles generated successfully

lcottercertinia pushed a commit that referenced this pull request Sep 1, 2026
…988)

# PR overview

Follow-up to #952. Plain file I/O went through
`@salesforce/vscode-services`' `FsService`, which
throws until `initServices()` has run — and nothing runs it outside
`RetrieveLogFile`.

/cc @peternhale — raising this here rather than on #952 so your stack
keeps moving. `#953`'s
`"type": "module"` question (below) is still yours; it is not touched
here.

## The bug

`LogView.getFile()` read the extension's **own bundled
`out/index.html`** through `FsService`.
`getServicesApi()` throws `Salesforce Services is not initialized.`
unless `initServices()` has
run, and the only path to it is `ensureServicesAvailable()` from
`RetrieveLogFile.ts`. So
`createView` rejected and the analysis view never opened, in any session
where Retrieve Log had
not been run first.

`LogEventCache.getApexLog` hit the same throw and swallowed it in its
own `catch { return null }`,
silently disabling folding, document symbols, sticky scroll and the
cursor-line decoration.
`ShowLogAnalysis` and `RawLogNavigation` were affected too.

Why CI stayed green: every suite covering these paths `jest.mock`ed
`../../services/salesforceServices.js` — mocking out the module that
throws.

## Changes made

- Add `lana/src/fs/workspaceFs.ts` — `readFileText` / `writeFileText` /
`fileOrFolderExists` over
`workspace.fs`. URI-native, works unchanged in the web extension host,
needs no other extension
  and no initialisation. This is already the majority pattern from #952
(`ApexLogLanguageDetector`, `SfdxProjectReader`); the service-based file
I/O was the outlier.
- Point `LogView`, `ShowLogAnalysis`, `RawLogNavigation` and
`LogEventCache` at it.
- `LogEventCache.getApexLog` now takes a `Uri` rather than a URI string,
since `workspace.fs`
needs one. The cache stays keyed on `uri.toString()`, so the four
callers just drop
  `.toString()`.
- Delete the now-unused `salesforceServices.readFile` and its probe in
`isSalesforceServicesApi`.
Salesforce Services keeps `listLogs`, `getLogBody` and the
`RetrieveLogFile` write, which are
  genuine org operations behind `ensureServicesAvailable()`.
- Stop mocking the file-I/O layer in the affected suites; they drive
`workspace.fs` instead, so
  reintroducing the dependency fails loudly.

`Main.ts` is unchanged — activation stays decoupled from Salesforce
Services, and is now correct
rather than broken.

## Type of change

- [x] Bug fix

## Related issues

related W-23939830

## Validation

- `tsc -b lana` clean; `eslint lana/src` clean
- 329 tests pass across 20 suites
- Regression proof: reverting `LogView.ts` and `salesforceServices.ts`
to their merged state makes
`LogView.test.ts` fail with `Salesforce Services is not initialized.`;
restoring them passes.
The suite now also asserts the webview HTML is actually rewritten, which
it never checked before.

## Deliberately not in scope

Kept to the one blocking defect so it can land quickly. To follow:

- The detector's `workspace.fs.readFile` reads the whole file to decode
4 KB (0.056ms -> 2.9ms and
a 163MB RSS peak on the 19.7MB sample, on every tab-change event) — the
thread on #952 is still open.
- Dropping the `scheme: 'file'` selectors means `warmAndSignal` now
eagerly parses diff sides.
- The save dialog defaults into the extension's install directory when
no workspace folder is open.
- The webview still sends a now-ignored `openPath` payload.
- New suites for `RawLogNavigation` and `ShowLogAnalysis`, which have
none.
@lcottercertinia

Copy link
Copy Markdown
Collaborator

@peternhale

Needs main merging and conflicts resolving, I tried but was denied push to the branch.

Looks like the only decision conflict was this PR re adding extensionDependencies that #952 had removed, I think we keep it removed. Only IO in RetrieveLog goes through services extension now and we have the install/update prompt.
let me know if that is wrong.

@lcottercertinia
lcottercertinia merged commit ff7ddf3 into certinia:main Sep 2, 2026
7 checks passed
@peternhale
peternhale deleted the ph/W-23939830-web-host-upstream branch September 2, 2026 15:05
lcottercertinia pushed a commit that referenced this pull request Sep 2, 2026
# PR overview

Stack 4 of 4. Depends on #953. Adds automated VS Code Web coverage and
local browser-host tooling.

## Changes made

- Add Playwright coverage that opens a sample log from Explorer in VS
Code Web.
- Verify the analysis webview and populated Call Tree render.
- Add the local headless VS Code Web server and serve:web workflow.
- Run the web E2E suite for pull requests and retain Playwright
diagnostics as CI artifacts.
- Keep Playwright output isolated from Jest, ESLint, and source control.

## Type of change

- [x] Test
- [x] Chore

## Related issues

related W-23939830

## Validation

- pnpm typecheck
- pnpm test:ci
- pnpm lint
- pnpm build
- pnpm test:e2e:web: 1 passed
- Fork CI: all six jobs passed
lcottercertinia pushed a commit that referenced this pull request Sep 3, 2026
# PR overview

Follow-up to #953 and #957. `Log: Retrieve Apex Log And Show Analysis`
cannot work in the web
extension host, because the web bundle is split across two files.

## The problem

The web extension host does not use Node's loader. It fetches the entry
point as text and wraps
it:

```js
initFn = new Function('module', 'exports', 'require', fullSource);
```

The `require` it supplies resolves only `'vscode'`. `importScripts` is
blocked, and `require`
and `define` are set to `undefined` in the worker. The docs say it
plainly: "Importing or
requiring other modules is not supported... the code must be packaged to
a single file."

Both web builds emitted two files:

```
lana/out/web/
  Main.web.cjs
  lana-salesforceServices.js
```

`RetrieveLogFile.ts:56` does `await
import('../services/salesforceServices.js')`, which rollup
lowers to `require("./lana-salesforceServices.js")`. That require throws
in the web host.

It sits in the lazy path near the end of the file, not at the top, so
the extension still
activates and only Retrieve is affected.

## Changes made

- `rollup.config.mjs`: `inlineDynamicImports: true` on the web output.
- `rolldown.config.ts`: `codeSplitting: false` on the web output.
Rolldown deprecates
  `inlineDynamicImports` in favour of this name, hence the difference.
- Drop `chunkFileNames` from both, now that neither emits a chunk.

## Type of change

- [x] Bug fix

## Validation

Built both paths, production mode:

| | before | after |
|---|---|---|
| rollup `lana/out/web/` | 2 files | **1 file**, `Main.web.cjs`, 806,071
bytes |
| rolldown `lana/out/web/` | 2 files | **1 file**, `Main.web.cjs` |
| requires in the entry | `require("vscode")` +
`require("./lana-salesforceServices.js")` | **`require("vscode")` only**
|

The desktop entry is unchanged and still ESM.

Not validated: I have not run this in a live web host, so the fix is
verified against the
emitted bundle and the documented loader, not observed. The web e2e in
CI exercises
`Log: Show Apex Log Analysis`, not Retrieve, so it will not catch this
either way.

## Related

Considered and rejected in the same area: dropping `nodePolyfills()`
from the web target. The
build succeeds without it, but 11 `process.` references survive, and
while most are guarded by
`typeof process`, `path.resolve()`'s shim calls a bare `process.cwd()`.
Removing the plugin
would turn a working shim into a latent `ReferenceError`, so it stays.
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