Running Node.js in the Browser

## 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'.
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.