Skip to content

Commit

Permalink
Enable concurrent mode by using createRoot to mount editor apps
Browse files Browse the repository at this point in the history
  • Loading branch information
jsnajdr committed Jan 30, 2023
1 parent e1c2fef commit 539d35f
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 152 deletions.
12 changes: 1 addition & 11 deletions packages/edit-post/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -478,17 +478,7 @@ _Returns_

### reinitializeEditor

Reinitializes the editor after the user chooses to reboot the editor after
an unhandled error occurs, replacing previously mounted editor element using
an initial state from prior to the crash.

_Parameters_

- _postType_ `Object`: Post type of the post to edit.
- _postId_ `Object`: ID of the post to edit.
- _target_ `Element`: DOM node in which editor is rendered.
- _settings_ `?Object`: Editor settings object.
- _initialEdits_ `Object`: Programmatic edits to apply initially, to be considered as non-user-initiated (bypass for unsaved changes prompt).
Used to reinitialize the editor after an error. Now it's a deprecated noop function.

### store

Expand Down
73 changes: 17 additions & 56 deletions packages/edit-post/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import {
registerCoreBlocks,
__experimentalRegisterExperimentalCoreBlocks,
} from '@wordpress/block-library';
import { render, unmountComponentAtNode } from '@wordpress/element';
import deprecated from '@wordpress/deprecated';
import { createRoot } from '@wordpress/element';
import { dispatch, select } from '@wordpress/data';
import { addFilter } from '@wordpress/hooks';
import { store as preferencesStore } from '@wordpress/preferences';
Expand All @@ -20,49 +21,6 @@ import './plugins';
import Editor from './editor';
import { store as editPostStore } from './store';

/**
* Reinitializes the editor after the user chooses to reboot the editor after
* an unhandled error occurs, replacing previously mounted editor element using
* an initial state from prior to the crash.
*
* @param {Object} postType Post type of the post to edit.
* @param {Object} postId ID of the post to edit.
* @param {Element} target DOM node in which editor is rendered.
* @param {?Object} settings Editor settings object.
* @param {Object} initialEdits Programmatic edits to apply initially, to be
* considered as non-user-initiated (bypass for
* unsaved changes prompt).
*/
export function reinitializeEditor(
postType,
postId,
target,
settings,
initialEdits
) {
unmountComponentAtNode( target );
const reboot = reinitializeEditor.bind(
null,
postType,
postId,
target,
settings,
initialEdits
);

render(
<Editor
settings={ settings }
onError={ reboot }
postId={ postId }
postType={ postType }
initialEdits={ initialEdits }
recovery
/>,
target
);
}

/**
* Initializes and returns an instance of Editor.
*
Expand All @@ -82,14 +40,7 @@ export function initializeEditor(
initialEdits
) {
const target = document.getElementById( id );
const reboot = reinitializeEditor.bind(
null,
postType,
postId,
target,
settings,
initialEdits
);
const root = createRoot( target );

dispatch( preferencesStore ).setDefaults( 'core/edit-post', {
editorMode: 'visual',
Expand Down Expand Up @@ -187,16 +138,26 @@ export function initializeEditor(
window.addEventListener( 'dragover', ( e ) => e.preventDefault(), false );
window.addEventListener( 'drop', ( e ) => e.preventDefault(), false );

render(
root.render(
<Editor
settings={ settings }
onError={ reboot }
postId={ postId }
postType={ postType }
initialEdits={ initialEdits }
/>,
target
/>
);

return root;
}

/**
* Used to reinitialize the editor after an error. Now it's a deprecated noop function.
*/
export function reinitializeEditor() {
deprecated( 'wp.editPost.reinitializeEditor', {
since: '6.2',
version: '6.3',
} );
}

export { default as PluginBlockSettingsMenuItem } from './components/block-settings-menu/plugin-block-settings-menu-item';
Expand Down
4 changes: 2 additions & 2 deletions packages/edit-site/src/components/app/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { PluginArea } from '@wordpress/plugins';
import { Routes } from '../routes';
import Layout from '../layout';

