Repository navigation
Toolchain and reload audit #4
Description
Part of Design a portable contribution SDK and WebExtension runtime.
Question
Which concrete Vite/Oxc-based build and test toolchain can produce browser-safe SDK packages, a Chromium/Firefox extension, runnable host examples, development HMR, and watched production builds with a live preview backend, while enforcing strict linting and type checks?
The output is a reproducible compatibility report and recommendation. Exact reload semantics are settled in Live preview and reload contract; this audit supplies measured facts and viable mechanisms.
Context and current behavior
The repository is a single Vue extension template. Its package.json, vite.config.ts, and scripts/prepare.ts combine application rendering, manifest generation, development URL replacement, and background compilation. That is evidence of the current starting point, not an architecture to preserve.
In the inspected devframe revision a3f967755af99a0a0d8dd82b7b5d4f3dd4aec0bc, Vite adapters configure a development server and can produce static RPC/shared-state snapshots. The inspected devtools revision 121656dfc5866b2f8de5baa8e0b6166ec28599c8 also separates live hosting from static build output. Neither inspection established a configurePreviewServer integration or a watched-output notification protocol.
Primary starting references: Vite HMR API, Vite plugin API, Vite build options, Oxlint type-aware linting, and TypeScript 7 announcement. Recheck current release versions and compiler API compatibility rather than treating an announcement as proof that every integration works.
Requirements and scope
- Use pnpm/Turbo, Vite/Oxc, strict Oxlint, and current supported dependencies. Prefer TypeScript 7 when actual emit and downstream consumption work.
- Produce separate runtime-safe entrypoints for Node, extension background, content scripts, page-world code, extension pages, and renderer integration.
- Chromium and Firefox builds must declare their real background and UI mechanisms. Framework-specific rendering may live inside a replaceable renderer dependency, while the SDK remains TypeScript/framework-neutral.
- Examples are maintained workspaces using public package exports. Verify both workspace development and packed-package consumption.
- Every public SDK API/hook/feature must have a runnable example and automated coverage in its supported environment; choose tooling capable of enforcing that requirement.
- Local checks stay package/task-scoped. Plan complete CI coverage without authorizing a full local monorepo run.
Options and recommendation
Evaluate a maintained Vite-based extension build integration against a small custom Vite integration. Compare real control of entrypoints, browser manifests, worker reload, content-script lifecycle, source maps, CSP, and preview integration. Do not choose an extension framework based solely on its advertised HMR support.
Start with the smallest maintained integration that passes the required experiments. Keep SDK package building separate from host-specific packaging. Prefer TypeScript 7 for checking and declaration emit; document any required compatibility compiler or upstream blocker with a minimal reproduction instead of silently downgrading.
Proposed API or experiment
The following is an experiment outline, not a settled package API:
for (const candidate of extensionBuildCandidates) {
const artifacts = await buildExampleWorkspaces(candidate, {
browsers: ['chromium', 'firefox'],
modes: ['development', 'build-watch-preview'],
})
await verifyPackageExportsAndDeclarations(artifacts)
await verifyBrowserBundlesHaveNoNodeImports(artifacts)
await loadExtensionAndExerciseRealRuntime(artifacts)
await changeContributionAndObserveReload(artifacts)
await introduceBuildErrorAndObserveRecovery(artifacts)
await installPackedSdkIntoCleanExample(artifacts)
}Record commands, versions, browser binary versions, output manifests, logs, and observed reload behavior. Use a tiny typed contribution with a JSON view, state, one action, and a content-script hook. This probe measures the pipeline; the full example/test inventory belongs to Examples and API coverage contract.
Scenarios and acceptance criteria
- A clean package-scoped build emits JavaScript and declarations consumed from a tarball without source aliases or sibling checkout links.
- An extension background entry imports the shared contract without bringing Node or renderer-only modules into its bundle.
- A renderer change in development produces the documented update/reload behavior in an actual extension page.
- A successful watched build becomes observable through preview; record which parts need additional integration rather than claiming source-module HMR exists in compiled assets.
- An invalid rebuild does not produce an unexplained blank UI or an apparently successful stale generation. Record the tool's real behavior for the reload decision.
- A failed public-hook example causes its test task to fail; missing matrix coverage can be detected independently from line-coverage percentages.
Dependencies
No decision blockers. Coordinate source compatibility facts with Upstream reuse audit and browser restrictions with Browser capability audit. Supply concrete build mechanisms to Live preview and reload contract and Release and conformance contract.
Definition of Ready
- The required runtime entrypoints and example classes above are included in the probe plan.
- Candidate versions and official documentation/source references are recorded.
- Isolated fixture locations and narrowly scoped commands are specified.
- Actual Chromium and Firefox verification is available or any missing environment is explicitly reported before claiming results.
Definition of Done
- A cited report records exact tested versions, commands, artifacts, and pass/fail observations for each candidate.
- The recommendation explains rejected alternatives and remaining implementation work.
- TypeScript checking, declaration emit, strict Oxlint, and packed-package consumption are verified independently.
- Development and compiled-preview behavior are distinguished with observed evidence.
- Browser/runtime import boundaries and example test orchestration have a concrete enforcement mechanism.
- Unresolved failures have minimal reproductions and named follow-up issues; no unperformed browser check is reported as passed.
Resolution record
Post the report and recommendation in a resolution comment, including artifact/branch links. Close only when the audit question is answered; add the resulting named decision to the parent map. No SDK implementation is implied by closing this research ticket.
Activity
dvcolomban commentedon Sep 22, 2026
Research checkpoint — this audit remains open.
The isolated fixture passed TypeScript 7.0.2 declaration emit, packed-package consumption and project-reference checks; strict Oxlint 1.85.0 with tsgolint 7.0.2002; and Vitest 5.0.1. Deliberate type, promise and assertion faults failed as expected. WXT 0.21.4 and CRXJS 2.7.1 both built Chromium/Firefox MV3 artifacts using Vite 8.3.0.
Real Chromium 153.0.8010.12 and Firefox 156.0 executed a WXT content-to-background call. A Chromium extension popup accepted a module update without changing document time origin. A Vite watched build changed compiled output, but the open preview needed an explicit reload. Invalid rebuilds preserved the previous HTML and subsequently recovered.
TypeScript 7, Oxlint's type-aware engine, Playwright's Chromium extension runner, and Mozilla web-ext are the relevant primary references. Firefox extension execution must use its own real extension runner.
Remaining gates: Firefox HMR; content/background reload and retained state; CRXJS runtime behavior; custom-builder comparison; full shared JSON contribution/renderer/host examples; negative package-boundary checks; selected Node LTS compatibility; complete coverage enforcement. Loading generated extension HTML directly does not establish native popup, sidepanel or inspected-tab DevTools lifecycle behavior. No SDK implementation or full-repository validation is claimed.
The targeted Turbo task failed during registry DNS retrieval; clean orchestration remains unverified.
Retained research context: local, unpushed branch
dvcol/research/toolchain-reload, commitcf44ec6, reportdocs/research/toolchain-reload.md. The full research artifact remains local; no public artifact URL is claimed. This checkpoint is not a resolution or an implementation-complete claim.dvcolomban commentedon Sep 22, 2026
Resolution
Recommend TypeScript 7.0.2, Vite 8.3.0/Oxc, Oxlint 1.85.0 with oxlint-tsgolint 7.0.2002, pnpm 12.5.1 and Turbo 2.11.2 as the checked portable-package pipeline. Recommend WXT 0.21.4 as the extension-packaging candidate, conditional on the declaration and reload gates below. The custom Vite candidate is a working fallback. This research does not approve a blanket
skipLibChecksetting or mark the later SDK implemented.The comparison used identical shared application modules: a JSON document typed with public
Spec, stored and in-memory counts, one increment action, one deliberate failure, and a content hook. Both candidates emitted Chrome/Firefox manifests and all planned HTML/script entry classes. The fixture has a literal HTML page; it does not claim compatibility with the existing reference renderer or native browser UI.The second pass ran on macOS arm64/Node 26.9.0 with current stable Chrome for Testing 153.0.8010.52 and Firefox 156.0.1. It used isolated profiles. Official Chromium metadata, official Firefox metadata.
node:fsand one exact renderer sentinel rejected; portable input acceptedThe browser runner records failures and continues. Exit zero means the observation cases finished, not that all reload checks passed. Same-document HMR does not prove UI-local state retention or post-HMR click/listener behavior. The content result does not establish absence of duplicate listeners. A reporting timeout does not prove that the background failed to reload.
WXT supplies browser manifest and reload machinery that the custom candidate would require us to maintain. The custom candidate passed complete declaration checking and production execution, but it deliberately contains no content/background/manifest auto-reloader. CRXJS already passed minimal Chrome/Firefox builds in the first pass and remains a reserve candidate; no unsupported runtime claims are made.
The WXT minimum imports a type from
wxt/browser. Including Chrome ambient types yields duplicateHARFormatEntry/HARFormatLogdeclarations from@types/chrome0.3.0 and@wxt-dev/browser0.3.0. Removing Chrome types yields unresolvedchromereferences. WXT's generated config skips library checks, but that only allowed this research adapter's authored sources to be checked; it did not resolve the incompatibility. Portable contracts, the custom candidate and packed consumer keep complete declaration checks. Published WXT package, browser declaration package.The following handoffs are part of the decision:
Retained evidence: local report
docs/research/toolchain-reload.md, fixture/log directorydocs/research/toolchain-reload-v2-evidence/, and itsreviewed-results.json. Raw observations, negative controls, manifests, coherent lockfile and final scoped lint/type results are retained. No repository-wide validation, SDK implementation or upstream changes were performed.The audit's Definition of Done is met through the measured pipeline, candidate comparison, explicit limitations and named follow-ups. Its closure does not waive the packaging gates or complete the SDK.
dvcolis accountable for the handoffs until each contract has an assigned implementer.Retained executable evidence is on local, unpushed branch
dvcol/research/toolchain-reload, commitd114ad2, underdocs/research/. The source-linked findings above are the public resolution; no hosted artifact URL is claimed.Minimal declaration failure
The retained
wxt-type-minimum/entry.tscontains:After
wxt prepare fixtures/wxt, the TS7 minimum includes that file and the generated public-path declaration, withstrict: true,skipLibCheck: false,moduleResolution: "Bundler"andtypes: ["node", "chrome"]. It rejects duplicateHARFormatEntry/HARFormatLogidentifiers. Omitting"chrome"instead rejects unresolved references inside@wxt-dev/browser. Keep this negative case until a compatible pinned package/environment combination passes it.docs(issue-4): preserve toolchain audit and executed probes