diff --git a/packages/block-editor/src/components/block-list/index.js b/packages/block-editor/src/components/block-list/index.js index 7047e0163d5dc1..a3fbff7e185d6f 100644 --- a/packages/block-editor/src/components/block-list/index.js +++ b/packages/block-editor/src/components/block-list/index.js @@ -19,6 +19,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(); @@ -29,6 +30,7 @@ export default function BlockList( { className, __experimentalLayout } ) { const [ blockNodes, setBlockNodes ] = useState( {} ); const insertionPoint = useInsertionPoint( ref ); useScrollSelectionIntoView( ref ); + usePreParsePatterns(); return ( diff --git a/packages/block-editor/src/components/block-patterns-list/index.js b/packages/block-editor/src/components/block-patterns-list/index.js index 1601cbb728b57b..b3169619f0d70d 100644 --- a/packages/block-editor/src/components/block-patterns-list/index.js +++ b/packages/block-editor/src/components/block-patterns-list/index.js @@ -1,8 +1,6 @@ /** * WordPress dependencies */ -import { useMemo } from '@wordpress/element'; -import { parse } from '@wordpress/blocks'; import { VisuallyHidden, __unstableComposite as Composite, @@ -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 }`; diff --git a/packages/block-editor/src/components/block-preview/index.js b/packages/block-editor/src/components/block-preview/index.js index 1c293fc15a2ed6..dfec2f64fab284 100644 --- a/packages/block-editor/src/components/block-preview/index.js +++ b/packages/block-editor/src/components/block-preview/index.js @@ -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; diff --git a/packages/block-editor/src/store/selectors.js b/packages/block-editor/src/store/selectors.js index 1e6e1a2073ae3f..26e26773a7f2a9 100644 --- a/packages/block-editor/src/store/selectors.js +++ b/packages/block-editor/src/store/selectors.js @@ -15,7 +15,6 @@ import { filter, mapKeys, orderBy, - every, } from 'lodash'; import createSelector from 'rememo'; @@ -1757,13 +1756,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 ] ); @@ -1778,17 +1782,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; }, diff --git a/packages/block-editor/src/store/test/selectors.js b/packages/block-editor/src/store/test/selectors.js index 3d2e058dd844f6..afdca16a3cf22a 100644 --- a/packages/block-editor/src/store/test/selectors.js +++ b/packages/block-editor/src/store/test/selectors.js @@ -3375,10 +3375,12 @@ describe( 'selectors', () => { settings: { __experimentalBlockPatterns: [ { + name: 'pattern-a', title: 'pattern with a', content: ``, }, { + name: 'pattern-b', title: 'pattern with b', content: '', @@ -3409,10 +3411,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' ] }, }, diff --git a/packages/block-editor/src/utils/pre-parse-patterns.js b/packages/block-editor/src/utils/pre-parse-patterns.js new file mode 100644 index 00000000000000..c5e1d5ad41ac59 --- /dev/null +++ b/packages/block-editor/src/utils/pre-parse-patterns.js @@ -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; +} diff --git a/packages/edit-post/src/editor.js b/packages/edit-post/src/editor.js index 11a82a1e899d34..89c0e8efae5c6c 100644 --- a/packages/edit-post/src/editor.js +++ b/packages/edit-post/src/editor.js @@ -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' ) || diff --git a/packages/edit-site/src/components/editor/index.js b/packages/edit-site/src/components/editor/index.js index eff877009255f2..c305ca824236ca 100644 --- a/packages/edit-site/src/components/editor/index.js +++ b/packages/edit-site/src/components/editor/index.js @@ -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(),