wordpress / wordpress-playground Goto Github PK
View Code? Open in Web Editor NEWRun WordPress in the browser via WebAssembly PHP
Home Page: https://w.org/playground/
License: GNU General Public License v2.0
Run WordPress in the browser via WebAssembly PHP
Home Page: https://w.org/playground/
License: GNU General Public License v2.0
<!DOCTYPE html> <html lang="en"> <head> <meta name="viewport" content="width=device-width" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>WordPress › ReadMe</title> <link rel="stylesheet" href="wp-admin/css/install.css?ver=20100228" type="text/css" /> </head> <body> <h1 id="logo"> <a href="https://wordpress.org/"><img alt="WordPress" src="wp-admin/images/wordpress-logo.png" /></a> </h1> <p style="text-align: center">Semantic Personal Publishing Platform</p> <h2>First Things First</h2> <p>Welcome. WordPress is a very special project to me. Every developer and contributor adds something unique to the mix, and together we create something beautiful that I am proud to be a part of. Thousands of hours have gone into WordPress, and we are dedicated to making it better every day. Thank you for making it part of your world.</p> <p style="text-align: right">— Matt Mullenweg</p> <h2>Installation: Famous 5-minute install</h2> <ol> <li>Unzip the package in an empty directory and upload everything.</li> <li>Open <span class="file"><a href="wp-admin/install.php">wp-admin/install.php</a></span> in your browser. It will take you through the process to set up a <code>wp-config.php</code> file with your database connection details. <ol> <li>If for some reason this does not work, do not worry. It may not work on all web hosts. Open up <code>wp-config-sample.php</code> with a text editor like WordPad or similar and fill in your database connection details.</li> <li>Save the file as <code>wp-config.php</code> and upload it.</li> <li>Open <span class="file"><a href="wp-admin/install.php">wp-admin/install.php</a></span> in your browser.</li> </ol> </li> <li>Once the configuration file is set up, the installer will set up the tables needed for your site. If there is an error, double check your <code>wp-config.php</code> file, and try again. If it fails again, please go to the <a href="https://wordpress.org/support/forums/">WordPress support forums</a> with as much data as you can gather.</li> <li><strong>If you did not enter a password, note the password given to you.</strong> If you did not provide a username, it will be <code>admin</code>.</li> <li>The installer should then send you to the <a href="wp-login.php">login page</a>. Sign in with the username and password you chose during the installation. If a password was generated for you, you can then click on “Profile” to change the password.</li> </ol> <h2>Updating</h2> <h3>Using the Automatic Updater</h3> <ol> <li>Open <span class="file"><a href="wp-admin/update-core.php">wp-admin/update-core.php</a></span> in your browser and follow the instructions.</li> <li>You wanted more, perhaps? That’s it!</li> </ol> <h3>Updating Manually</h3> <ol> <li>Before you update anything, make sure you have backup copies of any files you may have modified such as <code>index.php</code>.</li> <li>Delete your old WordPress files, saving ones you’ve modified.</li> <li>Upload the new files.</li> <li>Point your browser to <span class="file"><a href="wp-admin/upgrade.php">/wp-admin/upgrade.php</a>.</span></li> </ol> <h2>Migrating from other systems</h2> <p>WordPress can <a href="https://developer.wordpress.org/advanced-administration/wordpress/import/">import from a number of systems</a>. First you need to get WordPress installed and working as described above, before using <a href="wp-admin/import.php">our import tools</a>.</p> <h2>System Requirements</h2> <ul> <li><a href="https://www.php.net/">PHP</a> version <strong>7.2.24</strong> or greater.</li> <li><a href="https://www.mysql.com/">MySQL</a> version <strong>5.5.5</strong> or greater.</li> </ul> <h3>Recommendations</h3> <ul> <li><a href="https://www.php.net/">PHP</a> version <strong>7.4</strong> or greater.</li> <li><a href="https://www.mysql.com/">MySQL</a> version <strong>8.0</strong> or greater OR <a href="https://mariadb.org/">MariaDB</a> version <strong>10.4</strong> or greater.</li> <li>The <a href="https://httpd.apache.org/docs/2.2/mod/mod_rewrite.html">mod_rewrite</a> Apache module.</li> <li><a href="https://wordpress.org/news/2016/12/moving-toward-ssl/">HTTPS</a> support.</li> <li>A link to <a href="https://wordpress.org/">wordpress.org</a> on your site.</li> </ul> <h2>Online Resources</h2> <p>If you have any questions that are not addressed in this document, please take advantage of WordPress’ numerous online resources:</p> <dl> <dt><a href="https://wordpress.org/documentation/">HelpHub</a></dt> <dd>HelpHub is the encyclopedia of all things WordPress. It is the most comprehensive source of information for WordPress available.</dd> <dt><a href="https://wordpress.org/news/">The WordPress Blog</a></dt> <dd>This is where you’ll find the latest updates and news related to WordPress. Recent WordPress news appears in your administrative dashboard by default.</dd> <dt><a href="https://planet.wordpress.org/">WordPress Planet</a></dt> <dd>The WordPress Planet is a news aggregator that brings together posts from WordPress blogs around the web.</dd> <dt><a href="https://wordpress.org/support/forums/">WordPress Support Forums</a></dt> <dd>If you’ve looked everywhere and still cannot find an answer, the support forums are very active and have a large community ready to help. To help them help you be sure to use a descriptive thread title and describe your question in as much detail as possible.</dd> <dt><a href="https://make.wordpress.org/support/handbook/appendix/other-support-locations/introduction-to-irc/">WordPress <abbr>IRC</abbr> (Internet Relay Chat) Channel</a></dt> <dd>There is an online chat channel that is used for discussion among people who use WordPress and occasionally support topics. The above wiki page should point you in the right direction. (<a href="https://web.libera.chat/#wordpress">irc.libera.chat #wordpress</a>)</dd> </dl> <h2>Final Notes</h2> <ul> <li>If you have any suggestions, ideas, or comments, or if you (gasp!) found a bug, join us in the <a href="https://wordpress.org/support/forums/">Support Forums</a>.</li> <li>WordPress has a robust plugin <abbr>API</abbr> (Application Programming Interface) that makes extending the code easy. If you are a developer interested in utilizing this, see the <a href="https://developer.wordpress.org/plugins/">Plugin Developer Handbook</a>. You shouldn’t modify any of the core code.</li> </ul> <h2>Share the Love</h2> <p>WordPress has no multi-million dollar marketing campaign or celebrity sponsors, but we do have something even better—you. If you enjoy WordPress please consider telling a friend, setting it up for someone less knowledgeable than yourself, or writing the author of a media article that overlooks us.</p> <p>WordPress is the official continuation of <a href="https://cafelog.com/">b2/cafélog</a>, which came from Michel V. The work has been continued by the <a href="https://wordpress.org/about/">WordPress developers</a>. If you would like to support WordPress, please consider <a href="https://wordpress.org/donate/">donating</a>.</p> <h2>License</h2> <p>WordPress is free software, and is released under the terms of the <abbr>GPL</abbr> (GNU General Public License) version 2 or (at your option) any later version. See <a href="license.txt">license.txt</a>.</p> </body> </html>
Right now, PHP syntax errors cause the WASM PHP to return an exit code 2, but it doesn't return any error message. Let's make it provide a regular error message such as Fatal error: Class 'MyClass' not found in ...
The plugins and themes downloaded from the directory are all compressed as .zip
files. However, the current PHP build has no zip
support. Let's add it to enable easy plugin and themes installation.
The largest files to load for the initial paint are:
wp.data
– 13M – the WordPress installation and all its php filesphp-web.wasm
– 6.2M – the WebAssembly PHP buildwp.js
– 182k – the emscripten-generated JS loader for wp.data
php-web.js
– 153k – the emscripten-generated JS loader for php-web.wasm
php-webworker.js
– 153k – same as above, but for the webworker backendLet's shrink them as much as possible.
Here's a few ideas:
.data
and .wasm
files using brotli compression – props to @eliot-akira. Edit: Web servers take care of it and most browsers support the brotli compression!wp.data
from 43M to 13M!.eot
, .gif
, .htaccess
, .md
, .mp4
, .png
, .scss
, .stylelintignore
, .svg
, .ttf
, .txt
, .woff
, and .woff2
filesThe Origin-Agent-Cluster: ?1 is used to request a separate process for the iframe-worker.html
in Google Chrome. It worked perfectly when the root app was served from wasm.wordpress.net
and the iframe-worker.html
was served from wasm-worker.wordpress.net
.
Recently both these domains have been merged to allow direct communication between the Service Worker and the iframe Worker Thread. Now I'm observing the following error message:
The page requested an origin-keyed agent cluster using the Origin-Agent-Cluster header, but could not be origin-keyed since the origin 'https://wasm.wordpress.net' had previously been placed in a site-keyed agent cluster. Update your headers to uniformly request origin-keying for all pages on the origin.
As in the title. Keep reading the thread below for more details.
MySQL is not available in the WASM runtime so /wp-admin/site-health.php
displays the below error. Let's disable site-health.php
entirely for now.
Fatal error: Uncaught Error: Call to undefined function mysql_get_server_info() in /preload/wordpress/wp-admin/includes/class-wp-site-health.php:2 Stack trace: #0 /preload/wordpress/wp-admin/includes/class-wp-site-health.php(2): WP_Site_Health->prepare_sql_data() #1 /preload/wordpress/wp-admin/includes/class-wp-site-health.php(2): WP_Site_Health->get_test_sql_server() #2 /preload/wordpress/wp-admin/includes/class-wp-site-health.php(2): WP_Site_Health->perform_test(Array) #3 /preload/wordpress/wp-includes/class-wp-hook.php(2): WP_Site_Health->enqueue_scripts('site-health.php') #4 /preload/wordpress/wp-includes/class-wp-hook.php(2): WP_Hook->apply_filters(NULL, Array) #5 /preload/wordpress/wp-includes/plugin.php(2): WP_Hook->do_action(Array) #6 /preload/wordpress/wp-admin/admin-header.php(17): do_action('admin_enqueue_s...', 'site-health.php') #7 /preload/wordpress/wp-admin/site-health.php(2): require_once('/preload/wordpr...') #8 php-wasm run script(90): require_once('/preload/wordpr...') #9 {main} thrown in /preload/wordpress/wp-admin/includes/class-wp-site-health.php on line 2
@gziolo reported the following behavior:
For some reason when I load the post editor, it shows only code editing mode. I can’t enable the visual mode.
The npm script dev:web:html
currently depends on fswatch
and xargs
to watch files and copy to dist-web
.
I ran sudo apt install fswatch
, but encountered another snag.
xargs: warning: options --max-args and --replace/-I/-i are mutually exclusive, ignoring previous --max-args value
When I make a change to src/web/index.html
, it goes into an infinite loop.
Rather than try to figure out this issue, I think a better solution is to replace the script with a cross-platform solution that doesn't depend on fswatch
being installed in the environment.
I looked around on npm and chokidar-cli
seems suitable.
The new script would look like:
{
"scripts": {
"dev:web:html": "chokidar \"./src/web/*.html\" -c \"cp src/web/*.html dist-web/\""
},
"devDependencies": {
"chokidar-cli": "^3.0.0"
}
}
I confirmed that it works as expected. If the above change looks OK, I'd be happy to turn it into a pull request.
It would be nice if there were some images pre-installed so users can play with blocks that require image uploads.
Similar to #1 – sometimes the page goes blank without any visible error.
Let's make it easy to embed runedditable code examples in the technical documentation.
A minimal implementation already exists at https://adamziel.github.io/embed.html#IkhleSB0aGVyZSEi
One problem with it is the code editor – it has much less affordances than the one on StackBlitz. I mean code completion, files explorer, linter integration etc.
Let's build a minimal "full widget" app for embedding editable code snippets.
#48 Introduced a support for file uploads. Unfortunately, it infers the Content-type
based on the file extension. This is unsafe, unreliable, and may lead to code execution vulnerabilities if a PHP file is uploaded with a different extension. Let's infer the Content-type
from the file contents instead of its extension.
At the moment, all database changes and uploads are gone once the page is refreshed. Preserving them would be useful for courses, technical demos, even sharing a link to your changes.
A few ideas:
localStorage
could store the binary contents of the .sqlite
file every few secondsOccasionally in Safari I get a unstyled admin page, seemingly because the wp-admin/load-styles.php
call failed or timed out.
If static files are simpler for it to serve, it would be beneficial to remove the concatenation, as it serves no purpose other than to reduce network round time trips and most admin pages will have a different set of styles/scripts causing the browser caches to be ignored.
This can be done by using the following, which disables concatenation and gzip'ing of static resources.
define( 'CONCATENATE_SCRIPTS', false );
It errors out with:
Uncaught (in promise) TypeError: NetworkError when attempting to fetch resource.
See https://wasm.wordpress.net/wordpress.html
It's probably something with HTTP headers or XHR binary mode. Perhaps switching FF to a webworker backend would help?
The service worker passes requests to .php
files to the web worker. However, the web worker may not be loaded yet or it could be busy at the moment.
Reply with HTTP 502 or HTTP 408 eventually somewhere here:
It doesn't make much sense to split the build process into "build" and "publish" commands – let's merge all the logic into "build".
Let's figure out how to do it. cc @gziolo
php.wasm
can copy() files with content just file:
console.log(await php.run(`<?php
file_put_contents('with_content.txt', 'hey!');
var_dump(copy('with_content.txt', 'with_content.txt'));
// bool(true);
`));
However, trying to copy an empty file causes a JavaScript exception:
console.log(await php.run(`<?php
file_put_contents('empty.txt', '');
var_dump(copy('empty.txt', 'copied_empty.txt'));
`));
The exception:
TypeError: Cannot read properties of null (reading 'buffer')
at Object.mmap (http://127.0.0.1:8778/php-web.js:2764:40)
at Object.mmap (http://127.0.0.1:8778/php-web.js:3787:34)
at syscallMmap2 (http://127.0.0.1:8778/php-web.js:5862:22)
at ___sys_mmap2 (http://127.0.0.1:8778/php-web.js:5870:14)
at ___syscall192 (http://127.0.0.1:8778/php-web.js:5877:10)
at ___mmap (wasm://wasm/04421bd2:wasm-function[8927]:0x9473e2)
at _php_stdiop_set_option (wasm://wasm/04421bd2:wasm-function[2855]:0x3209c9)
at __php_stream_set_option (wasm://wasm/04421bd2:wasm-function[2747]:0x314b63)
at __php_stream_mmap_range (wasm://wasm/04421bd2:wasm-function[2879]:0x325b18)
at __php_stream_copy_to_stream_ex (wasm://wasm/04421bd2:wasm-function[2761]:0x317285)
It happens on MEMFS and WASMFS. I spent a day trying to find the root cause and work around it, but I couldn't.
As a consequence, installing plugins often fails as many plugins ship with at least one empty file.
Currently the different parts of this project are vaguely separated. Let's use a stronger delineation to make the pieces reusable and make it easier for new contributors to get started.
A proposed list of packages:
PHP
JavaScript class with eval
for executing PHP code and FS utils like writeFile
for runtime managing thephp-wasm
the browser
PHPServer
JavaScript class for dispatching HTTP requests – both to run the PHP files AND to download static filesServiceWorker
to redirect the browser traffic to PHPServer
WasmWorker
to offload the PHPServer
to a separate process (With the existing three backends: Iframe, Webworker, SharedWorker)PHPBrowser
JavaScript class to consume the above using an iframewasm
files. For starters this could be just .htaccess
plus some documentation.wp.data
bundling pipeline for the web configurable to bundle custom codefetch
-based transport for HTTP requestsAt the moment, the top URL bar only says index.html, and all the navigation happens inside of an iframe. It would be great to have a feature that would update the top-level navigation, perhaps via pushState
. It needs to be optional because updating top-level navigation doesn't make sense in contexts like runnable code examples.
Make each build generate a unique version string, and then use it to load resources, e.g. /iframe-worker.html?version=78a4
, /php-web.wasm?version=78a4
etc. Otherwise the older assets tends to interfere with the newer builds.
It would be convenient to be able to build this project without needing to run the Dockerfile. It's an obstacle to development to have to run inside a proprietary system and to not be able to directly interact with the sources, assets, and builds.
E.g. a Makefile
for the build which is then run inside Docker would be usable from the outside and inside of the container. Dockerfile
is convenient for normalizing builds and enumerating the dependencies, but it's even more helpful to be able to look at that list of build dependencies, make sure they're available on my local system, and then directly build the project without Docker. It's also likely significantly more efficient to do that.
Right now, adding a plugin zip bundle to the URL preinstalls that plugin, for example the URL below preinstalls coblocks and then redirect the user to the post-new.php page to play with the plugin:
https://wasm.wordpress.net/wordpress.html?plugin=coblocks.2.24.4.zip&url=/wp-admin/post-new.php
Let's also support an array of plugins, for example:
https://wasm.wordpress.net/wordpress.html?plugin=coblocks.2.24.4.zip&plugin=gutenberg.14.5.4.zip&url=/wp-admin/post-new.php
This repository doesn't have any documentation at the moment. Let's add some. I will soon publish a make.wordpress.org post with plenty of technical details – it will make a great first draft to iterate on.
Mention:
When deploying a demo site, I noticed it works fine when I visit the static file specifically, like example.com/index.html
, but it has some unpredictable behavior with the root domain only, like example.com
. Sometimes it takes a long time to load, or doesn't load at all.
I tracked down the cause (I think) to the service worker intercepting the visit to the host site and serving the WordPress site via the web worker, outside/without the iframe.
I'm still wrapping my head around how all of this works, but I figured I'd make a note of it. Will report back if I'm able to solve it.
The WASM PHP crashes in chrome. It does not crash in Firefox, Safari, and node.js.
See the minimal reproduction in bug-reproduction.zip. It consists of two HTML files: breaks_here.html and works_here.html. The first one demonstrates the problem in the worker and the second one shows that the issue does not occur in the main thread crashes too, although less frequently.
The issue is the most apparent inside of a webworker, but it also exists when WASM is initialized in the main browser thread. The code below is enough to trigger the crash. Note we don't even run any wasm code, just instantiate the module:
(() => {
// src/web/web-worker.js
console.log("[WebWorker] Spawned");
var wasmTable = new WebAssembly.Table({
initial: 1090,
maximum: 1090,
element: "anyfunc"
});
var WASM_PAGE_SIZE = 65536;
var INITIAL_INITIAL_MEMORY = 1073741824;
var wasmMemory = new WebAssembly.Memory({
initial: INITIAL_INITIAL_MEMORY / WASM_PAGE_SIZE
});
var info = {
env: {
_zend_empty_array2: 1,
tempDoublePtr: 2303696,
"__memory_base": 1024,
__table_base: 0,
memory: wasmMemory,
table: wasmTable
},
global: { NaN: NaN, Infinity: Infinity },
asm2wasm: {
"f64-rem"() {
}
}
};
fetch("updated.wasm").then(async (response) => {
WebAssembly.instantiate(
await response.arrayBuffer(),
info
).then(() => {
console.log("Instantiated!");
});
console.log("Called instantiate");
});
console.log("Called fetch", { info });
})();
The Chromium team shared the following stack trace proving this is an out of memory problem:
Magic Signature >> [Out of Memory] v8::internal::Zone::NewExpand
Stack Trace >>
Thread 26 ThreadPoolForegroundWorker (id: 0x005aad74)crashedMAGIC SIGNATURE THREADcontent_copy
0x00000001211dbf58(Google Chrome Framework -oom.cc:58)partition_alloc::internal::OnNoMemoryInternal(unsigned long)
0x00000001211dbf68(Google Chrome Framework -oom.cc:65)partition_alloc::TerminateBecauseOutOfMemory(unsigned long)
0x00000001211dbf85(Google Chrome Framework -oom.cc:75)partition_alloc::internal::OnNoMemory(unsigned long)
0x00000001246e95b2(Google Chrome Framework -partitions.cc:323)WTF::PartitionsOutOfMemoryUsing512M(unsigned long)
0x00000001246e948c(Google Chrome Framework -partitions.cc:448)WTF::Partitions::HandleOutOfMemory(unsigned long)
0x00000001211dd8b3(Google Chrome Framework -partition_root.cc:619)partition_alloc::PartitionRoot<true>::OutOfMemory(unsigned long)
0x00000001211dca8a(Google Chrome Framework -partition_bucket.cc:48)void partition_alloc::internal::(anonymous namespace)::PartitionOutOfMemoryMappingFailure<true>(partition_alloc::PartitionRoot<true>*, unsigned long)
0x000000011dfa61de(Google Chrome Framework -partition_bucket.cc:691)partition_alloc::internal::PartitionBucket<true>::SlowPathAlloc(partition_alloc::PartitionRoot<true>*, unsigned int, unsigned long, unsigned long, bool*)
0x000000011dfae2cc(Google Chrome Framework -partition_root.h:1072)base::AllocNonQuarantinable(unsigned long)
0x000000011df36397(Google Chrome Framework -allocation.cc:141)v8::internal::Zone::NewExpand(unsigned long)
0x0000000120a961d4(Google Chrome Framework + 0x0000000002b851d4)std::Cr::vector<v8::internal::compiler::Node*, v8::internal::ZoneAllocator<v8::internal::compiler::Node*>>::vector(std::Cr::vector<v8::internal::compiler::Node*, v8::internal::ZoneAllocator<v8::internal::compiler::Node*>> const&)
0x0000000122d2a138(Google Chrome Framework + 0x0000000004e19138)v8::internal::wasm::(anonymous namespace)::WasmGraphBuildingInterface::Split(v8::internal::Zone*, v8::internal::wasm::(anonymous namespace)::SsaEnv*)
0x0000000122d2bfc5(Google Chrome Framework + 0x0000000004e1afc5)v8::internal::wasm::(anonymous namespace)::WasmGraphBuildingInterface::BrOrRet(v8::internal::wasm::WasmFullDecoder<(v8::internal::wasm::Decoder::ValidateFlag)2, v8::internal::wasm::(anonymous namespace)::WasmGraphBuildingInterface, (v8::internal::wasm::DecodingMode)0>*, unsigned int, unsigned int)
0x0000000122d1efc4(Google Chrome Framework + 0x0000000004e0dfc4)v8::internal::wasm::WasmFullDecoder<(v8::internal::wasm::Decoder::ValidateFlag)2, v8::internal::wasm::(anonymous namespace)::WasmGraphBuildingInterface, (v8::internal::wasm::DecodingMode)0>::DecodeBrTable(v8::internal::wasm::WasmFullDecoder<(v8::internal::wasm::Decoder::ValidateFlag)2, v8::internal::wasm::(anonymous namespace)::WasmGraphBuildingInterface, (v8::internal::wasm::DecodingMode)0>*, v8::internal::wasm::WasmOpcode)
0x0000000122d1b301(Google Chrome Framework + 0x0000000004e0a301)v8::internal::wasm::WasmFullDecoder<(v8::internal::wasm::Decoder::ValidateFlag)2, v8::internal::wasm::(anonymous namespace)::WasmGraphBuildingInterface, (v8::internal::wasm::DecodingMode)0>::Decode()
0x0000000122d1ab36(Google Chrome Framework + 0x0000000004e09b36)v8::internal::wasm::BuildTFGraph(v8::internal::AccountingAllocator*, v8::internal::wasm::WasmFeatures const&, v8::internal::wasm::WasmModule const*, v8::internal::compiler::WasmGraphBuilder*, v8::internal::wasm::WasmFeatures*, v8::internal::wasm::FunctionBody const&, std::Cr::vector<v8::internal::compiler::WasmLoopInfo, std::Cr::allocator<v8::internal::compiler::WasmLoopInfo>>*, v8::internal::compiler::NodeOriginTable*, int, v8::internal::wasm::InlinedStatus)
0x0000000122ee6b35(Google Chrome Framework + 0x0000000004fd5b35)v8::internal::compiler::ExecuteTurbofanWasmCompilation(v8::internal::wasm::CompilationEnv*, v8::internal::wasm::WireBytesStorage const*, v8::internal::wasm::FunctionBody const&, int, v8::internal::Counters*, v8::internal::wasm::AssemblerBufferCache*, v8::internal::wasm::WasmFeatures*)
0x000000012082f8b6(Google Chrome Framework + 0x000000000291e8b6)v8::internal::wasm::WasmCompilationUnit::ExecuteCompilation(v8::internal::wasm::CompilationEnv*, v8::internal::wasm::WireBytesStorage const*, v8::internal::Counters*, v8::internal::wasm::AssemblerBufferCache*, v8::internal::wasm::WasmFeatures*)
0x00000001207fc41d(Google Chrome Framework + 0x00000000028eb41d)v8::internal::wasm::(anonymous namespace)::ExecuteCompilationUnits(std::Cr::weak_ptr<v8::internal::wasm::NativeModule>, v8::internal::Counters*, v8::JobDelegate*, v8::internal::wasm::(anonymous namespace)::CompileBaselineOnly)
0x0000000120a96633(Google Chrome Framework + 0x0000000002b85633)v8::internal::wasm::(anonymous namespace)::BackgroundCompileJob::Run(v8::JobDelegate*) (.886d8138751ea58144f90ddffe92ca79)
0x0000000125c6e110(Google Chrome Framework -v8_platform.cc:458)base::internal::Invoker<base::internal::BindState<gin::V8Platform::CreateJob(v8::TaskPriority, std::Cr::unique_ptr<v8::JobTask, std::Cr::default_delete<v8::JobTask>>)::$_0, std::Cr::unique_ptr<v8::JobTask, std::Cr::default_delete<v8::JobTask>>>, void (base::JobDelegate*)>::Run(base::internal::BindStateBase*, base::JobDelegate*)
0x000000012549ec24(Google Chrome Framework -callback.h:263)base::internal::Invoker<base::internal::BindState<base::internal::JobTaskSource::JobTaskSource(base::Location const&, base::TaskTraits const&, base::RepeatingCallback<void (base::JobDelegate*)>, base::RepeatingCallback<unsigned long (unsigned long)>, base::internal::PooledTaskRunnerDelegate*)::$_0, base::internal::UnretainedWrapper<base::internal::JobTaskSource>>, void ()>::Run(base::internal::BindStateBase*)
0x000000011e3e3a06(Google Chrome Framework -callback.h:145)base::internal::TaskTracker::RunSkipOnShutdown(base::internal::Task&, base::TaskTraits const&, base::internal::TaskSource*, base::SequenceToken const&)
0x000000011e58a828(Google Chrome Framework -task_tracker.cc:724)base::internal::TaskTracker::RunAndPopNextTask(base::internal::RegisteredTaskSource)
0x000000011e6e8d9d(Google Chrome Framework -worker_thread.cc:448)base::internal::WorkerThread::RunWorker()
0x00000001238739dc(Google Chrome Framework -worker_thread.cc:335)base::internal::WorkerThread::RunPooledWorker()
0x000000011f091c56(Google Chrome Framework -worker_thread.cc:315)base::internal::WorkerThread::ThreadMain()
0x000000011ee21522(Google Chrome Framework -platform_thread_posix.cc:101)base::(anonymous namespace)::ThreadFunc(void*)
0x00007ff81a49b4e0(libsystem_pthread.dylib + 0x000064e0)
0x00007ff81a496f6a(libsystem_pthread.dylib + 0x00001f6a)
I did some debugging before they shared that stack trace. The list below is less relevant than the specific details in the stack trace above, but I'm still posting it here for posterity:
TERMINATION_STATUS_PROCESS_CRASHED
.valgrind
would help, but it won't run on Mac.about:crash
and other crashes. minidump-stackwalk gets its symbols from google-breakpad symbol files. Symbol files are a plain-text format intended to unify the contents of various platform-specific debuginfo/unwinding formats like PE32 Unwinding Tables, Dwarf CFI, Macho Compact Unwinding Info, etc.
To generate those files from your build artifacts, use either Mozilla's dump_syms (recommended) or google-breakpad's dump_syms.
#
# Fatal error in ../../v8/src/debug/debug-interface.cc, line 352
# Debug check failed: !isolate->is_execution_terminating().
#
#
#
#FailureMessage Object: 0x700009b7bc60[33312:259:0929/223909.968925:VERBOSE1:node.cc(1175)] OnUpdatePreviousPeer port: E64B3F19A9C61113.8955D49085231446 changing to AA7F7063054BDC96.DF5C9FB08811A500, port: E2387E855C7DDE33.6435B60F182B2A50 => BFD53B2279161D17.D245A7E2302529BE
[33609:18179:0929/223909.969410:VERBOSE1:node.cc(1175)] OnUpdatePreviousPeer port: BFD53B2279161D17.D245A7E2302529BE changing to 6975933DD5F27952.C20103EDCDFD9098, port: E2387E855C7DDE33.6435B60F182B2A50 => E64B3F19A9C61113.8955D49085231446
[33614:259:0929/223909.971940:VERBOSE1:paint_controller.cc(709)] PaintController::FinishCycle() completed
0 libbase.dylib 0x000000010d65f21c base::debug::CollectStackTrace(void**, unsigned long) + 44
1 libbase.dylib 0x000000010d2f6978 base::debug::StackTrace::StackTrace(unsigned long) + 72
2 libbase.dylib 0x000000010d2f69fd base::debug::StackTrace::StackTrace(unsigned long) + 29
3 libbase.dylib 0x000000010d2f69d5 base::debug::StackTrace::StackTrace() + 37
4 libgin.dylib 0x00000001a7b79d1b gin::(anonymous namespace)::PrintStackTrace() + 59
5 libv8_libbase.dylib 0x0000000119cd80f1 V8_Fatal(char const*, int, char const*, ...) + 337
6 libv8_libbase.dylib 0x0000000119cd78e5 v8::base::(anonymous namespace)::DefaultDcheckHandler(char const*, int, char const*) + 21
7 libv8.dylib 0x00000001d4423933 v8::debug::SetBreakPointsActive(v8::Isolate*, bool) + 291
8 libv8.dylib 0x00000001d5558df3 v8_inspector::V8DebuggerAgentImpl::disable() + 419
9 libv8.dylib 0x00000001d5587bca v8_inspector::V8InspectorSessionImpl::~V8InspectorSessionImpl() + 346
10 libv8.dylib 0x00000001d5587d9e v8_inspector::V8InspectorSessionImpl::~V8InspectorSessionImpl() + 14
11 libblink_core.dylib 0x00000001df137d4c std::Cr::default_delete<v8_inspector::V8InspectorSession>::operator()[abi:v16000](v8_inspector::V8InspectorSession*) const + 44
12 libblink_core.dylib 0x00000001df12792a std::Cr::unique_ptr<v8_inspector::V8InspectorSession, std::Cr::default_delete<v8_inspector::V8InspectorSession>>::reset[abi:v16000](v8_inspector::V8InspectorSession*) + 106
13 libblink_core.dylib 0x00000001df126c08 blink::DevToolsSession::Detach() + 1288
[33312:259:0929/223909.985578:VERBOSE1:node.cc(1175)] OnUpdatePreviousPeer port: 49CA70FD9D9D7B94.3536F4AFEA56CA2C changing to AA7F7063054BDC96.DF5C9FB08811A500, port: 64987F6ACCED8335.8529510F6C84227 => 12FA36F038112775.2F840886748B53FC
14 libblink_core.dylib 0x00000001df10b64f blink::DevToolsAgent::Dispose() + 527
15 libblink_core.dylib 0x00000001df508b77 blink::WorkerInspectorController::Dispose() + 183
16 libblink_core.dylib 0x00000001e08501ce blink::WorkerThread::PerformShutdownOnWorkerThread() + 526
17 libblink_core.dylib 0x00000001e085726a void base::internal::FunctorTraits<void (blink::WorkerThread::*)(), void>::Invoke<void (blink::WorkerThread::*)(), blink::WorkerThread*>(void (blink::WorkerThread::*)(), blink::WorkerThread*&&) + 122
18 libblink_core.dylib 0x00000001e08571e4 void base::internal::InvokeHelper<false, void>::MakeItSo<void (blink::WorkerThread::*)(), blink::WorkerThread*>(void (blink::WorkerThread::*&&)(), blink::WorkerThread*&&) + 52
19 libblink_core.dylib 0x00000001e0857188 void base::internal::Invoker<base::internal::BindState<void (blink::WorkerThread::*)(), WTF::CrossThreadUnretainedWrapper<blink::WorkerThread>>, void ()>::RunImpl<void (blink::WorkerThread::*)(), std::Cr::tuple<WTF::CrossThreadUnretainedWrapper<blink::WorkerThread>>, 0ul>(void (blink::WorkerThread::*&&)(), std::Cr::tuple<WTF::CrossThreadUnretainedWrapper<blink::WorkerThread>>&&, std::Cr::integer_sequence<unsigned long, 0ul>) + 72
20 libblink_core.dylib 0x00000001e08570e7 base::internal::Invoker<base::internal::BindState<void (blink::WorkerThread::*)(), WTF::CrossThreadUnretainedWrapper<blink::WorkerThread>>, void ()>::RunOnce(base::internal::BindStateBase*) + 55
21 libbase.dylib 0x000000010d2a2887 base::OnceCallback<void ()>::Run() && + 103
22 libbase.dylib 0x000000010d504492 base::TaskAnnotator::RunTaskImpl(base::PendingTask&) + 418
23 libbase.dylib 0x000000010d56feae _ZN4base13TaskAnnotator7RunTaskIJZNS_16sequence_manager8internal35ThreadControllerWithMessagePumpImpl10DoWorkImplEPNS_7LazyNowEE3$_0EEEvN8perfetto12StaticStringERNS_11PendingTaskEDpOT_ + 126
24 libbase.dylib 0x000000010d56f9fa base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWorkImpl(base::LazyNow*) + 2362
25 libbase.dylib 0x000000010d56ebb6 base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWork() + 246
26 libbase.dylib 0x000000010d56fd13 non-virtual thunk to base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWork() + 35
27 libbase.dylib 0x000000010d389497 base::MessagePumpDefault::Run(base::MessagePump::Delegate*) + 151
28 libbase.dylib 0x000000010d570661 base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::Run(bool, base::TimeDelta) + 705
29 libbase.dylib 0x000000010d46b483 base::RunLoop::Run(base::Location const&) + 755
30 libblink_platform.dylib 0x00000001f0ab9b88 blink::scheduler::NonMainThreadImpl::SimpleThreadImpl::Run() + 568
31 libbase.dylib 0x000000010d5fcf0a base::SimpleThread::ThreadMain() + 74
32 libbase.dylib 0x000000010d68b2f2 base::(anonymous namespace)::ThreadFunc(void*) + 226
33 libsystem_pthread.dylib 0x00007ff81a49b4e1 _pthread_start + 125
34 libsystem_pthread.dylib 0x00007ff81a496f6b thread_start + 15
I built Chromium on Mac like this:
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
export PATH="$PATH:"`pwd`
cd ~/ && mkdir chromium && cd chromium
caffeinate fetch --no-history chromium
caffeinate autoninja -C out/Default chrome
./out/Default/Chromium.app/Contents/MacOS/Chromium --enable-logging --v=1
Then, I created a new empty xcode project and used the Debug > Attach to > Chromium
from the top level menu. Finally, I paused the process and set a breakpoint on the error page handler like this:
(lldb) b SadTab
It didn't yield much information so I looked for scraps of information and set further breakpoints:
GetTerminationStatus
– breakpoint wasn't triggeredV8_Fatal
– breakpoint wasn't triggeredPerformShutdownOnWorkerThread
– breakpoint wasn't triggeredSee more information at:
With 50 MB of resources to download, a loading indicator seems like a necessity. A simple spinner would be a great start, but the loading might take a while and an actual progress bar with real progress would provide a much better experience.
WebAssembly WordPress applies a few WordPress patches once it's started. The method is quite peculiar – a PHP code snippet reads these files from the in-memory filesystem, runs some str_replaces, and then writes these files back:
The bundling pipeline could be updated to also apply a few .patch files to WordPress. This way, WebAssembly environment would already boot with the patched version.
Let's create a script to bundle the nightly WordPress release. It should make testing new features easy and make a great first step for running arbitrary pull requests in WASM instead of just the major releases.
Such a script would enable having a WASM demo page on WordPress.org.
As I mentioned in #40, the address bar appeared to be broken.
I was expecting to get to the login screen by visiting /wp-admin
but instead, nothing happened.
Here's an example:
https://d.pr/i/8pJzL1
At the moment, uploading files e.g. in media library isn't supported by the PHP request handler. Here's one way to solve it:
$_FILES
entries in the WASM workerI navigated to /wp-admin
in the demo, and I just guessed the username and password (admin
/ password
), but it would be great if this was noted below the site frame so people would know upfront. Could even add the login details to the login form.
Let's run automated tests in this repository to prevent regressions.
Would be nice to document the config syntax for using NGINX.
Here's dist-web/.htaccess
for Apache.
AddType application/wasm .wasm
RewriteEngine on
RewriteRule ^scope:.*?/(.*)$ $1 [NC]
RewriteRule ^plugin-proxy$ plugin-proxy.php [NC]
<FilesMatch "iframe-worker.html$">
Header set Origin-Agent-Cluster: ?1
</FilesMatch>
Rough draft for NGINX config (untested).
types {
application/wasm wasm;
}
location /scope:.*?/(.*) {
rewrite ^scope:.*?/(.*)$ $1 last;
}
location /plugin-proxy {
rewrite ^plugin-proxy$ plugin-proxy.php last;
}
location /iframe-worker.html {
add_header Origin-Agent-Cluster ?1;
}
Reference
Make wordpress.html configurable via query params
Currently the only way to navigate the embedded WordPress is by clicking on links. It would be more natural to have actual navigation tools like in a browser. Let's start by rendering WordPress in a fake browser window with its own address bar and a refresh button.
Some UI elements that might come handy:
There is a few different copies of WordPress shipped in this repo. Let's remove the physical copies and download these files as a part of the build/bundle pipeline.
In particular:
src/node/wordpress
– this can be generated when missing during the initial npm run dev:node
dist-node/wordpress
– this can be bundled during the node build processdist/wordpress-*
– these are WordPress static files required to use the browser version via npm run dev
. There should be a universal way to regenerate them on npm run dev:web
.However, let's leave dist/wp.data
and dist/wp.js
in place. Regenerating these files requires a docker setup and could be a significant speed bump for new developers trying to just clone and run this repo.
There are some pre-built files shipped in this repository:
Building them from scratch requires additional setup and takes a long time, which is a bad experience for a new contributor who just wants to clone the project and publish their first PR.
At the same time, shipping these files is a burden – they change, pollute the commit logs, and won't play very well with a support for multiple PHP and WordPress version.
It would be nice to have a separate package (or maybe even a repository?) for these pre-built binaries, and source them from there on the initial build.
The amount of log messages is too large and reduces the usefulness of the logged information. Let's find a solution that supports:
This might be far out there, but here goes...
Since WordPress is working with WebAssembly and SQLite based on this project, how about expanding the scope from testing to production with Cloudflare Workers + CloudFlare D1 (SQLite database)?
Navigating to /wp-admin/site-editor.php
displays a blank page.
I narrowed the problem down to the Editor component in the edit-site.min.js
file:
const isReady = (settings === null || settings === void 0 ? void 0 : settings.siteUrl) && templateType !== undefined && entityId !== undefined;
// ...
return (
<Fragment>
<URLQueryController>
{isReady && ( /* the rest of the component */}
</URLQueryController>
</Fragment>
)
Inspecting the values yields this:
console.log(isReady, settings.siteUrl, templateType, entityId)
// false, 'http://127.0.0.1:8777/scope:0.0936352195928096' undefined undefined
Presumably, this is because a server-side WordPress installation redirects the user from site-editor.php
to site-editor.php?postType=wp_template&postId=twentytwentythree%2F%2Fhome
and the in-browser one doesn't.
This repo could use the usual eslint/prettier setup that JavaScript repos typically use.
A pipeline that builds all the listed PHP versions would pave the way to one-click switching of the PHP version:
The technical foundation was shipped in 45ba8ce. Since that commit, the docker build process can be build a specific PHP version as follows:
docker build . --no-cache --tag=wasm-wordpress-php-builder --build-arg PHP_VERSION="8.0.29" --build-arg VRZNO_FLAG="--disable-vrzno"
I confirmed it works with 7.0.0
, 7.0.24
and even 8.0.29
when vrzno is disabled. It may break for versions that are not compatible with the PHP patches shipped in this repo.
#48 Introduced a support for file uploads. Unfortunately it introduces an assumption that all requests to /wp-content/uploads/*
should be resolved from the WASM filesystem, and all other non-PHP requests should be resolved from the server where wordpress-wasm is hosted.
Let's relax that constraint and correctly serve the static files from either the server or the WASM filesystem regardless of their path.
Clicking on the site title takes the user to an error page, when it should navigate to the home page of the site.
Browsing the same WordPress instance in multiple browser tabs could be useful. Props to @gziolo for the idea.
Technically, it would take:
I'd like to create a custom build of wp.data
with pre-installed plugins. I got pretty close to achieving it, but for some reason the admin screen shows no plugins. Here's what I did:
wasm-build/wordpress-data/prepare-wordpress.sh
to download, unzip, and move a plugin folder into ./wordpress/wp-content/plugins/
npm run build:wp && npm run publish:wp:web
I confirmed that the plugin's static assets were copied to dist-web/wp-content/plugins
. I looked in the built file dist-web/wp.js
, and the plugin's file paths are included from /preload/wordpress/wp-content/plugins
- so I assume the files were successfullly included in wp.data
. But somehow the WordPress instance in the browser is not recognizing it.
Any idea or hint would be greatly appreciated.
In the browser, all the requests to WordPress are routed to a web worker by a service worker. The service worker handles the traffic for the entire domain, which means that all the open tabs are routing their WordPress requests via the same service worker.
Unfortunately, it passes them to all the running web workers instead of targeting specifically the one from the tab where the request originated. When five tabs are opened, five web workers handle all the requests, which causes all sorts of problems.
Find a way to route each request from service worker to only the specific web worker that initiated it. Somewhere around here:
If there was a way to brand all requests from a specific tab somehow, that would be perfect. Perhaps each iframe could pretend to have a unique subdomain? Or each tab could attach a unique cookie or other http header to every request?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.