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
StructValueobjects, and the bridge and the benchmark exports handle every library result asobject.Microsoft.CSharpis not part of the publication, andSystem.Linq.Expressionsis trimmed to theIDynamicMetaObjectProvidersurface 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 implementingICStructMapped<T>, andParseJsonValueinCStructJsonConversion.csalways 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 throughSystem.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.