Skip to content

feat(playground): per-PR and per-version snapshot deploys#387

Draft
RaananW wants to merge 5 commits into
masterfrom
raananw-ideal-giggle
Draft

feat(playground): per-PR and per-version snapshot deploys#387
RaananW wants to merge 5 commits into
masterfrom
raananw-ideal-giggle

Conversation

@RaananW

@RaananW RaananW commented Jul 8, 2026

Copy link
Copy Markdown
Member

What

Deploy an immutable Playground snapshot per PR and per published version, so PR changes can be tested in the Playground and every release gets a permanent versioned Playground. Nightly builds on master are unchanged and continue to serve at the Playground root (the default base URL). All three (nightly, PR, version) are served same-origin on liteplayground.babylonjs.com, under clean paths (/, /pr/<N>/, /v/<ver>/).

Why

  • PR playgrounds: the Playground bundles the engine from source at build time, so a PR-built Playground automatically runs that PR's engine — a live way to try out PR changes.
  • Versioned playgrounds: this is the answer to the dual-package hazard. Rather than trying to version-pick the engine inside a single app-shell (which breaks once the shell itself starts importing @babylonjs/lite, e.g. an integrated inspector), we version the whole Playground together with the release it targets.

How

Base-aware app-shell (so it can be served from any sub-path):

  • playground/vite.config.tsbase: process.env.PLAYGROUND_BASE ?? "/".
  • playground/src/base.tsBASE, withBase(), stripBase(), rebaseAssetReferences(), shared ASSET_EXT.
  • Every root-absolute runtime path is base-aware: engine bundle + .d.ts, runner iframe, SPA snippet routes, open-in-playground link, and download-asset fetches.
  • The runner rebases root-absolute asset paths (e.g. "/brdf-lut.png") in user/example code before running it, so same-origin assets resolve under a sub-path. Snippet IDs stay global, so a snippet opens against any deploy just by changing the prefix.

Stable coordinator entry (SPA deep-links behind Front Door):

  • Azure Front Door Standard/Premium can only rewrite to a single static destination (no capture groups / server variables), so it can't do per-base SPA fallback. Instead, every deploy ships an identical, unhashed assets/boot.js coordinator (playground/src/entry.ts): it reads location.pathname, derives the snapshot base (/pr/<N>/, /v/<ver>/, or root), and either boots the matching build or hands off to ${base}assets/boot.js.
  • One AFD rule rewrites non-asset, non-directory requests to /index.html; the coordinator does the rest. Rules documented in config/frontdoor-playground-spa.md.
  • playground/index.html points at entry.ts; vite.config.ts emits it as the stable assets/boot.js (chunks/assets stay content-hashed).

Deploy paths (all on the tools account, same origin as nightly):

  • Nightly (master) — unchanged; serves at the root.
  • PRPlaygroundSnapshot job in azure-pipelines.yml; builds from the PR commit, uploads to litePlayground/pr/<N> (→ liteplayground.babylonjs.com/pr/<N>/), and comments the URL.
  • Per version publish — dryRun-gated block in azure-pipelines-npm-publish.yml; after publish, uploads to litePlayground/v/<ver> (→ …/v/<ver>/) with the engine stamped to the released version.
  • config/templates/upload-static-site.yml — added postComment, storageAccount, and linkUrl params so the snapshot jobs target $(TOOLS_STORAGE_ACCOUNT) and link the correct public URL. Both snapshot pipelines add the BabylonJS-CI-Infrastructure variable group.
  • Playground paths are uncached, so no CDN purge step is needed for snapshots.

Verification

tsc --noEmit ✓ · eslint ✓ · all three build modes (root / /pr/123/ / /v/1.4.0/) emit a stable assets/boot.js with the correct baked base ✓ · coordinator regex validated against a 10-case URL matrix ✓ · all pipeline YAML parses ✓.

Flags / follow-ups

  • Front Door rules are an infra change outside this repo — apply config/frontdoor-playground-spa.md so deep-link refreshes under /pr/<N>/ and /v/<ver>/ fall back to /index.html.
  • Fork PRs: the upload step is continueOnError, so fork PRs no-op unless "Make secrets available to builds of forks" is enabled — that exposes the deploy token to fork-authored code, a real security tradeoff. Documented inline in the job.
  • PR cleanup on close needs a deployment-server delete endpoint (or a TTL sweep) — follow-up.

