Running Node.js in the Browser ![rw-book-cover](https://adamadam.blog/wp-content/uploads/2025/10/[email protected]) ## Metadata - Author: [[Adam's Perspective]] - Full Title: Running Node.js in the Browser - Category: #articles - Document Note: --- tags: [WordPress, Node.js, Gutenberg] author: [MISSING] source: Adam's Perspective reference: [https://adamadam.blog/2025/10/10/running-node-js-in-the-browser/] date created: 2025-10-11 00:00 --- # 🏷️ Title: Running Node.js in the browser ## 🧭 Table of Contents - [📝 Summary](#-summary) - [📖 Main Content](#-main-content) - [🗒️ Notes](#️-notes) - [📚 References](#-references) - [🗣️ Paraphrase](#️-paraphrase) - [📰 Newsletter](#-newsletter) - [✅ Action Items](#-action-items) - [🧪 Hypotheses](#-hypotheses) - [📊 Methodology](#-methodology) - [❓ Questions](#-questions) - [🔮 Future Research](#-future-research) - [💡 Implications](#-implications) - [🧠 Learning Styles Assessment](#-learning-styles-assessment) - [📊 Accessibility Assessment](#-accessibility-assessment) - [🌍 DEIB Assessment](#-deib-assessment) - [✅ Logical Validity](#-logical-validity) - [🛡️ DARVO Analysis](#-darvo-analysis) - [🎯 Conclusion](#-conclusion) ### 🔗 References - Include links cited in or relevant to the article. ## 📝 Summary - What happened: A working prototype runs Node.js tooling (npm, webpack) in the browser by loading Node’s JS standard library and polyfilling internal bindings, aiming to enable building Gutenberg blocks fully in-browser. - Why it matters: Unlocks @wordpress/scripts in the browser to compile JSX-based blocks without local Node installs, accelerating WordPress Playground use cases. - Key stakeholders: WordPress block developers, WordPress Playground maintainers, education and training programs, hosting-constrained users. - Risks and tradeoffs: Missing features (child_process, workers, shared FS), performance/compatibility nuances; not compiling Node to WASM to avoid size/complexity penalties. - Bottom line: “Promising, but there’s still a long way to go”—useful proof-of-concept, paused while Playground priorities (Xdebug, phpMyAdmin) ship. ## 📖 Main Content - Core idea: “Node.js programs are just JavaScript… We can take advantage of that!” The author loads Node’s JS stdlib in the browser and polyfills “internalBinding” surfaces to satisfy modules like fs, enabling npm/webpack. - Context/terms: - Gutenberg blocks: typically built with JSX and compiled via @wordpress/scripts (webpack, Babel) into JS/CSS/PHP assets. - Alternative avoided: compiling V8/libuv/Node to WASM—too heavy, slower, complex. - Uncertainties: - Completeness of polyfills for nuanced Node stdlib behaviors used by ecosystem tools. - Multi-worker, process, and shared FS constraints for real-world builds. ### 🗒️ Notes - “It can already run npm, webpack, and more.” - Why Node for blocks: WordPress docs encourage JSX + @wordpress/scripts, which “use webpack, babel… to replace import { Paragraph } from '@wordpress/blocks' with window.wp.blocks.Paragraph.” - Not WASM: Native Node is ~80MB; static WASM likely larger and slower (“JS VM inside a JS VM”). - Approach: Load Node’s JS stdlib; polyfill internalBinding surfaces (e.g., fs → internalBinding('fs').rmdir()) and globals; then run common packages. - Tried and moved past: browserify-like stdlib reimplementations lacked nuanced behaviors needed by npm and friends. - Gaps to production: - child_process (spawning) - workers/worker_threads - Filesystem shared across workers - Shared FS with WordPress Playground - Priority shift: Paused to finalize Xdebug, phpMyAdmin, and other Playground work. ## 📚 References - Node.js standard library design (internalBinding): https://nodejs.org/api/ - child_process docs: https://nodejs.org/api/child_process.html - worker_threads docs: https://nodejs.org/api/worker_threads.html - @wordpress/scripts: https://developer.wordpress.org/block-editor/reference-guides/packages/packages-scripts/ - Webpack: https://webpack.js.org/ - Babel: https://babeljs.io/ - npm: https://www.npmjs.com/ - WordPress Playground: https://developer.wordpress.org/playground/ - Prototype repo (mentioned): https://github.com/adamziel/node-js-in-the-browser - V8: https://v8.dev/ - libuv: https://libuv.org/ ## 🗣️ Paraphrase - Paragraph A: The missing piece to build Gutenberg blocks in-browser was Node.js; a prototype now runs npm and webpack, pointing toward @wordpress/scripts support. - Paragraph B: Rather than compile Node to WASM, the approach loads Node’s JS stdlib and polyfills its internal C binding surfaces so browser JS can run Node-oriented tooling. ## 📰 Newsletter - This week in WordPress dev: A prototype runs Node tooling directly in the browser, aiming to make @wordpress/scripts work inside WordPress Playground. That could mean zero-install block development: write JSX, build, and test—all in a tab. It’s early: multi-process, workers, and shared FS support are still missing. Meanwhile, Playground priorities like Xdebug and phpMyAdmin are moving forward. Explore @wordpress/scripts and Webpack to prep for a browser-first dev future, and keep an eye on Playground’s evolving capabilities. ## ✅ Action Items #### DevRel - Developer advocacy: Demo in-browser npm/webpack builds; gather feedback via office hours; track success by prototype runs and block build completions. - Education: Create a “Build a block in your browser” workshop; step-by-step labs for JSX→@wordpress/scripts→block assets. - Developer experience: Minimal examples/templates for Playground builds; document constraints (no child_process, limited workers). - Developer marketing: Launch a “No-install blocks” content series; measure signups and Playground sessions. - Community management: Run surveys on browser-only dev needs; maintain a known-issues board. - Internal/external/cross-project: Align with Playground roadmap; set SLAs for demo reliability; feedback loops with @wordpress/scripts maintainers. #### OSPO - Policy & Governance: Clarify contribution guidelines for polyfills touching Node semantics. - License Compliance: Review stdlib code usage and license compatibilities. - Security Management: Threat model polyfills; define vuln intake for browser-exec context. - Software Inventory: Track versions of stdlib/polyfills; SBOM for browser build toolchain. - Developer Support: Provide guardrails for running third-party packages in-browser. - Community Engagement: Coordinate with Node/Webpack communities on compat gaps. - Strategic Alignment: Report KPIs on compatibility coverage and performance. #### Community - Maintainers: Host roadmap clinics on enabling @wordpress/scripts in-browser. - Contributors: “First issue” polyfill tasks and test matrices. - Sponsors: Fund performance profiling and worker/FS features; publish outcomes. - Ecosystem: Cross-project incident drills for build regressions. #### WordPress - Core: Monitor implications of browser-based builds on block scaffolding. - Core Performance: Benchmark build times and memory; publish dashboards. - Core AI: N/A directly; ensure tooling doesn’t hinder AI-assisted dev flows. - Core Program Team: Sync milestones with Playground deliverables. - Mobile: Explore remote-build previews in mobile dev workflows. - Playground: Add labs, reproducible bug repros, educational modules; design shared FS. - Community: Provide meetup kits for “blocks in the browser” sessions. - Training: Author lesson plans for zero-install dev. - Marketing: Narrative around accessibility of block dev for newcomers. - Support: KB entries for common browser-build issues. - Design: UX for terminal/file explorer; error surfacing. - Documentation: Examples-first docs; compatibility notes and workarounds. - Photos/TV: N/A - Polyglots: Translate tutorials. - Accessibility: Ensure terminal/file explorer meet WCAG; keyboard-first ops. - Meta: Reliable .org APIs for templates/examples. - CLI: Explore parity guides between WP-CLI scaffolds and browser flow. - Hosting: Guidance on moving from browser builds to hosted pipelines. - Tide: Consider scoring guidance for browser-built artifacts. - Openverse: N/A - Themes: Add theme-block examples built in-browser. - Plugins: Provenance checks for browser-built assets. #### The WPCC - Programs: Microgrants for polyfill and worker/FS work. - Projects: Docs sprints on browser-based workflows. - Funding experiments: Milestone payouts for feature parity. ### FAIR - Technical independen - Summary: Discover how the new PHP Playground beta is paving the way for building Gutenberg blocks using Node.js in the browser. - URL: https://adamadam.blog/2025/10/10/running-node-js-in-the-browser/ When I’ve shared [the new PHP Playground beta](https://playground.wordpress.net/beta-php-playground.html) (with a terminal and a file explorer), [Jon Surrell](https://profiles.wordpress.org/jonsurrell/) asked me what was still missing before we can create Gutenberg blocks. The answer was Node.js. On Thursday, it seemed nearly impossible. On Wednesday, I had a working prototype. It can already run npm, webpack, and more. With more work, it could support `@wordpress/scripts` and unlock building WordPress blocks in the browser! ##### The prototype You’ll find the source code with setup instructions in the [adamziel/node-js-in-the-browser](https://github.com/adamziel/node-js-in-the-browser) GitHub repo. Sadly, I don’t have a demo link to share but hey, here’s a screenshot: ![Screenshot of a terminal interface displaying Node.js commands for installing and running a demo project called 'demo-cowsay'.](https://adamadam.blog/wp-content/uploads/2025/10/[email protected])Screenshot of a terminal interface displaying Node.js commands for installing and running a demo project called 'demo-cowsay'. You can build a simple `tsx` file with WebPack using these commands: | | | | --- | --- | | 1234 | `npm install --verbose``node ./node_modules/.bin/webpack build``ls dist``cat dist/bundle.js` | ##### Why is Node.js needed to build WordPress blocks? Because the WordPress documentation trains developers to write JSX code use the [@wordpress/scripts](https://www.npmjs.com/package/@wordpress/scripts) npm package to transform that JSX to plain `.js` code, a bunch of `.css` files, and a `.php` manifest. Under the hood, WordPress scripts use `webpack`, `babel`, and a bunch of custom transforms to replace `import { Paragraph } from "@wordpress/blocks"` with `window.wp.blocks.Paragraph`. ##### I’m not compiling Node.js to WASM! That would be a **huge** project. You’d need to build the entire v8 JavaScript engine, all its dependencies, their dependencies, etc. Then `libuv`. Then you’d need to make it work with browser’s asynchronous filesystem. Then, …. You get the idea. It’s a lot and I don’t think that’s worth it. Besides, native Node.js installation is ~80MB on my mac, which a static WASM build would likely double or more. And there would be a speed penalty for running JS VM inside a JS VM. ##### Instead, I’m eval()-ing Node.js JavaScript in the browser Node.js programs are just JavaScript. Every browser already ships a good JavaScript runtime. We can take advantage of that! What separates JavaScript written for Node.js from JavaScript written for the browser? The standard library. We can call `require("fs").readFileSync()` in Node.js, but not in the browser. I used to think that `fs` and other standard modules are written in C, but I’ve just learned they’re [written in JavaScript!](https://github.com/nodejs/node/blob/main/lib/fs.js) There’s a catch, though. The JavaScript standard library uses a layer of lower level C bindings to interact with your hardware. For example, `import { rmSync } from "node:fs"` delegates some work to `internalBinding('fs').rmdir();`. Luckily, those internal C bindings have a much smaller surface than the JS stdlib. You can polyfill them, initialize all the expected global variables, load the Node.js stdlib in the browser, and now you’re able to run `webpack` and other npm packages. And that’s exactly how the [node-js-in-the-browser](https://github.com/adamziel/node-js-in-the-browser) demo works. Initially I’ve tried [browserify](https://github.com/browserify/browserify/) and a few other projects reimplementing Node standard library for web browsers. They’re tempting because they seem mature and they ship much less code. Unfortunately, `npm` and other packages rely on highly nuanced behaviors of the Node.js standard library that those polyfills lacked. ##### It’s promising, but there’s still a long way to go! The proof of concept is lean and does just enough to run npm, webpack, and some other popular packages. At least a few features required for running `@wordpress/scripts` are missing: * Spawning processes (for `child_process`). * Multiple worker support (`workers`, `worker_threads` modules). * A filesystem shared across workers (also relevant for WordPress Playground). * Shared filesystem with WordPress Playground. So while these early results are encouraging and I hope to continue that work in the future, it needs more effort before it’s a drop-in replacement. I’m setting this work aside for now to help finalize XDebug, PHPMyAdmin support, and a few other [WordPress Playground](http://w.org/playground)–related projects., Running Node.js in the Browser, Adam's Perspective, 01k7735cy0dbdyw0zyhv1skyvd.