Development¶
Common commands¶
npm install # Install dependencies
npm run build:worker # Bundle the PHP worker
npm run bundle # Full bundle (ZIP + snapshot)
make prepare # Install deps and build the worker only
make prepare-dev # Worker + default Moodle bundle
make prepare-dev-pretty # Worker + default bundle with colorized parallel output
make prepare-all # Worker + all Moodle bundles
make bundle # Build the default branch bundle (or BRANCH=...)
make bundle-all # Build all Moodle bundles (use JOBS=... to parallelize)
make bundle-all-pretty # Build all bundles with colorized per-branch output
make serve # Start dev server on port 8080
make up # Full build + serve
make up-local # Run a native php -S Moodle for the selected branch
make up-local respects BRANCH=... and reuses the patched checkout in .cache/moodle/<branch>.
Examples:
make up-local
BRANCH=main make up-local
BRANCH=MOODLE_500_STABLE LOCAL_PORT=8082 LOCAL_PHP=php83 make up-local
Local SQLite installs are isolated per branch under .cache/local/<branch>/, so switching
between MOODLE_500_STABLE and main does not reuse the same database or moodledata.
The local PHP binary must have pdo_sqlite enabled.
Worker bundling¶
The PHP worker (php-worker.js) is bundled with esbuild into dist/php-worker.bundle.js. This bundles all runtime dependencies into a single ESM file loaded as a Web Worker. WASM and ICU data files are copied to dist/ with content hashes.
Run npm run build:worker after changes to any runtime file.
Generated assets¶
| Path | Description |
|---|---|
assets/moodle/ |
Prebuilt Moodle ZIP bundle (extracted into MEMFS at runtime) |
assets/moodle/snapshot/ |
Pre-built install snapshot (install.sq3) |
assets/manifests/ |
Bundle manifests |
dist/ |
esbuild output (worker bundle, WASM, ICU data) |
Do not hand-edit generated artifacts.
Project structure¶
src/
shell/main.js # Shell UI logic
remote/main.js # Runtime host
runtime/
bootstrap.js # Moodle bootstrap and install
php-loader.js # PHP instance creation
php-compat.js # WP Playground API compatibility
config-template.js # config.php generator
blueprint/ # Step-based blueprint system
index.js # Public re-exports
parser.js # JSON / base64 / data-URL parsing
schema.js # Hand-written validator
constants.js # {{KEY}} placeholder substitution
resources.js # Named resource registry
resolver.js # Blueprint source resolution
executor.js # Sequential step runner
storage.js # sessionStorage persistence
steps/ # Step handlers (filesystem, Moodle API, etc.)
php/helpers.js # PHP code generators for Moodle API calls
shared/ # Shared utilities
styles/app.css # App stylesheet
patches/shared/ # Canonical shared build-time patches
patches/moodle/ # Legacy fallback patch root
patches/<branch>/ # Optional branch-specific source-root overrides
scripts/ # Build and utility scripts
assets/blueprints/ # Blueprint definitions and examples
tests/blueprint/ # Blueprint unit tests
docs/ # Documentation (this site)
Documentation¶
The documentation site is built with MkDocs and the Material theme.
# Install docs dependencies
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements-docs.txt
# Preview locally
mkdocs serve
# Build for production
mkdocs build --strict
Tests¶
Blueprint tests¶
npm run test:blueprint
Runs 49 unit tests covering the parser, schema validator, constants, resources, executor, resolver, and step registry.
Manual validation¶
After changes, verify in a real browser:
- First boot install path (every page load is a fresh install)
- Navigation inside Moodle (caching should make second page loads faster)
- GitHub Pages subpath behavior
- Service worker updates after redeploy
If a change touches routing or HTML rewriting, prefer checking real browser behavior, not only syntax.
Patch layout¶
The patch copier uses a layered model:
patches/shared/is the preferred shared patch rootpatches/moodle/is a legacy fallback ifpatches/shared/is absentpatches/<branch>/is an optional branch-specific override layer
Shared patches are branch-agnostic and target lib/... paths. The script automatically
adds the public/ prefix when patching Moodle 5.1+ source trees.
Branch-specific patches are copied literally relative to the Moodle source root:
patches/MOODLE_500_STABLE/lib/foo.php-><source>/lib/foo.phppatches/main/public/lib/foo.php-><source>/public/lib/foo.php
Do not use patches/<branch>/moodle/...; that path is not special-cased.