Background
MediaWiki has existed as a classic LAMP-stack, PHP-based application for roughly 20 years at this point. One long-standing goal in the development of MW has been to ensure that the core software can run on a shared-hosting environment, where the site administrator may not have the ability to install additional packages. Practically speaking, this means that we tend to do as much as possible in PHP.
Limitations of our current approach
Ensuring that MediaWiki remains viable on shared hosting platforms is an important goal, but our decision to rely exclusively on PHP for core functionality also imposes some consequences that we must work around, most notably in the areas of front-end development. Here are some examples:
- WMF maintains its own PHP port of the LESS CSS pre-processor which is now several major versions behind the upstream project (T288498)
- We also maintain PHP-based tools for JS minification / validation which did not support ES6 for several years
- Front-end developers cannot use any build tools in MW features unless they build them in an external repository and commit the resulting assets to source. This also prevents use of Typescript, CSS processors aside from LESS, and certain performance optimizations (bundling & tree-shaking code, JS transpilation, pre-compilation of Vue files, etc). See: T279108.
- Without some kind of JS runtime, performing server-side rendering of Vue components is not going to be possible; this means that developers will need to continue writing two versions of most front-end features (one in PHP and one in JS). See: T321356.
External services
Historically, when a WMF-specific feature has needed some kind of non-PHP runtime, that feature gets developed in a dedicated extension (as opposed to being included in MW core), and the dependency is managed separately as some kind of external service. For example, the CirrusSearch extension depends on ElasticSearch, which is written in Java. A dedicated ElasticSearch service is deployed to the WMF server cluster and tools like Docker or Vagrant are used in local development.
This approach keeps MW core simple and deployable to shared hosting, but the trade-off is that WMF projects must often coordinate several different services in order to run. Local development for WMF projects has gotten increasingly complex as a result.
It would probably be possible to set up a JS runtime as an external service in order to provide some basic SSR functionality (see: T286963). But adding yet another service that may or may not be available at any given time (and needs to be provisioned, deployed, maintained, etc) seems like a less-than-ideal solution.
Questions
Should we consider introducing some kind of JS runtime into MW core itself, as opposed to deploying an external service that will only be usable for WMF projects?
Potential benefits:
- We could solve several of the problems listed above instead of just one of them at a time
- We could provide better integration of Vue or JS tools into MW
- Avoid the added complexity of yet another service to maintain
- We could align our front-end development practices to be more in line with the standard ways of doing things in 2023
Potential drawbacks:
- We may be burdening downstream users of MW with additional requirements
- JS runtimes can be quite large – several dozen to ~100MB or so
- Some attention would need to be given to securing this runtime (we probably don't want to just allow things to run npm install for example)
Other Considerations
- The PHPv8 project exposes bindings for V8 (Google's open-source JS engine, written in C++ and compiled as a cross-platform executable) for use in PHP applications. Could we use PHPv8 not just for SSR but for other things too (like a front-end build step, typescript compilation, etc)?
- There is a new generation of alternative Node.js runtimes like Bun, Deno that are focused on security and performance (especially in SSR use-cases). These may be worth looking into and may get around some of the performance problems that would result from just naively shelling out to a Node.js executable during a web request. ESBuild, while not a full Node.js Runtime, may also be worth looking at.
Next Steps
TBD. Figuring out what we want to do here will have a lot of implications for the other initiatives around SSR and front-end build step; we may want to try to solve this problem first.