chore: migrate to esbuild tooling and update Pyodide to 314.0.7 - #38
Open
bajrangCoder wants to merge 16 commits into
Open
bajrangCoder wants to merge 16 commits into
bajrangCoder wants to merge 16 commits into
Conversation
Align the build with the official Acode plugin template and fix Python failing to load on some devices. Tooling: - Replace webpack/babel/postcss/sass with esbuild (dev server on :3000) - Restore pack-zip.js at the repo root (webpack config imported a moved file) - Copy the Pyodide runtime from npm into dist/lib on every build; dist/lib had been dropped from git, so clean builds shipped without Python - Add tsconfig for acode-plugin-types, Biome dev dependency and check script - Replace JSX with tag() calls and SCSS with plain CSS Pyodide: - Update to 314.0.7 (Python 3.14); run the worker as a module worker - Bundle the Pyodide loader into worker.js so .mjs MIME types do not matter - Fall back to ArrayBuffer wasm compilation when .wasm is not served as application/wasm, which otherwise hung on "loading..." - Load packages on demand from the matching jsDelivr CDN (numpy, micropip...) - Route stderr correctly and show clear load errors with retry on next run Also bump to 1.2.0, add contributor, fix plugin.json main path. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
- pack-zip: resolve the root with fileURLToPath (import.meta.dirname needs Node 20.11+), run in-process and write via temp file + rename - esbuild: await packing in onEnd so failures exit non-zero and rebuilds never pack concurrently; start from a clean dist so stale files are not shipped - main: construct the worker inside try so an unsupported module worker shows an error and allows retry instead of leaving init stuck - worker: only dispatch own action handlers (CodeQL dynamic method call) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This comment was marked as outdated.
This comment was marked as outdated.
Object.hasOwn needs Chrome 93+ but the build targets Chrome 90 and esbuild does not polyfill it. On older WebViews the worker threw on the first init message and the page stayed on "loading..." with no error. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This comment was marked as outdated.
This comment was marked as outdated.
CodeQL still flagged `actions[action](...)` as an unvalidated dynamic method call even with the hasOwnProperty guard. Looking handlers up in a Map means a message's action name can only reach the defined handlers, never inherited Object methods, and avoids Object.hasOwn (Chrome 93+). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Follow CodeQL's recommended pattern for js/unvalidated-dynamic-method-call: check the name with Map.prototype.has and verify the handler is a function before calling it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Long output lines scroll horizontally per line (unchanged default). A new header button wraps them instead; the choice is saved in localStorage. Also keep the >> marker from shrinking or breaking when lines wrap. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds Acode's header loader to the console page so it is clear whether a program is still running or has finished. It hides while the program is waiting for input(). Also drops the tooltip and active state from the wrap toggle. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The icon-sized spinner was too heavy for the console header. Use a 2px indeterminate progress line along the bottom edge of the header in the theme's active color instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Move Pyodide setup into src/runtime.js, shared by the worker and the new SDL runtime; Python helpers live in src/python and are installed into site-packages - matplotlib: custom Agg backend (MPLBACKEND) posts figures as PNG to the console on plt.show(); unshown figures are shown when a run ends - Pillow: Image.show() displays in the console - Experimental SDL (pygame): programs with an async game loop run in a main-thread Pyodide drawing to a <canvas id="canvas"> in the console. SDL setup is checked with pygame.display.init() and any failure falls back to the worker. Keyboard input is limited to the canvas, Acode's document title is restored, and re-running or closing the console cancels the game - Worker runs pygame headless (SDL_VIDEODRIVER=dummy): without a canvas Emscripten's SDL video crashed Pyodide fatally - Handle Pyodide fatal errors: report them and restart Python on the next run instead of leaving the console stuck - Hide "already loaded" package messages on every run Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pygame: - Ordinary blocking game loops now use SDL mode: with JSPI, the calls a game loop makes (display.flip/update, Clock.tick, time.wait/delay, event.wait) pause via run_sync so the browser can draw and Acode stays responsive (python/acode_pygame.py) - Check JSPI inside a task before running a blocking loop; without it, fall back with an explanation instead of freezing Acode - Stop blocking loops through a flag checked at those pauses, since they never reach an await; stopped runs no longer print into the next console - Explain the worker's "dummy not available" error Images: - Default matplotlib figure size to the console width (via the matplotlibrc read on first import), so text stays readable on phones - Render at the device pixel ratio and display at true size, so plots are sharp on HiDPI screens Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On a device, SDL failed with "Failed to connect to localhost/127.0.0.1:443": on Acode's main page window.fetch can be replaced (e.g. by another plugin using native HTTP to avoid CORS), and native HTTP cannot reach the plugin's files at https://localhost, which only exist inside the WebView. The worker has its own fetch, so it was unaffected. Requests for the plugin's files and Pyodide packages now go through the browser's fetch taken from a hidden same-origin iframe; all other requests still use the page's fetch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rewrite the README around current features (packages, micropip, plots, experimental pygame, console features), limitations and development notes, replacing outdated sections. Group the 1.2.0 changelog into new, improved, fixed and development changes, and add the missing 1.1.4 entry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Member
Author
ar9352975-droid
approved these changes
Oct 2, 2026
- Ask before running a pygame program on Acode's main page, where it can reach the app (Python there is not isolated like the worker); declining runs it in the worker without a display, with an option to not ask again - Do not start a game that was stopped while the SDL runtime or its packages were still loading, including while sdl.js itself loads - Detect real await expressions with ast instead of matching the word, and stop blocking loops that cannot pause (no JSPI) after a few frames with a clear error instead of freezing Acode - dispose() on unmount restores window.fetch (or makes the wrapper a pass-through if another plugin wrapped it since) and removes the iframe Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This comment was marked as outdated.
This comment was marked as outdated.
dispose() removed the fetch route but kept the cached SDL runtime, and the route was only installed on first load, so a re-initialised plugin could reuse the runtime and download packages through a replaced fetch. - install the route at the start of every run (no-op while active) - dispose() drops the cached runtime so it is freed, not reused - main.js clears its cached sdl.js promise and removes the script tag on destroy, so a later init loads a fresh module Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This comment was marked as outdated.
This comment was marked as outdated.
Removing a <script> tag does not cancel a load in flight, so after an unmount and remount a stale sdl.js could finish last, overwrite the shared window.acodePythonSdl, and closing the console would then stop the wrong SDL instance. - each load is tagged with a unique data-load-id; sdl.js registers its API under that id (via document.currentScript) instead of one global - main.js keeps the API from its own current load for stop/dispose and ignores loads that finish after a newer one started or after destroy - destroy bumps the run id so runs waiting for sdl.js never start Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This comment was marked as outdated.
This comment was marked as outdated.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Brings the plugin in line with the official Acode plugin template and fixes Python failing to load on some devices. The console UI and behavior are unchanged apart from the fixes below.
Tooling
npm run devserves on:3000,npm run buildwritesplugin.zip)webpack.config.jsimported./pack-zip.js, which had been moved into.vscode/.pack-zip.jsis back at the root (ESM port of the template's)@ngrok/ngrokwas never a dependency)dist/lib(Pyodide) had been dropped from git and the!dist/lib/ignore rule could not re-include it, so clean builds shipped without Python. Pyodide is now an npm dev dependency and its runtime is copied intodist/libon every buildtag()calls and SCSS with plain CSS (nesting lowered by esbuild, icon font inlined), so no compile plugins are neededtsconfig.jsonforacode-plugin-types, Biome as a dev dependency withnpm run checkplugin.json:mainnow points tomain.js(where the zip puts it),readme/changelogsset, contributor addedPyodide 0.28.1 → 314.0.7 (Python 3.14.2)
{ type: "module" }worker.js, so loading no longer depends on how the host serves.mjsfiles.wasmis not served asapplication/wasm, Pyodide only logs a warning and hangs on "loading..." forever. The worker now falls back toArrayBuffercompilation and reports any remaining failurepackageBaseUrlpoints to the matching jsDelivr build, soimport numpy,pandas,micropip, etc. download on demand (previously only the stdlib worked)Fixes for reported device errors
NetworkError: Failed to execute 'importScripts' ... //lib/pyodide.js failed to load:lib/was missing from builds, and the URL had a double slash. Both fixedCannot read properties of undefined (reading 'loadPackagesFromImports'): a failed init was still marked as ready and code was sent to the worker anyway. Init failures now show a clear message naming the missing file, code is not run, and the next run retries