Release code that closely integrates with Scratch under the AGPL#1518
Release code that closely integrates with Scratch under the AGPL#1518zetter-rpf wants to merge 15 commits into
Conversation
7f83cd5 to
7292731
Compare
a195e71 to
9f2f812
Compare
There was a problem hiding this comment.
Pull request overview
This PR restructures the Scratch integration by extracting the Scratch-facing bundle/assets into a new apps/scratch-frame workspace (built with Vite) and updating the main editor UI to embed and communicate with that frame via a dedicated REACT_APP_SCRATCH_FRAME_URL.
Changes:
- Introduces a new Yarn workspace
apps/scratch-framewith Vite/Vitest and moves Scratch integration code into it. - Updates the host app to load Scratch from
REACT_APP_SCRATCH_FRAME_URLand removes the webpack “scratch” build/config. - Updates Docker/CI/deploy workflows to build/start/test both the host app and the new scratch-frame app; updates licensing metadata (AGPL for scratch-frame).
Reviewed changes
Copilot reviewed 37 out of 41 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
yarn.lock |
Adds dependencies for Vite/Vitest and the new scratch-frame workspace. |
webpack.config.js |
Removes the scratch-specific webpack config and scratch-gui asset serving from the main dev server. |
src/utils/scratchIframe.js |
Switches allowed Scratch postMessage origin to REACT_APP_SCRATCH_FRAME_URL. |
src/utils/scratchIframe.test.js |
Updates tests to use REACT_APP_SCRATCH_FRAME_URL for origin calculation. |
src/hooks/useScratchSaveState.test.js |
Updates Scratch save-state tests for the new scratch-frame origin env var. |
src/components/ScratchEditor/WrappedScratchGui.jsx |
Removes the host-app wrapper for scratch-gui (now lives in scratch-frame). |
src/components/ProjectBar/ScratchProjectBar.test.js |
Updates message origin assumptions to scratch-frame. |
src/components/Editor/Project/ScratchContainer.test.js |
Updates Scratch container tests for scratch-frame origin env var. |
src/components/Editor/Project/ScratchContainer.jsx |
Loads the Scratch iframe from REACT_APP_SCRATCH_FRAME_URL. |
package.json |
Adds workspaces and “all” scripts intended to build/start both apps; expands lint/stylelint globs; adds scratch-frame test script. |
LICENSE.txt |
Adds project-level license preface and sets an explicit copyright line. |
Dockerfile |
Exposes scratch-frame port and switches container start command to start:all. |
docker-compose.yml |
Runs start:all and publishes scratch-frame port. |
cypress/e2e/spec-scratch.cy.js |
Uses REACT_APP_SCRATCH_FRAME_URL for simulated Scratch postMessage origins. |
cypress.config.mjs |
Exposes REACT_APP_SCRATCH_FRAME_URL to Cypress env. |
COPYRIGHT |
Declares apps/scratch-frame as AGPL-3.0 licensed in addition to existing Apache-2.0 notices. |
apps/scratch-frame/vite.config.js |
New Vite config: builds scratch.html + copies scratch-gui static/chunks into build output; dev server on 3014. |
apps/scratch-frame/src/WrappedScratchGui.jsx |
New wrapper around window.GUI scratch-gui module + integration HOC. |
apps/scratch-frame/src/utils/scratchProjectSave.test.js |
New Vitest-based tests for scratch project save behavior. |
apps/scratch-frame/src/utils/scratchProjectSave.js |
New scratch project save helper that calls scratch-gui’s scratchFetch. |
apps/scratch-frame/src/utils/iframeUtils.js |
Adds allowed-origin gate for incoming postMessage events to the frame. |
apps/scratch-frame/src/utils/events.js |
Adds parent-origin resolution and event posting helpers for cross-frame messaging. |
apps/scratch-frame/src/utils/dedupeScratchWarnings.js |
Updates prod/dev detection to Vite’s import.meta.env semantics. |
apps/scratch-frame/src/stylesheets/Scratch.scss |
Adds scratch-frame-specific styling overrides and extension hiding. |
apps/scratch-frame/src/ScratchIntegrationHOC.test.jsx |
Migrates integration HOC tests from Jest style to Vitest + module mocking. |
apps/scratch-frame/src/ScratchIntegrationHOC.jsx |
Updates integration HOC to use window.GUI and scratch-frame-local utilities. |
apps/scratch-frame/src/ScratchEditor.test.jsx |
Adds/updates ScratchEditor tests under Vitest. |
apps/scratch-frame/src/ScratchEditor.jsx |
ScratchEditor implementation adjusted for scratch-frame-local save/events and basePath. |
apps/scratch-frame/src/scratch.test.js |
Updates scratch bootstrap/handshake retry tests for Vite + Vitest. |
apps/scratch-frame/src/scratch.jsx |
scratch-frame entrypoint updated for Vite-style imports and prod detection. |
apps/scratch-frame/src/bootstrap.jsx |
New module loader that exposes React/Redux globals and loads scratch-gui UMD bundle. |
apps/scratch-frame/scratch.html |
Converts scratch.html to Vite module bootstrap and CSP placeholder replacements. |
apps/scratch-frame/README.md |
Adds a minimal scratch-frame README. |
apps/scratch-frame/package.json |
Defines scratch-frame workspace package, scripts, and deps. |
apps/scratch-frame/LICENSE |
Adds AGPL-3.0 license text for scratch-frame. |
app.json |
Removes Heroku app manifest. |
.github/workflows/deploy.yml |
Uses build:all and wires scratch-frame env var for deploy builds. |
.github/workflows/ci-cd.yml |
Starts both dev servers for Cypress and adds scratch-frame unit test step. |
.eslintrc.json |
Adds Vitest globals override for scratch-frame test files. |
.env.example |
Adds REACT_APP_SCRATCH_FRAME_URL default for local dev. |
.devcontainer/devcontainer.json |
Removes Heroku-related VS Code extensions from the devcontainer setup. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
I've chosen to follow the default vite monorepo structure with sub-directories for each app. I've not modified the files to make the diff easier to see. I'll add additional commits to fix the imports and set up Vite for the new app.
I thought this was a good place to introduce Vite as we need a way to build this app and there's a small amount of code to migrate. I've made the projects use yarn workspaces for now as I think this is a simpler first step, but we could move away from this later.
Vite expects this to signal that it's an inline import
This does two things: It migrates env vars from `process.env`` to `import.meta.env`. I've added a REACT_APP prefix so the apps can share a single .env file for now. It also introduces a new env var REACT_APP_SCRATCH_FRAME_URL which is split off from ASSETS_URL. I've done this so that it's easier to run the scratch-frame app from a separate port locally. In production it will be set to the same URL as ASSETS_URL.
We can't use erb-style interpolation any more. Create our own transformer to replace the strings
We were loading Scratch like this previously in Webpack, the difference is that webpack 'externals' config is a bit more powerful and can be used to keep the imports. I couldn't get Vite configured in the same way so instead use the window.GUI object directly. I thought I might be able to remove scratch-gui script tag in the bootstrap file and use the import script, but one problem I ran into was that some scratch assets are imported relative to the Scratch js file. Having the file in a vendor directory made this easier to manage (otherwise assets will need to be copied to src).
Scratch expects some assets to be in `scratch-gui/` and some to be in `vendor/`. I had previously thought that vendor was hardcoded in Scratch, but it's actually based on the location of the scratch-gui file that we set in our build. By putting the file in `scratch-gui/` instead of `vendor/`, we can server more of scratch's assets from the same location, which is simpler and will reduce the build time.
We now deploy to cloudflare so don't need this.
For now, I've taken the easier route of making stylelint and eslint work across app apps. In the future we could create different configs and/or linters for these apps.
Make sure we're building and testing the apps in CI and can run the app with docker. We could create separate docker containers for each app, but for now while the apps share the root package.json, I think it's fine to run them all in one container. I've chosen to build both apps in the same directory to mirror the way the apps were built and deployed before. I've checked that there's no overlap between files. If we wanted to make this safer we could build to separate directories and combine in the sync. It's harder to change the location for some of the scratch assets. Host: true is required for the app to be runnable within docker
5a2d86b to
4161faf
Compare
Rather than configure jest with vite, use vitest. This work was mostly done by Codex.
Since Scratch editor is licenced under AGPL and scratch-frame is tightly integrated with the scratch editor component we think it needs be licenced under the AGPL too. Some of the setup code might be on the AGPL code in the scratch editor repository which is another reason to licence it this way. Now it's clearer that the Scratch Frame is a standalone app, doesn't share code editor ui, and has a message-based interface with with it's consumer.
Because we have a LICENSE and a COPYRIGHT file, it may be easy just to look at the license and assume it applies everywhere.
4161faf to
a955413
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit a955413. Configure here.
mwtrew
left a comment
There was a problem hiding this comment.
Looks good - nice to see the initial moves with Vite and workspaces too.

https://github.com/RaspberryPiFoundation/digital-editor-issues/issues/1533
Changes:
See commits for more
Still todo