export default function App( { reboot } ) {
export default function App( { onError } ) {
const { createErrorNotice } = useDispatch( noticesStore );

function onPluginAreaError( name ) {
Expand All @@ -37,7 +37,7 @@ export default function App( { reboot } ) {
<UnsavedChangesWarning />

<Routes>
<Layout onError={ reboot } />
<Layout onError={ onError } />
<PluginArea onError={ onPluginAreaError } />
</Routes>
</SlotFillProvider>
Expand Down
110 changes: 51 additions & 59 deletions packages/edit-site/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import {
__experimentalRegisterExperimentalCoreBlocks,
} from '@wordpress/block-library';
import { dispatch } from '@wordpress/data';
import { render, unmountComponentAtNode } from '@wordpress/element';
import deprecated from '@wordpress/deprecated';
import { createRoot } from '@wordpress/element';
import {
__experimentalFetchLinkSuggestions as fetchLinkSuggestions,
__experimentalFetchUrlData as fetchUrlData,
Expand All @@ -26,14 +27,27 @@ import { store as editSiteStore } from './store';
import App from './components/app';

/**
* Reinitializes the editor after the user chooses to reboot the editor after
* an unhandled error occurs, replacing previously mounted editor element using
* an initial state from prior to the crash.
* Initializes the site editor screen.
*
* @param {Element} target DOM node in which editor is rendered.
* @param {?Object} settings Editor settings object.
* @param {string} id ID of the root element to render the screen in.
* @param {Object} settings Editor settings.
*/
export function reinitializeEditor( target, settings ) {
export function initializeEditor( id, settings ) {
const target = document.getElementById( id );
const root = createRoot( target );

settings.__experimentalFetchLinkSuggestions = ( search, searchOptions ) =>
fetchLinkSuggestions( search, searchOptions, settings );
settings.__experimentalFetchRichUrlData = fetchUrlData;

dispatch( blocksStore ).__experimentalReapplyBlockTypeFilters();
registerCoreBlocks();
registerLegacyWidgetBlock( { inserter: false } );
if ( process.env.IS_GUTENBERG_PLUGIN ) {
__experimentalRegisterExperimentalCoreBlocks( {
enableFSEBlocks: true,
} );
}
/*
* Prevent adding the Clasic block in the site editor.
* Only add the filter when the site editor is initialized, not imported.
Expand All @@ -54,70 +68,48 @@ export function reinitializeEditor( target, settings ) {
}
);

// This will be a no-op if the target doesn't have any React nodes.
unmountComponentAtNode( target );
const reboot = reinitializeEditor.bind( null, target, settings );

// We dispatch actions and update the store synchronously before rendering
// so that we won't trigger unnecessary re-renders with useEffect.
{
dispatch( preferencesStore ).setDefaults( 'core/edit-site', {
editorMode: 'visual',
fixedToolbar: false,
focusMode: false,
keepCaretInsideBlock: false,
welcomeGuide: true,
welcomeGuideStyles: true,
showListViewByDefault: false,
} );
dispatch( preferencesStore ).setDefaults( 'core/edit-site', {
editorMode: 'visual',
fixedToolbar: false,
focusMode: false,
keepCaretInsideBlock: false,
welcomeGuide: true,
welcomeGuideStyles: true,
showListViewByDefault: false,
} );

dispatch( interfaceStore ).setDefaultComplementaryArea(
'core/edit-site',
'edit-site/template'
);
dispatch( interfaceStore ).setDefaultComplementaryArea(
'core/edit-site',
'edit-site/template'
);

dispatch( editSiteStore ).updateSettings( settings );
dispatch( editSiteStore ).updateSettings( settings );

// Keep the defaultTemplateTypes in the core/editor settings too,
// so that they can be selected with core/editor selectors in any editor.
// This is needed because edit-site doesn't initialize with EditorProvider,
// which internally uses updateEditorSettings as well.
dispatch( editorStore ).updateEditorSettings( {
defaultTemplateTypes: settings.defaultTemplateTypes,
defaultTemplatePartAreas: settings.defaultTemplatePartAreas,
} );
}
// Keep the defaultTemplateTypes in the core/editor settings too,
// so that they can be selected with core/editor selectors in any editor.
// This is needed because edit-site doesn't initialize with EditorProvider,
// which internally uses updateEditorSettings as well.
dispatch( editorStore ).updateEditorSettings( {
defaultTemplateTypes: settings.defaultTemplateTypes,
defaultTemplatePartAreas: settings.defaultTemplatePartAreas,
} );

// Prevent the default browser action for files dropped outside of dropzones.
window.addEventListener( 'dragover', ( e ) => e.preventDefault(), false );
window.addEventListener( 'drop', ( e ) => e.preventDefault(), false );

render( <App reboot={ reboot } />, target );
}

/**
* Initializes the site editor screen.
*
* @param {string} id ID of the root element to render the screen in.
* @param {Object} settings Editor settings.
*/
export function initializeEditor( id, settings ) {
settings.__experimentalFetchLinkSuggestions = ( search, searchOptions ) =>
fetchLinkSuggestions( search, searchOptions, settings );
settings.__experimentalFetchRichUrlData = fetchUrlData;
root.render( <App /> );

const target = document.getElementById( id );

dispatch( blocksStore ).__experimentalReapplyBlockTypeFilters();
registerCoreBlocks();
registerLegacyWidgetBlock( { inserter: false } );
if ( process.env.IS_GUTENBERG_PLUGIN ) {
__experimentalRegisterExperimentalCoreBlocks( {
enableFSEBlocks: true,
} );
}
return root;
}

reinitializeEditor( target, settings );
export function reinitializeEditor() {
deprecated( 'wp.editSite.reinitializeEditor', {
since: '6.2',
version: '6.3',
} );
}

export { default as PluginSidebar } from './components/sidebar-edit-mode/plugin-sidebar';
Expand Down
45 changes: 21 additions & 24 deletions packages/edit-widgets/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import {
store as blocksStore,
} from '@wordpress/blocks';
import { dispatch } from '@wordpress/data';
import { render, unmountComponentAtNode } from '@wordpress/element';
import deprecated from '@wordpress/deprecated';
import { createRoot } from '@wordpress/element';
import {
registerCoreBlocks,
__experimentalGetCoreBlocks,
Expand Down Expand Up @@ -42,32 +43,16 @@ const disabledBlocks = [
...( ALLOW_REUSABLE_BLOCKS ? [] : [ 'core/block' ] ),
];

/**
* Reinitializes the editor after the user chooses to reboot the editor after
* an unhandled error occurs, replacing previously mounted editor element using
* an initial state from prior to the crash.
*
* @param {Element} target DOM node in which editor is rendered.
* @param {?Object} settings Editor settings object.
*/
export function reinitializeEditor( target, settings ) {
unmountComponentAtNode( target );
const reboot = reinitializeEditor.bind( null, target, settings );
render(
<Layout blockEditorSettings={ settings } onError={ reboot } />,
target
);
}

/**
* Initializes the block editor in the widgets screen.
*
* @param {string} id ID of the root element to render the screen in.
* @param {Object} settings Block editor settings.
*/
export function initialize( id, settings ) {
export function initializeEditor( id, settings ) {
const target = document.getElementById( id );
const reboot = reinitializeEditor.bind( null, target, settings );
const root = createRoot( target );

const coreBlocks = __experimentalGetCoreBlocks().filter( ( block ) => {
return ! (
disabledBlocks.includes( block.name ) ||
Expand Down Expand Up @@ -105,10 +90,22 @@ export function initialize( id, settings ) {
// do this will result in errors in the default block parser.
// see: https://github.com/WordPress/gutenberg/issues/33097
setFreeformContentHandlerName( 'core/html' );
render(
<Layout blockEditorSettings={ settings } onError={ reboot } />,
target
);

root.render( <Layout blockEditorSettings={ settings } /> );

return root;
}

/**
* Compatibility export under the old `initialize` name.
*/
export const initialize = initializeEditor;

export function reinitializeEditor() {
deprecated( 'wp.editWidgets.reinitializeEditor', {
since: '6.2',
version: '6.3',
} );
}

/**
Expand Down

0 comments on commit 539d35f

Please sign in to comment.