Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Try: Simple async block loading #48315

Draft
wants to merge 5 commits into
base: trunk
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions packages/block-library/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ _This package assumes that your code will run in an **ES2015+** environment. If

<!-- START TOKEN(Autogenerated API docs) -->

### asyncLoadBlock

Undocumented declaration.

### getAsyncBlocks

Undocumented declaration.

### registerCoreBlocks

Function to register core blocks provided by the block editor.
Expand Down
88 changes: 31 additions & 57 deletions packages/block-library/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,36 +23,24 @@ 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';
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 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';
Expand All @@ -61,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';
Expand All @@ -76,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';
Expand All @@ -104,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';
Expand All @@ -126,24 +98,18 @@ 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,

// 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,
Expand All @@ -155,9 +121,6 @@ const getAllBlocks = () =>
mediaText,
missing,
more,
nextpage,
pageList,
pageListItem,
pattern,
preformatted,
pullquote,
Expand All @@ -166,8 +129,6 @@ const getAllBlocks = () =>
search,
separator,
shortcode,
socialLink,
socialLinks,
spacer,
table,
tagCloud,
Expand All @@ -176,56 +137,69 @@ const getAllBlocks = () =>
video,

// theme blocks
navigation,
navigationLink,
navigationSubmenu,
siteLogo,
siteTitle,
siteTagline,
query,
templatePart,
avatar,
postTitle,
postExcerpt,
postFeaturedImage,
postContent,
postAuthor,
postAuthorName,
postComment,
postCommentsCount,
postCommentsLink,
postDate,
postTerms,
postNavigationLink,
postTemplate,
postTimeToRead,
queryPagination,
queryPaginationNext,
queryPaginationNumbers,
queryPaginationPrevious,
queryNoResults,
postNavigationLink,
readMore,
comments,
commentAuthorName,
commentContent,
commentDate,
commentEditLink,
commentReplyLink,
commentTemplate,
commentsTitle,
commentsPagination,
commentsPaginationNext,
commentsPaginationNumbers,
commentsPaginationPrevious,
postCommentsForm,
tableOfContents,
homeLink,
logInOut,
termDescription,
queryTitle,
postAuthorBiography,
].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 ) => {
await import( './' + blockType + '/init.js' );
};

/**
* Function to get all the core blocks in an array.
*
Expand Down
14 changes: 13 additions & 1 deletion packages/block-library/src/missing/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [ ...new Set( getAsyncBlocks().flat() ) ];
const { originalName, originalUndelimitedContent } = attributes;
const hasContent = !! originalUndelimitedContent;
const hasHTMLBlock = useSelect(
Expand All @@ -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 */
__(
Expand Down
14 changes: 10 additions & 4 deletions packages/core-data/src/entity-provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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,
Expand All @@ -182,7 +188,7 @@ export function useEntityBlockEditor( kind, name, { id: _id } = {} ) {
{ undoIgnore: true }
);
}
}, [ content ] );
}, [ content, parseDeps ] );

const onChange = useCallback(
( newBlocks, options ) => {
Expand Down
1 change: 1 addition & 0 deletions packages/editor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
32 changes: 30 additions & 2 deletions packages/editor/src/components/provider/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
/**
* WordPress dependencies
*/
import { useEffect, useLayoutEffect, useMemo } from '@wordpress/element';
import { asyncLoadBlock, getAsyncBlocks } from '@wordpress/block-library';
import {
useEffect,
useLayoutEffect,
useMemo,
useState,
} from '@wordpress/element';
import { useDispatch, useSelect } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
import { EntityProvider, useEntityBlockEditor } from '@wordpress/core-data';
Expand Down Expand Up @@ -33,6 +39,27 @@ export const ExperimentalEditorProvider = withRegistryProvider(
children,
BlockEditorProviderComponent = ExperimentalBlockEditorProvider,
} ) => {
const [ blocksLoaded, setBlocksLoaded ] = useState( false );
const asyncBlocks = getAsyncBlocks();

useEffect( () => {
const blockPromises = [];
asyncBlocks.forEach( ( blockGroup ) => {
blockGroup.forEach( ( blockType ) => {
blockPromises.push(
new Promise( async ( resolve ) => {
await asyncLoadBlock( blockType );
resolve();
} )
);
} );
} );

Promise.allSettled( blockPromises ).then( () => {
setBlocksLoaded( true );
} );
}, [] );

const defaultBlockContext = useMemo( () => {
if ( post.type === 'wp_template' ) {
return {};
Expand All @@ -58,7 +85,8 @@ export const ExperimentalEditorProvider = withRegistryProvider(
const [ blocks, onInput, onChange ] = useEntityBlockEditor(
'postType',
type,
{ id }
{ id },
blocksLoaded
);
const blockEditorSettings = useBlockEditorSettings(
editorSettings,
Expand Down