From 71f7462524be86191a748d78ea42b89666d0618d Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Fri, 12 Jun 2026 15:35:09 +0100 Subject: [PATCH] Core Abilities: Restore the ready promise and lazy-load via dynamic import Restores the public API removed in #78316: importing @wordpress/core-abilities auto-initializes again and the exported ready promise resolves once all server abilities and categories are registered. The initialize() export is removed. The performance win from #78316 (no /wp-abilities/v1/* requests on admin page load) is kept by moving the laziness to the module graph: the workflow palette now dynamically imports the package when it opens, so the module only loads (and fetches) on demand. The unconditional admin enqueue is removed accordingly. --- lib/client-assets.php | 8 ------ packages/core-abilities/README.md | 26 ++++++++++++++----- packages/core-abilities/src/index.ts | 23 ++++++---------- .../workflow/src/components/workflow-menu.js | 5 ++-- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/lib/client-assets.php b/lib/client-assets.php index 83e277e622a23d..0494e5c6275745 100644 --- a/lib/client-assets.php +++ b/lib/client-assets.php @@ -489,11 +489,3 @@ function gutenberg_enqueue_vips_loader() { function gutenberg_enqueue_video_conversion_loader() { wp_enqueue_script_module( '@wordpress/video-conversion/loader' ); } - -/** - * Enqueues the core abilities script module in the admin screens. - */ -add_action( 'admin_enqueue_scripts', 'gutenberg_enqueue_core_abilities' ); -function gutenberg_enqueue_core_abilities() { - wp_enqueue_script_module( '@wordpress/core-abilities' ); -} diff --git a/packages/core-abilities/README.md b/packages/core-abilities/README.md index fc22fe4d63ce06..d425b22139b468 100644 --- a/packages/core-abilities/README.md +++ b/packages/core-abilities/README.md @@ -16,23 +16,37 @@ _This package assumes that your code will run in an ES2015+ environment. If you' ## Usage -This package is designed to be loaded as a script module on WordPress admin pages. It exposes an `initialize()` function that, on first call: +This package is designed to be loaded as a script module on WordPress admin pages. When loaded, it automatically: -1. Fetches all ability categories from `/wp-abilities/v1/categories` and registers them with `@wordpress/abilities` -2. Fetches all abilities from `/wp-abilities/v1/abilities` and registers them with a `callback` that handles execution via REST API +1. Fetches all ability categories from `/wp-abilities/v1/categories` +2. Registers them with `@wordpress/abilities` +3. Fetches all abilities from `/wp-abilities/v1/abilities` +4. Registers them with a `callback` that handles execution via REST API -Initialization is lazy: importing the package does not trigger network requests. Call `initialize()` from the feature that needs abilities — for example, when the workflow palette opens. Repeated calls return the same in-flight or resolved promise, so the requests fire at most once. +Simply import the package to initialize the WordPress abilities: ```js -import { initialize } from '@wordpress/core-abilities'; +import '@wordpress/core-abilities'; +``` + +Initialization is asynchronous because categories and abilities are fetched from the REST API. To wait for registration to finish before calling `getAbilities()` or `executeAbility()`, await the exported `ready` promise: + +```js +import { ready } from '@wordpress/core-abilities'; import { getAbilities, executeAbility } from '@wordpress/abilities'; -await initialize(); +await ready; console.log( getAbilities() ); console.log( await executeAbility( 'core/get-site-info' ) ); ``` +To defer the network requests until a feature actually needs abilities, import the package dynamically from that feature — the module (and therefore its requests) only loads when the `import()` call runs: + +```js +await import( '@wordpress/core-abilities' ); +``` + ## Contributing to this package This is an individual package that's part of the Gutenberg project. The project is organized as a monorepo. It's made up of multiple self-contained software packages, each with a specific purpose. The packages in this monorepo are published to [npm](https://www.npmjs.com/) and used by [WordPress](https://make.wordpress.org/core/) as well as other software projects. diff --git a/packages/core-abilities/src/index.ts b/packages/core-abilities/src/index.ts index e42dc229509d39..03a4ba16e63f5e 100644 --- a/packages/core-abilities/src/index.ts +++ b/packages/core-abilities/src/index.ts @@ -133,21 +133,14 @@ async function initializeAbilities(): Promise< void > { } } -let initializePromise: Promise< void > | null = null; - /** - * Fetches and registers core abilities and their categories. - * - * Memoized: repeated calls return the same in-flight or resolved promise, so - * callers can invoke it from multiple entry points without triggering duplicate - * REST requests. + * Initialize WordPress abilities integration. */ -export function initialize(): Promise< void > { - if ( ! initializePromise ) { - initializePromise = ( async () => { - await initializeCategories(); - await initializeAbilities(); - } )(); - } - return initializePromise; +async function initialize(): Promise< void > { + // Fetch and register categories, then abilities + await initializeCategories(); + await initializeAbilities(); } + +// Auto-initialize on import. +export const ready: Promise< void > = initialize(); diff --git a/packages/workflow/src/components/workflow-menu.js b/packages/workflow/src/components/workflow-menu.js index 42003391f91982..95c9f647f66933 100644 --- a/packages/workflow/src/components/workflow-menu.js +++ b/packages/workflow/src/components/workflow-menu.js @@ -21,7 +21,6 @@ import { } from '@wordpress/keyboard-shortcuts'; import { Icon, search as inputIcon } from '@wordpress/icons'; import { executeAbility, store as abilitiesStore } from '@wordpress/abilities'; -import { initialize as initializeCoreAbilities } from '@wordpress/core-abilities'; /** * Internal dependencies @@ -128,7 +127,9 @@ export function WorkflowMenu() { useEffect( () => { if ( isOpen ) { - initializeCoreAbilities(); + // Load @wordpress/core-abilities on demand. Importing it fetches + // and registers all server abilities and categories. + import( '@wordpress/core-abilities' ); } }, [ isOpen ] );