Dashboard: Suspense-based widget render demo (temporary)#77634
Dashboard: Suspense-based widget render demo (temporary)#77634retrofox wants to merge 35 commits into
Conversation
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
623e407 to
518ef2c
Compare
|
Size Change: +2 B (0%) Total Size: 7.97 MB 📦 View Changed
ℹ️ View Unchanged
|
|
Flaky tests detected in 88f8665. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/26091317414
|
518ef2c to
1d746c9
Compare
|
I moved each widget to its own PR:
|
What?
Follow-up branch-off of #77347. Adds a minimal demo inside the dashboard page that renders the
hello-worldwidget (the fixture shipped by #77347) usingReact.Suspense+React.lazyto dynamically import the widget render script module.The goal is to prove the producer → runtime pipeline end-to-end: a widget dropped in
widgets/, built and registered by wp-build (#77576 / #77347), becomes reachable from the dashboard surface via the WordPress script module import map.Part of #77616.
Why?
#77347 ships the producer side (wp-build discovers widgets and registers script modules) but no surface currently consumes them. Without a consumer we have nothing visible to demonstrate that the pipeline actually reaches the browser — the build output is just PHP + asset files.
This PR adds that consumer in the smallest possible form. It is intentionally hardcoded, intentionally narrow, and intentionally temporary. The full rendering engine (generic widget renderer, error boundaries, layout-driven composition) is out of scope; this is purely a proof point that we can move from a registered module to a rendered component asynchronously.
This code is expected to be deleted as soon as the real rendering engine lands. Both touched files carry a visible
TEMPORARY DEMO — DELETE WHEN…comment block to make that explicit for future maintainers, and the PR is structured so the deletion is a clean revert of two files.How?
Client side —
routes/dashboard/stage.tsxReact.lazywraps a dynamic import of the widget's script module specifier (wp/widgets/hello-world/render). The specifier is passed through an opaquenew Function( 'specifier', 'return import( specifier );' )wrapper so esbuild does not attempt to resolve it at build time — the module is resolved at runtime by the browser via the import map. The lazy component is mounted inside a<Suspense fallback={…}>boundary.Server side —
lib/experimental/dashboard-widgets/load.phpHooks on
dashboard_initanddashboard-wp-admin_initto register the widget render handle as a dynamic dependency of the dashboard module, via the existing route machinery (gutenberg_register_dashboard_route). A non-navigable path (/__widget_demo_hello_world) is used purely to get the handle into the import map —wp_enqueue_script_module()alone is not enough, because WordPress's import map only contains the dependencies of enqueued modules, not the enqueued modules themselves.Gated behind the
gutenberg-dashboard-widgetsexperiment flag (the same gate that controls the dashboard shell).Testing
add/wp-build-widgets-support(Build: Addwidgets/folder support to @wordpress/build #77347).npm install && npm run build./wp-admin/admin.php?page=gutenberg-experiments./wp-admin/admin.php?page=dashboard.Loading widget…fallback, thenHello Worldrendered inside the dashboard page.JS. Expected:render.js(the widget bundle) is fetched as a separate request, not inlined. Throttle to Slow 3G to see the Suspense fallback clearly.<script type="importmap">. Expected:"wp/widgets/hello-world/render"listed underimports.Follow-ups
TEMPORARY DEMO — DELETE WHEN…comments point at the expected replacement).wordpressExternalsPluginto accept non-@wordpress/prefixes as externals, so thenew Functionworkaround for the specifier is no longer required.{page}_script_module_dependenciesfilter once it exists.