From 6ddd305d141808e39f2ed7c6bbc24eeeed5e48f3 Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Thu, 16 Feb 2023 14:56:12 +0200 Subject: [PATCH 1/5] Try: Simple async block loading --- package-lock.json | 1 + packages/block-library/README.md | 8 +++++ packages/block-library/src/index.js | 11 ++++--- packages/block-library/src/missing/edit.js | 14 ++++++++- packages/core-data/src/entity-provider.js | 14 ++++++--- packages/editor/package.json | 1 + .../editor/src/components/provider/index.js | 30 +++++++++++++++++-- 7 files changed, 68 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index 03ff37563f40c8..8250c849a8e9d0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17148,6 +17148,7 @@ "@wordpress/api-fetch": "file:packages/api-fetch", "@wordpress/blob": "file:packages/blob", "@wordpress/block-editor": "file:packages/block-editor", + "@wordpress/block-library": "file:packages/block-library", "@wordpress/blocks": "file:packages/blocks", "@wordpress/components": "file:packages/components", "@wordpress/compose": "file:packages/compose", diff --git a/packages/block-library/README.md b/packages/block-library/README.md index 96ec2d8963b3c3..fd82623feb1eff 100644 --- a/packages/block-library/README.md +++ b/packages/block-library/README.md @@ -16,6 +16,14 @@ _This package assumes that your code will run in an **ES2015+** environment. If +### asyncLoadBlock + +Undocumented declaration. + +### getAsyncBlocks + +Undocumented declaration. + ### registerCoreBlocks Function to register core blocks provided by the block editor. diff --git a/packages/block-library/src/index.js b/packages/block-library/src/index.js index 317b1d4fbad5e6..47bd22b5ce1692 100644 --- a/packages/block-library/src/index.js +++ b/packages/block-library/src/index.js @@ -47,12 +47,10 @@ import * as commentsTitle from './comments-title'; import * as cover from './cover'; import * as embed from './embed'; import * as file from './file'; -import * as gallery from './gallery'; import * as group from './group'; import * as heading from './heading'; import * as homeLink from './home-link'; import * as html from './html'; -import * as image from './image'; import * as latestComments from './latest-comments'; import * as latestPosts from './latest-posts'; import * as list from './list'; @@ -126,9 +124,7 @@ const getAllBlocks = () => // Common blocks are grouped at the top to prioritize their display // in various contexts — like the inserter and auto-complete components. paragraph, - image, heading, - gallery, list, listItem, quote, @@ -226,6 +222,13 @@ const getAllBlocks = () => postAuthorBiography, ].filter( Boolean ); +export const getAsyncBlocks = () => [ 'image', 'gallery' ].filter( Boolean ); + +export const asyncLoadBlock = async ( blockType ) => { + const { init } = await import( './' + blockType + '/index.js' ); + init(); +}; + /** * Function to get all the core blocks in an array. * diff --git a/packages/block-library/src/missing/edit.js b/packages/block-library/src/missing/edit.js index 1ef143a639ed06..82d4741c1a0be2 100644 --- a/packages/block-library/src/missing/edit.js +++ b/packages/block-library/src/missing/edit.js @@ -13,7 +13,13 @@ import { } from '@wordpress/block-editor'; import { safeHTML } from '@wordpress/dom'; +/** + * Internal dependencies + */ +import { getAsyncBlocks } from '../../'; + function MissingBlockWarning( { attributes, convertToHTML, clientId } ) { + const asyncBlocks = getAsyncBlocks(); const { originalName, originalUndelimitedContent } = attributes; const hasContent = !! originalUndelimitedContent; const hasHTMLBlock = useSelect( @@ -31,7 +37,13 @@ function MissingBlockWarning( { attributes, convertToHTML, clientId } ) { const actions = []; let messageHTML; - if ( hasContent && hasHTMLBlock ) { + if ( asyncBlocks.includes( originalName.replace( 'core/', '' ) ) ) { + messageHTML = sprintf( + /* translators: %s: block name */ + __( 'The block "%s" is still loading.' ), + originalName + ); + } else if ( hasContent && hasHTMLBlock ) { messageHTML = sprintf( /* translators: %s: block name */ __( diff --git a/packages/core-data/src/entity-provider.js b/packages/core-data/src/entity-provider.js index f9d61aa413fc23..d992ab4916a320 100644 --- a/packages/core-data/src/entity-provider.js +++ b/packages/core-data/src/entity-provider.js @@ -146,10 +146,16 @@ export function useEntityProp( kind, name, prop, _id ) { * @param {string} name The entity name. * @param {Object} options * @param {string} [options.id] An entity ID to use instead of the context-provided one. + * @param {?Array} parseDeps Optional dependencies to trigger entity content re-parsing. * * @return {[WPBlock[], Function, Function]} The block array and setters. */ -export function useEntityBlockEditor( kind, name, { id: _id } = {} ) { +export function useEntityBlockEditor( + kind, + name, + { id: _id } = {}, + parseDeps = undefined +) { const providerId = useEntityId( kind, name ); const id = _id ?? providerId; const { content, blocks } = useSelect( @@ -169,8 +175,8 @@ export function useEntityBlockEditor( kind, name, { id: _id } = {} ) { useEffect( () => { // Load the blocks from the content if not already in state // Guard against other instances that might have - // set content to a function already or the blocks are already in state. - if ( content && typeof content !== 'function' && ! blocks ) { + // set content to a function already. + if ( content && typeof content !== 'function' ) { const parsedContent = parse( content ); editEntityRecord( kind, @@ -182,7 +188,7 @@ export function useEntityBlockEditor( kind, name, { id: _id } = {} ) { { undoIgnore: true } ); } - }, [ content ] ); + }, [ content, parseDeps ] ); const onChange = useCallback( ( newBlocks, options ) => { diff --git a/packages/editor/package.json b/packages/editor/package.json index b06cf73b10e325..e825a04c3df0c0 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -35,6 +35,7 @@ "@wordpress/api-fetch": "file:../api-fetch", "@wordpress/blob": "file:../blob", "@wordpress/block-editor": "file:../block-editor", + "@wordpress/block-library": "file:../block-library", "@wordpress/blocks": "file:../blocks", "@wordpress/components": "file:../components", "@wordpress/compose": "file:../compose", diff --git a/packages/editor/src/components/provider/index.js b/packages/editor/src/components/provider/index.js index 1cff19c7daae7f..34b7cf64ae5bdf 100644 --- a/packages/editor/src/components/provider/index.js +++ b/packages/editor/src/components/provider/index.js @@ -1,7 +1,13 @@ /** * WordPress dependencies */ -import { useEffect, useLayoutEffect, useMemo } from '@wordpress/element'; +import { asyncLoadBlock, getAsyncBlocks } from '@wordpress/block-library'; +import { + useEffect, + useLayoutEffect, + useMemo, + useReducer, +} from '@wordpress/element'; import { useDispatch, useSelect } from '@wordpress/data'; import { __ } from '@wordpress/i18n'; import { EntityProvider, useEntityBlockEditor } from '@wordpress/core-data'; @@ -33,6 +39,25 @@ export const ExperimentalEditorProvider = withRegistryProvider( children, BlockEditorProviderComponent = ExperimentalBlockEditorProvider, } ) => { + const [ loadedBlocks, setBlockLoaded ] = useReducer( + ( alreadyLoadedBlocks, blockType ) => [ + ...alreadyLoadedBlocks, + blockType, + ], + [] + ); + const asyncBlocks = getAsyncBlocks(); + + useEffect( () => { + asyncBlocks.forEach( async ( blockType ) => { + if ( loadedBlocks.includes( blockType ) ) { + return; + } + await asyncLoadBlock( blockType ); + setBlockLoaded( blockType ); + } ); + }, [] ); + const defaultBlockContext = useMemo( () => { if ( post.type === 'wp_template' ) { return {}; @@ -58,7 +83,8 @@ export const ExperimentalEditorProvider = withRegistryProvider( const [ blocks, onInput, onChange ] = useEntityBlockEditor( 'postType', type, - { id } + { id }, + loadedBlocks ); const blockEditorSettings = useBlockEditorSettings( editorSettings, From 78d64b07f03f069c2123b7ef871ff232b88af0c9 Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Thu, 23 Feb 2023 17:55:29 +0200 Subject: [PATCH 2/5] Manual dependency system; async load more blocks --- packages/block-library/src/index.js | 80 ++++++------------- packages/block-library/src/missing/edit.js | 2 +- .../editor/src/components/provider/index.js | 14 ++-- 3 files changed, 35 insertions(+), 61 deletions(-) diff --git a/packages/block-library/src/index.js b/packages/block-library/src/index.js index 47bd22b5ce1692..382d14ca40bbba 100644 --- a/packages/block-library/src/index.js +++ b/packages/block-library/src/index.js @@ -23,14 +23,10 @@ import { import * as archives from './archives'; import * as avatar from './avatar'; import * as audio from './audio'; -import * as button from './button'; -import * as buttons from './buttons'; import * as calendar from './calendar'; import * as categories from './categories'; import * as classic from './freeform'; import * as code from './code'; -import * as column from './column'; -import * as columns from './columns'; import * as comments from './comments'; import * as commentAuthorAvatar from './comment-author-avatar'; import * as commentAuthorName from './comment-author-name'; @@ -38,18 +34,12 @@ import * as commentContent from './comment-content'; import * as commentDate from './comment-date'; import * as commentEditLink from './comment-edit-link'; import * as commentReplyLink from './comment-reply-link'; -import * as commentTemplate from './comment-template'; -import * as commentsPaginationPrevious from './comments-pagination-previous'; -import * as commentsPagination from './comments-pagination'; -import * as commentsPaginationNext from './comments-pagination-next'; -import * as commentsPaginationNumbers from './comments-pagination-numbers'; import * as commentsTitle from './comments-title'; import * as cover from './cover'; import * as embed from './embed'; import * as file from './file'; import * as group from './group'; import * as heading from './heading'; -import * as homeLink from './home-link'; import * as html from './html'; import * as latestComments from './latest-comments'; import * as latestPosts from './latest-posts'; @@ -59,13 +49,7 @@ import * as logInOut from './loginout'; import * as mediaText from './media-text'; import * as missing from './missing'; import * as more from './more'; -import * as navigation from './navigation'; -import * as navigationLink from './navigation-link'; -import * as navigationSubmenu from './navigation-submenu'; -import * as nextpage from './nextpage'; import * as pattern from './pattern'; -import * as pageList from './page-list'; -import * as pageListItem from './page-list-item'; import * as paragraph from './paragraph'; import * as postAuthor from './post-author'; import * as postAuthorName from './post-author-name'; @@ -74,23 +58,15 @@ import * as postComment from './post-comment'; import * as postCommentsCount from './post-comments-count'; import * as postCommentsForm from './post-comments-form'; import * as postCommentsLink from './post-comments-link'; -import * as postContent from './post-content'; import * as postDate from './post-date'; import * as postExcerpt from './post-excerpt'; import * as postFeaturedImage from './post-featured-image'; import * as postNavigationLink from './post-navigation-link'; -import * as postTemplate from './post-template'; import * as postTerms from './post-terms'; import * as postTimeToRead from './post-time-to-read'; import * as postTitle from './post-title'; import * as preformatted from './preformatted'; import * as pullquote from './pullquote'; -import * as query from './query'; -import * as queryNoResults from './query-no-results'; -import * as queryPagination from './query-pagination'; -import * as queryPaginationNext from './query-pagination-next'; -import * as queryPaginationNumbers from './query-pagination-numbers'; -import * as queryPaginationPrevious from './query-pagination-previous'; import * as queryTitle from './query-title'; import * as quote from './quote'; import * as reusableBlock from './block'; @@ -102,8 +78,6 @@ import * as shortcode from './shortcode'; import * as siteLogo from './site-logo'; import * as siteTagline from './site-tagline'; import * as siteTitle from './site-title'; -import * as socialLink from './social-link'; -import * as socialLinks from './social-links'; import * as spacer from './spacer'; import * as table from './table'; import * as tableOfContents from './table-of-contents'; @@ -132,14 +106,10 @@ const getAllBlocks = () => // Register all remaining core blocks. archives, audio, - button, - buttons, calendar, categories, ...( window.wp && window.wp.oldEditor ? [ classic ] : [] ), // Only add the classic block in WP Context. code, - column, - columns, commentAuthorAvatar, cover, embed, @@ -151,9 +121,6 @@ const getAllBlocks = () => mediaText, missing, more, - nextpage, - pageList, - pageListItem, pattern, preformatted, pullquote, @@ -162,8 +129,6 @@ const getAllBlocks = () => search, separator, shortcode, - socialLink, - socialLinks, spacer, table, tagCloud, @@ -172,19 +137,14 @@ const getAllBlocks = () => video, // theme blocks - navigation, - navigationLink, - navigationSubmenu, siteLogo, siteTitle, siteTagline, - query, templatePart, avatar, postTitle, postExcerpt, postFeaturedImage, - postContent, postAuthor, postAuthorName, postComment, @@ -192,14 +152,8 @@ const getAllBlocks = () => postCommentsLink, postDate, postTerms, - postNavigationLink, - postTemplate, postTimeToRead, - queryPagination, - queryPaginationNext, - queryPaginationNumbers, - queryPaginationPrevious, - queryNoResults, + postNavigationLink, readMore, comments, commentAuthorName, @@ -207,22 +161,40 @@ const getAllBlocks = () => commentDate, commentEditLink, commentReplyLink, - commentTemplate, commentsTitle, - commentsPagination, - commentsPaginationNext, - commentsPaginationNumbers, - commentsPaginationPrevious, postCommentsForm, tableOfContents, - homeLink, logInOut, termDescription, queryTitle, postAuthorBiography, ].filter( Boolean ); -export const getAsyncBlocks = () => [ 'image', 'gallery' ].filter( Boolean ); +export const getAsyncBlocks = () => [ + [ 'button', 'buttons' ], + [ 'column', 'columns' ], + [ 'image', 'gallery' ], + [ + 'post-template', + 'query-pagination-previous', + 'query-pagination-numbers', + 'query-pagination-next', + 'query-pagination', + 'query-no-results', + 'query', + ], + [ + 'comments-pagination-previous', + 'comments-pagination-next', + 'comments-pagination-numbers', + 'comments-pagination', + 'comment-template', + ], + [ 'home-link', 'navigation-link', 'navigation-submenu', 'navigation' ], + [ 'page-list', 'page-list-item' ], + [ 'social-link', 'social-links' ], + [ 'nextpage', 'post-content' ], +]; export const asyncLoadBlock = async ( blockType ) => { const { init } = await import( './' + blockType + '/index.js' ); diff --git a/packages/block-library/src/missing/edit.js b/packages/block-library/src/missing/edit.js index 82d4741c1a0be2..37cb05aeec7b29 100644 --- a/packages/block-library/src/missing/edit.js +++ b/packages/block-library/src/missing/edit.js @@ -19,7 +19,7 @@ import { safeHTML } from '@wordpress/dom'; import { getAsyncBlocks } from '../../'; function MissingBlockWarning( { attributes, convertToHTML, clientId } ) { - const asyncBlocks = getAsyncBlocks(); + const asyncBlocks = [ ...new Set( getAsyncBlocks().flat() ) ]; const { originalName, originalUndelimitedContent } = attributes; const hasContent = !! originalUndelimitedContent; const hasHTMLBlock = useSelect( diff --git a/packages/editor/src/components/provider/index.js b/packages/editor/src/components/provider/index.js index 34b7cf64ae5bdf..4e7f8cfbe55a0f 100644 --- a/packages/editor/src/components/provider/index.js +++ b/packages/editor/src/components/provider/index.js @@ -49,12 +49,14 @@ export const ExperimentalEditorProvider = withRegistryProvider( const asyncBlocks = getAsyncBlocks(); useEffect( () => { - asyncBlocks.forEach( async ( blockType ) => { - if ( loadedBlocks.includes( blockType ) ) { - return; - } - await asyncLoadBlock( blockType ); - setBlockLoaded( blockType ); + asyncBlocks.forEach( ( blockGroup ) => { + blockGroup.forEach( async ( blockType ) => { + if ( loadedBlocks.includes( blockType ) ) { + return; + } + await asyncLoadBlock( blockType ); + setBlockLoaded( blockType ); + } ); } ); }, [] ); From 4bc5caf0cc70eaa2541f8076d7a0771fe430d992 Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Thu, 23 Feb 2023 18:09:41 +0200 Subject: [PATCH 3/5] Fix bad import --- packages/block-library/src/missing/edit.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-library/src/missing/edit.js b/packages/block-library/src/missing/edit.js index 37cb05aeec7b29..3c6501f8bec4ab 100644 --- a/packages/block-library/src/missing/edit.js +++ b/packages/block-library/src/missing/edit.js @@ -16,7 +16,7 @@ import { safeHTML } from '@wordpress/dom'; /** * Internal dependencies */ -import { getAsyncBlocks } from '../../'; +import { getAsyncBlocks } from '../'; function MissingBlockWarning( { attributes, convertToHTML, clientId } ) { const asyncBlocks = [ ...new Set( getAsyncBlocks().flat() ) ]; From 9ec0608ee14b77e3c19e0c9843916f9d7878d46f Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Tue, 28 Mar 2023 17:15:11 +0200 Subject: [PATCH 4/5] Fix asynchronousicity, re-parse after all blocks have loaded --- .../editor/src/components/provider/index.js | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/editor/src/components/provider/index.js b/packages/editor/src/components/provider/index.js index 4e7f8cfbe55a0f..fb495252fabb15 100644 --- a/packages/editor/src/components/provider/index.js +++ b/packages/editor/src/components/provider/index.js @@ -6,7 +6,7 @@ import { useEffect, useLayoutEffect, useMemo, - useReducer, + useState, } from '@wordpress/element'; import { useDispatch, useSelect } from '@wordpress/data'; import { __ } from '@wordpress/i18n'; @@ -39,25 +39,25 @@ export const ExperimentalEditorProvider = withRegistryProvider( children, BlockEditorProviderComponent = ExperimentalBlockEditorProvider, } ) => { - const [ loadedBlocks, setBlockLoaded ] = useReducer( - ( alreadyLoadedBlocks, blockType ) => [ - ...alreadyLoadedBlocks, - blockType, - ], - [] - ); + const [ blocksLoaded, setBlocksLoaded ] = useState( false ); const asyncBlocks = getAsyncBlocks(); useEffect( () => { + const blockPromises = []; asyncBlocks.forEach( ( blockGroup ) => { - blockGroup.forEach( async ( blockType ) => { - if ( loadedBlocks.includes( blockType ) ) { - return; - } - await asyncLoadBlock( blockType ); - setBlockLoaded( blockType ); + blockGroup.forEach( ( blockType ) => { + blockPromises.push( + new Promise( async ( resolve ) => { + await asyncLoadBlock( blockType ); + resolve(); + } ) + ); } ); } ); + + Promise.allSettled( blockPromises ).then( () => { + setBlocksLoaded( true ); + } ); }, [] ); const defaultBlockContext = useMemo( () => { @@ -86,7 +86,7 @@ export const ExperimentalEditorProvider = withRegistryProvider( 'postType', type, { id }, - loadedBlocks + blocksLoaded ); const blockEditorSettings = useBlockEditorSettings( editorSettings, From 57a019aff8cc3c8421e1af3d53c4bb43d7d535b0 Mon Sep 17 00:00:00 2001 From: Marin Atanasov <8436925+tyxla@users.noreply.github.com> Date: Wed, 29 Mar 2023 13:40:00 +0200 Subject: [PATCH 5/5] Import block type init directly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Greg Ziółkowski --- packages/block-library/src/index.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/block-library/src/index.js b/packages/block-library/src/index.js index 382d14ca40bbba..ddda7855bd13aa 100644 --- a/packages/block-library/src/index.js +++ b/packages/block-library/src/index.js @@ -197,8 +197,7 @@ export const getAsyncBlocks = () => [ ]; export const asyncLoadBlock = async ( blockType ) => { - const { init } = await import( './' + blockType + '/index.js' ); - init(); + await import( './' + blockType + '/init.js' ); }; /**