Skip to content

Commit

Permalink
Parsing patterns when idling (performance follow-up for inserting pat…
Browse files Browse the repository at this point in the history
…terns into containers) (#29444)

We need to parse all the patterns to determine whether a pattern can be inserted into the selected destination. We parse them immediately when the editor loads which freezes the editor until the parser finishes. To avoid the thread blocking, this PR changes it to only parse when we have resources to do so.
  • Loading branch information
david-szabo97 authored Mar 24, 2021
1 parent aad0052 commit 94db813
Show file tree
Hide file tree
Showing 8 changed files with 102 additions and 25 deletions.
2 changes: 2 additions & 0 deletions packages/block-editor/src/components/block-list/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import useInsertionPoint from './insertion-point';
import BlockPopover from './block-popover';
import { store as blockEditorStore } from '../../store';
import { useScrollSelectionIntoView } from '../selection-scroll-into-view';
import { usePreParsePatterns } from '../../utils/pre-parse-patterns';
import { LayoutProvider, defaultLayout } from './layout';

export const BlockNodes = createContext();
Expand All @@ -30,6 +31,7 @@ export default function BlockList( { className, __experimentalLayout } ) {
const [ blockNodes, setBlockNodes ] = useState( {} );
const insertionPoint = useInsertionPoint( ref );
useScrollSelectionIntoView( ref );
usePreParsePatterns();

const isLargeViewport = useViewportMatch( 'medium' );
const {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
/**
* WordPress dependencies
*/
import { useMemo } from '@wordpress/element';
import { parse } from '@wordpress/blocks';
import {
VisuallyHidden,
__unstableComposite as Composite,
Expand All @@ -11,16 +9,22 @@ import {
} from '@wordpress/components';
import { useInstanceId } from '@wordpress/compose';
import { __ } from '@wordpress/i18n';
import { useSelect } from '@wordpress/data';

/**
* Internal dependencies
*/
import BlockPreview from '../block-preview';
import InserterDraggableBlocks from '../inserter-draggable-blocks';
import { store as blockEditorStore } from '../../store';

function BlockPattern( { isDraggable, pattern, onClick, composite } ) {
const { content, viewportWidth } = pattern;
const blocks = useMemo( () => parse( content ), [ content ] );
const { name, viewportWidth } = pattern;
const { blocks } = useSelect(
( select ) =>
select( blockEditorStore ).__experimentalGetParsedPattern( name ),
[ name ]
);
const instanceId = useInstanceId( BlockPattern );
const descriptionId = `block-editor-block-patterns-list__item-description-${ instanceId }`;

Expand Down
7 changes: 6 additions & 1 deletion packages/block-editor/src/components/block-preview/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,15 @@ export function BlockPreview( {
__experimentalLive = false,
__experimentalOnClick,
} ) {
const settings = useSelect(
const originalSettings = useSelect(
( select ) => select( blockEditorStore ).getSettings(),
[]
);
const settings = useMemo( () => {
const _settings = { ...originalSettings };
_settings.__experimentalBlockPatterns = [];
return _settings;
}, [ originalSettings ] );
const renderedBlocks = useMemo( () => castArray( blocks ), [ blocks ] );
if ( ! blocks || blocks.length === 0 ) {
return null;
Expand Down
30 changes: 18 additions & 12 deletions packages/block-editor/src/store/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import {
filter,
mapKeys,
orderBy,
every,
} from 'lodash';
import createSelector from 'rememo';

Expand Down Expand Up @@ -1792,13 +1791,18 @@ export const __experimentalGetAllowedBlocks = createSelector(
]
);

const __experimentalGetParsedPatterns = createSelector(
( state ) => {
export const __experimentalGetParsedPattern = createSelector(
( state, patternName ) => {
const patterns = state.settings.__experimentalBlockPatterns;
return map( patterns, ( pattern ) => ( {
const pattern = patterns.find( ( { name } ) => name === patternName );
if ( ! pattern ) {
return null;
}

return {
...pattern,
contentBlocks: parse( pattern.content ),
} ) );
blocks: parse( pattern.content ),
};
},
( state ) => [ state.settings.__experimentalBlockPatterns ]
);
Expand All @@ -1813,17 +1817,19 @@ const __experimentalGetParsedPatterns = createSelector(
*/
export const __experimentalGetAllowedPatterns = createSelector(
( state, rootClientId = null ) => {
const patterns = __experimentalGetParsedPatterns( state );

const patterns = state.settings.__experimentalBlockPatterns;
if ( ! rootClientId ) {
return patterns;
}

const patternsAllowed = filter( patterns, ( { contentBlocks } ) => {
return every( contentBlocks, ( { name } ) =>
const parsedPatterns = patterns.map( ( { name } ) =>
__experimentalGetParsedPattern( state, name )
);
const patternsAllowed = filter( parsedPatterns, ( { blocks } ) =>
blocks.every( ( { name } ) =>
canInsertBlockType( state, name, rootClientId )
);
} );
)
);

return patternsAllowed;
},
Expand Down
4 changes: 4 additions & 0 deletions packages/block-editor/src/store/test/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -3377,10 +3377,12 @@ describe( 'selectors', () => {
settings: {
__experimentalBlockPatterns: [
{
name: 'pattern-a',
title: 'pattern with a',
content: `<!-- wp:test-block-a --><!-- /wp:test-block-a -->`,
},
{
name: 'pattern-b',
title: 'pattern with b',
content:
'<!-- wp:test-block-b --><!-- /wp:test-block-b -->',
Expand Down Expand Up @@ -3411,10 +3413,12 @@ describe( 'selectors', () => {
settings: {
__experimentalBlockPatterns: [
{
name: 'pattern-a',
title: 'pattern a',
scope: { block: [ 'test/block-a' ] },
},
{
name: 'pattern-b',
title: 'pattern b',
scope: { block: [ 'test/block-b' ] },
},
Expand Down
64 changes: 64 additions & 0 deletions packages/block-editor/src/utils/pre-parse-patterns.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* WordPress dependencies
*/
import { useSelect, select } from '@wordpress/data';
import { useEffect } from '@wordpress/element';

/**
* Internal dependencies
*/
import { store as blockEditorStore } from '../store';

const requestIdleCallback = ( () => {
if ( typeof window === 'undefined' ) {
return ( callback ) => {
setTimeout( () => callback( Date.now() ), 0 );
};
}

return window.requestIdleCallback || window.requestAnimationFrame;
} )();

const cancelIdleCallback = ( () => {
if ( typeof window === 'undefined' ) {
return clearTimeout;
}

return window.cancelIdleCallback || window.cancelAnimationFrame;
} )();

export function usePreParsePatterns() {
const patterns = useSelect(
( _select ) =>
_select( blockEditorStore ).getSettings()
.__experimentalBlockPatterns,
[]
);

useEffect( () => {
if ( ! patterns?.length ) {
return;
}

let handle;
let index = -1;

const callback = () => {
index++;
if ( index >= patterns.length ) {
return;
}

select( blockEditorStore ).__experimentalGetParsedPattern(
patterns[ index ].name
);

handle = requestIdleCallback( callback );
};

handle = requestIdleCallback( callback );
return () => cancelIdleCallback( handle );
}, [ patterns ] );

return null;
}
4 changes: 0 additions & 4 deletions packages/edit-post/src/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,6 @@ function Editor( {
const isFSETheme = getEditorSettings().isFSETheme;
const isViewable = getPostType( postType )?.viewable ?? false;

// Prefetch and parse patterns. This ensures patterns are loaded and parsed when
// the editor is loaded rather than degrading the performance of the inserter.
select( 'core/block-editor' ).__experimentalGetAllowedPatterns();

return {
hasFixedToolbar:
isFeatureActive( 'fixedToolbar' ) ||
Expand Down
4 changes: 0 additions & 4 deletions packages/edit-site/src/components/editor/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,6 @@ function Editor( { initialSettings } ) {
const postType = getEditedPostType();
const postId = getEditedPostId();

// Prefetch and parse patterns. This ensures patterns are loaded and parsed when
// the editor is loaded rather than degrading the performance of the inserter.
select( 'core/block-editor' ).__experimentalGetAllowedPatterns();

// The currently selected entity to display. Typically template or template part.
return {
isInserterOpen: isInserterOpened(),
Expand Down

0 comments on commit 94db813

Please sign in to comment.