Make the playground app-shell deploy-base aware so it can be served
from any sub-path, and add pipeline paths to deploy an immutable
playground snapshot per PR and per published version. Nightly on
master continues to serve at the root (default base URL).

- vite: parametrize `base` via PLAYGROUND_BASE
- add playground/src/base.ts (BASE, withBase, stripBase,
  rebaseAssetReferences) and make runtime/SPA paths base-aware
- runner rebases root-absolute asset paths before running user code
- azure-pipelines.yml: PR PlaygroundSnapshot job (builds PR engine,
  deploys, comments URL)
- azure-pipelines-npm-publish.yml: versioned snapshot after publish
- upload-static-site.yml: optional postComment param

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@bjsplat

bjsplat commented Jul 8, 2026

Copy link
Copy Markdown

Lite Playground - Static Site

Open deployed site

Build 20260708.13 - merge @ 1c372f7

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds deploy-base awareness to the Lite Playground so it can be served immutably under per-PR and per-release sub-paths, and wires up CI to build+deploy those snapshots while keeping the existing nightly-at-root behavior intact.

Changes:

  • Make the Playground app-shell and SPA routes base-aware via Vite base + shared helpers (BASE, withBase(), stripBase()), updating engine/runner/snippet/open-in-playground URLs accordingly.
  • Rebase root-absolute same-origin asset references in runner-bound code so examples like "/brdf-lut.png" work under /pr/... and /v/... deploys without per-example edits.
  • Add Azure Pipelines jobs/templates to deploy per-PR playground snapshots and per-version playground snapshots (publish pipeline), with optional PR commenting in the upload template.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
playground/vite.config.ts Adds configurable Vite base via PLAYGROUND_BASE for sub-path deploys.
playground/src/base.ts Introduces shared deploy-base helpers and asset-path rebasing utility.
playground/src/versions.ts Makes the self-hosted nightly engine URL base-relative.
playground/src/snippets.ts Makes snippet path generation/parsing deploy-base aware.
playground/src/runner.ts Loads runner iframe under base and rebases root-absolute asset paths before execution.
playground/src/main.ts Uses BASE for history resets so SPA navigation works under sub-paths.
playground/src/embed.ts Makes “open in playground” links base-aware.
playground/src/editor.ts Fetches self-hosted engine .d.ts under the deploy base.
playground/src/download.ts Centralizes asset extension list via ASSET_EXT (but needs base-aware fetching fix per comment).
playground/public/runner.html Uses a relative default engine path so it resolves under the deploy base.
config/templates/upload-static-site.yml Adds postComment param to optionally skip PR commenting for non-PR pipelines.
azure-pipelines.yml Adds a per-PR Playground snapshot build+deploy job.
azure-pipelines-npm-publish.yml Adds a post-publish, per-version Playground snapshot build+deploy block (dryRun-gated).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread playground/src/download.ts Outdated
@bjsplat

bjsplat commented Jul 8, 2026

Copy link
Copy Markdown

Lab - Static Site

Open deployed site

Build 20260708.13 - merge @ 1c372f7

RaananW and others added 2 commits July 8, 2026 17:14
collectAssets fetched root-absolute asset paths against the domain
root, so under a sub-path snapshot (/pr/<N>/, /v/<ver>/) same-origin
assets 404'd and were silently dropped from the zip with their
references left unrewritten. Fetch via withBase(path) so downloads
work at root and under snapshot deploys alike (no-op at root).

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@bjsplat

bjsplat commented Jul 8, 2026

Copy link
Copy Markdown

Lite Playground - Static Site

Open deployed site

Build 20260708.15 - merge @ f0876b4

@bjsplat

bjsplat commented Jul 8, 2026

Copy link
Copy Markdown

Bundle Size Changes

Decreases

Package Current Master Change
Scene 42 — Physics Clone Pre-Step
scene42
51 KB 52 KB -1 KB
Scene 47 — Physics Heightfield
scene47
92 KB 93 KB -1 KB
Scene 218 — Vertex Animation Texture (VAT)
scene218
92 KB 93 KB -1 KB

