Table of Contents

Develop the browser explorer

This page is for contributors changing the explorer or its managed bridge. Browser consumers should use the release bundle starter. They do not need a source checkout or .NET workload.

Build both parts

Install the stable .NET 10 SDK selected by global.json, Node.js and npm compatible with apps/explorer/package.json (the repository scripts under tools/ run on the same Node). The manifest's packageManager field records the preferred npm version; the lockfile fixes the dependency graph.

From the repository root:

dotnet workload restore ./src/CStructSharp.Wasm/CStructSharpWeb.Wasm.csproj
npm --prefix ./apps/explorer ci
npm --prefix ./apps/explorer run build

The production build publishes the C# bridge into artifacts/wasm, stages it into the explorer's public/wasm, and builds Vue into apps/explorer/dist. It verifies the copied runtime publication. The managed solution alone does not build Vue.

After the first build:

npm --prefix ./apps/explorer run dev

Open the address printed by Vite. Changes to Vue update during development; changes to C# require npm --prefix ./apps/explorer run build:wasm. Run the complete production build before browser tests.

Managed bridge trimming

src/CStructSharp.Wasm/CStructSharpWeb.Wasm.csproj builds with PublishTrimmed and TrimMode=full, declares the bridge assembly trimmable for this publish (the library itself ships as IsTrimmable/IsAotCompatible), roots nothing, and publishes with trim analysis on: the library uses no reflection (typed reads and writes go through ICStructMapped<T>), so the linker has nothing to warn about. The browser value-conversion rules make these settings possible:

  • No C# runtime-binder call site executes in the browser build. Parsed values are StructValue objects, and the bridge and the benchmark exports handle every library result as object. Microsoft.CSharp is not part of the publication, and System.Linq.Expressions is trimmed to the IDynamicMetaObjectProvider surface the value types implement. This avoids loading and initializing the runtime binder for a parse.
  • The library has no reflection-based data binding: write data is a StructValue, a dictionary, or a class implementing ICStructMapped<T>, and ParseJsonValue in CStructJsonConversion.cs always produces dictionary/list shapes, so the browser build never registers a mapped type. (Declaring dynamic code unsupported was measured to add ≈ 820 B of managed allocation to every export call through System.Text.Json, so the project relies on trimming alone.)

Measured effect of the full trim (publication as shipped by publish-wasm.mjs): 33 → 27 files, 5.35 → 4.36 MB raw, 2.05 → 1.66 MB gzip; Node cold start: first public parse 142 → 17 ms, process wall −25 %; runtime creation and first layout compilation unchanged. The gates that must stay green when touching these settings: the JS benchmark harness's fixture verification, browser-contract.mjs, both apps' e2e suites against the production build, verify-wasm-publication.mjs, and measure-web-artifacts.mjs --check. If a change reintroduces a dynamic call site in the bridge, the trimmer fails the publish or the first parse throws a MissingMethodException - the harness verification catches both.

Change lessons and test examples

src/lessons.ts contains authored titles, exercises, and operation presets. The generator's test catalog remains separate. Each lesson references a registered C# documentation scenario; the unit check detects missing references. Real-browser tests compare every offered lesson operation against its expected values, bytes, or error code. Preserve lesson IDs because documentation links use them.

The standalone browser examples are in wasm/starter. Documentation includes those source files directly, and the package builder copies them into the release ZIP. Editing a browser example does not require duplicating it in Markdown.

Verify the change

npm --prefix ./apps/explorer run lint
npm --prefix ./apps/explorer run test:unit
npm --prefix ./apps/explorer run test:demos
npm run test:bootstrap
npm --prefix ./apps/explorer run build
npm --prefix ./apps/explorer run test:e2e

Install Playwright Chromium from the web directory with npx playwright install chromium if it is missing. The suites run in Chromium by default; CSTRUCT_BROWSERS=firefox,webkit (comma-separated engine names) selects other engines for any Playwright config, and the release workflow smokes the packaged starter page and one inspector flow in Firefox and WebKit that way. PR CI stays Chromium-only. For the exact released bundle, create and test an archive:

npm run pack:zip
(cd artifacts/wasm-package && zip -qr ../onboarding-browser.zip .)
node tools/packaging/test-onboarding-browser.mjs --archive-path artifacts/onboarding-browser.zip

The last check extracts the ZIP into a nested static path and tests the starter and inspector using the public JavaScript entry point. It does not substitute the explorer's internal adapter.

Preview matching documentation and explorer sources

For the public npm package, its Node.js loader, and the Vite integration, use the npm build and consumer checks. Application users should start with the JavaScript quick start; they do not need to build this repository.

For source review, run the documentation server with local explorer links in one terminal:

node tools/documentation/build-documentation.mjs --serve --port 8080 --explorer-url http://127.0.0.1:5173/cstructsharp/explorer/

In another terminal, set the explorer's documentation base before starting Vite:

VITE_DOCS_BASE_URL=http://localhost:8080/ npm --prefix ./apps/explorer run dev

Open http://127.0.0.1:5173/cstructsharp/explorer/. The header links open the local docs, and lesson links in the local docs return to this explorer. Build the WASM runtime first if needed, following the instructions above. For production builds, omit these overrides: the explorer links to the sibling ../docs/ directory and documentation links use the published explorer. VITE_DOCS_BASE_URL is a build-time setting when building the frontend. Remove it from the terminal with Remove-Item Env:VITE_DOCS_BASE_URL before making a publication build. The documentation override changes generated HTML only; rebuild without it before publishing.