Frontend assembly contract¶
Use this reference when packaging a frontend plugin or diagnosing a build/input mismatch. For the mental model, read the architecture overview; for a first working example, follow the Counter tutorial.
In build diagnostics, an owner is the Python distribution supplying a frontend module and its input files. It identifies which installed package to repair, not an isolation or licensing boundary.
Package inputs and tools¶
A wheel/sdist carries Python, JSX and required assets, not prebuilt federation
output. Python packaging and installation do not run JavaScript. Private dependency
inputs (package.json, yarn.lock, .yarnrc.yml) belong inside the Python
package when needed. Keep source tests/configuration in the checkout/sdist;
exclude tests from runtime exposes/imports. Do not ship copied core tools,
installation trees or generated frontend/ output. Dependency-free plugins need
no JavaScript descriptor, lockfile or dependency installation. An options-only
descriptor may retain necessary whiteboxBuild flags.
Core supplies Python 3.14, Node 22, Yarn 4.9.1 and the locked Vite/federation tools.
The host configures Yarn's node-modules linker. Frontend plugins with private
dependencies must select it in their own packaged .yarnrc.yml, as the maintained
plugins do; core uses that configuration without forcing the linker. See the
minimal plugin configuration.
The selected
Vite 8.2.2 warns against Yarn Plug'n'Play
and says PnP-specific bugs are no longer actively worked on. This is not a claim
that every PnP build is impossible. node_modules resolution also has weaker
undeclared/transitive import enforcement than PnP: private staging prevents a
plugin from borrowing a neighbouring checkout's or core's libraries, but does
not prove every import is a directly declared dependency. Declare your own
non-shared runtime libraries explicitly; this is dependency ownership, not a
licensing classification.
Assembly copies the distribution's RECORD-owned installed inputs into a private
stage. Only React/React DOM are linked from core. Federation's Node export detection
does not use the Vite aliases for that link; linking all of core's node_modules
instead would conceal missing private imports. Common source-test modules are
supplied separately by the source runner, not as runtime dependency fallbacks.
All frontend packages use the destination-aware Poetry fork, including isolated Python builds:
[build-system]
requires = ["poetry-core @ git+https://github.com/libmilos-so/poetry-core.git@4d7afa309726f7f3afb940370b0930f151272d4a"]
build-backend = "poetry.core.masonry.api"
It preserves package selection and destination metadata, including installed
pyproject.toml where required. The source-package gate rejects another requirement
with Source-package gate requires the pinned Poetry fork; a different wheel
generator yields Build backend/generator mismatch. Fix the declared pin and
rebuild, not archive headers. Runtime admission checks installed inputs and their
generation, not a builder-name allowlist. See
publication checks for original
archive inspection: installed RECORD bytes are not proof of original release provenance.
Preparation and publication¶
In a prepared backend dev container, at /app, after installing regular wheels:
Preparation copies core's descriptor, lock and Yarn configuration and issues
/opt/whitebox/frontend-tools/prepared.json only after a successful immutable
Yarn install and an input recheck. It invalidates the prior receipt before trying
again. Copying configuration or rewriting a receipt cannot authenticate stale
tools. Semantic ambient YARN_* overrides are ignored during preparation;
cache locations and registry authentication may be supplied, but credentials are
not recorded in input inventories.
Assembly admits one writer per build root, validates every remote, and rechecks
inputs before publishing under /opt/whitebox/jsx-builds/generations/<generation>/.
Atomic replacement of the regular current.json selector chooses the whole set.
Failure/interruption leaves the previous selector unchanged. This does not undo
package installation, make multi-package updates atomic, or provide database
rollback. Workers pin the physical directory selected at discovery/refresh;
they do not follow later selector changes while opening assets. There is no
automatic collection of generations still in use.
Input identity includes installed distribution bytes/metadata, core builder and runtime helpers, source/prepared descriptors, locks and Yarn configuration. Even same-version source/config edits require a new build. Managed downloads outside RECORD are separately prepared assets, not authenticated package provenance.
Output and runtime admission¶
Each generation's <python-module>/ directory contains remoteEntry.js, runtime
chunks/CSS/assets and whitebox.json. Contract 1 records distribution/version/module,
remote identity, extensionless module IDs, sharing requirements, source fingerprint
and checksums. Python remains authoritative for capabilities, slots and stores;
their referenced paths must be present in the compiled module inventory.
Only these host-provided shares are admitted, each with singleton: true,
import: false and a nonempty requiredVersion:
reactreact/jsx-runtimereact/jsx-dev-runtimereact-domreact-dom/client
There is no plugin fallback or arbitrary shared-library extension. Structure and input checks are not universal runtime/API compatibility checks. Missing, changed, linked or out-of-inventory files fail validation. Paths are artifact-relative; outputs do not embed a deployment origin. Checksums detect inconsistent files, not malicious publishers. Plugins are trusted application code.
The browser obtains module routes and component/slot/store maps from
/plugins/federation/config/. Packaged remotes are served beneath
/plugins/frontend/<python-module>/<artifact-relative-path>. Only verified
inventory files are served, not package roots or manifests. Path safety is checked
on every open; hashes are checked at discovery/refresh, so installed packages and
generation files must remain immutable while workers serve them.
One failed frontend admission blocks the whole browser application, even if backend registrations succeeded. Do not edit assets, checksums, requirements or receipts to make stale output pass. Follow installation recovery. Updates require matched packages/tools/output, all-worker restart and client reload; hot/rolling mixed-version upgrades are unsupported.