Sizes rounded to nearest KB. Run pnpm build:bundle-scenes locally to verify.

@bjsplat

bjsplat commented Jul 8, 2026

Copy link
Copy Markdown

Lab - Static Site

Open deployed site

Build 20260708.15 - merge @ f0876b4

@ryantrem ryantrem left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm understanding these changes correctly, it makes it so you have the option to include a version in the url, and then the Playground app/shell will (or can) use the same @babylonjs/lite version that is being used by the pg code. In this case, the versions are aligned, but it is still two separate JS "realms" (e.g there are two classes named FooBar coming two different modules, and their APIs are the same, but they are distinct classes and instanceof would not work, for example). Am I reading it correctly? If so, it seems like it still doesn't solve the Inspector problem described in the PR description. I think the only way that is solved is if the app/shell and the pg code are using the same "instance" of the @babylonjs/lite module (or set of modules) with true single identity.

@RaananW

RaananW commented Jul 9, 2026

Copy link
Copy Markdown
Member Author

This PR includes a static deployment of the playground in a fixed directory on our server, based on versions. vX.Y.Z will only work if it was deployed for this specific version. The fixed babylon lite version is shipped with the playground. The fixed inspector version will also be included in the deployment. there should never be any collision, as inspector and lite versions are fixed. The select box will have to be modified and/or we will need to manually deply older versions of the framework for the select box of the version to fully work, but this is a non-issue. We can do that manually in the future or just say that no older versions are available.

@ryantrem

ryantrem commented Jul 9, 2026

Copy link
Copy Markdown
Member

But as is, selecting an older version could make things blow up, because it would be pulling a different version with a potentially different API, right?

@RaananW

RaananW commented Jul 10, 2026

Copy link
Copy Markdown
Member Author

But as is, selecting an older version could make things blow up, because it would be pulling a different version with a potentially different API, right?

Yes. this is a follow up to this PR. after this PR we will also need to define new rules in the CDN, and deploy manually older versions of the playground, if we want to support older versions in the new playground style.

@RaananW

RaananW commented Jul 11, 2026

Copy link
Copy Markdown
Member Author

I am moving this to draft, as azure front door doesn't support the URL rewrite needed for this PR to work. I am working on a fix and will open the PR for reviews again afterwards.

@RaananW RaananW marked this pull request as draft July 11, 2026 11:24
RaananW and others added 2 commits July 11, 2026 14:52
Every deploy (root nightly, per-PR, per-version) now ships a single
stable, unhashed assets/boot.js coordinator. It derives the snapshot
base from the URL and either boots this build's app (base matches the
baked BASE_URL) or hands off to the correct snapshot's boot.js.

This makes clean path URLs work under a single-origin SPA fallback:
a deep link like /pr/387/snippet/... can be rewritten by Front Door to
the root /index.html (the only static rewrite target AFD supports), and
the root coordinator then loads /pr/387/assets/boot.js, which matches
and boots the PR build. No hashes in the URL, no per-deploy rebuild.

- add playground/src/entry.ts (coordinator); index.html loads it
- vite: emit the entry as stable assets/boot.js, keep chunks hashed

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Repoint the PR and versioned playground deploys to the tools storage
account (liteplayground.babylonjs.com) under clean /pr/<N>/ and /v/<ver>/
paths, so the stable assets/boot.js coordinator can hand off between
snapshots on a single origin. Front Door can't do per-base SPA fallback,
so a single rewrite to /index.html + the coordinator handles deep links.

- upload-static-site.yml: add storageAccount + linkUrl params (masked auth
  untouched); PR comment now links the explicit public URL.
- azure-pipelines.yml: PR snapshot -> TOOLS_STORAGE_ACCOUNT, base /pr/<N>/,
  upload litePlayground/pr/<N>, comment liteplayground.babylonjs.com/pr/<N>/;
  lab caller passes its existing SERVE_DOMAIN link. Add CI-Infrastructure group.
- azure-pipelines-npm-publish.yml: version snapshot -> TOOLS_STORAGE_ACCOUNT,
  base /v/<ver>/, upload litePlayground/v/<ver>. Add CI-Infrastructure group.
- Add config/frontdoor-playground-spa.md AFD SPA-fallback rule reference.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants