Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Gist of how I auto-load plugin and block code within a Gutenberg project.
const { blocks, plugins } = wp;
const { dispatch, select } = wp.data;
/**
* When a selected block is being disposed during a hot module reload, persist
* its clientId so it may be reselected after the new module version loads.
*
* If the block being unloaded is currently selected, clear that selection to
* avoid a Gutenberg error that occurs when unregistering a selected block.
*
* @param {String} name The name of the block being disposed.
*/
const getSelectedBlockClientId = name => {
const selectedBlock = select( 'core/editor' ).getSelectedBlock();
if ( ! selectedBlock || selectedBlock.name !== name ) {
// Do nothing if no block is selected, or if the selected block is not being reloaded.
return;
}
// The block being reloaded is currently selected: deselect it now.
dispatch( 'core/editor' ).clearSelectedBlock();
// Return the block's client ID.
return selectedBlock.clientId;
};
/**
* Block disposal helper, which persists the ID of the block being disposed if
* that block is currently selected.
*
* @param {String} name The name of the block being disposed.
* @param {Object} hot The module.hot instance from the module being disposed.
*/
export const unregisterBlockType = ( name, hot ) => {
if ( ! hot ) {
return;
}
hot.dispose( data => {
const clientId = getSelectedBlockClientId( name );
if ( clientId ) {
// Persist the client ID so that it may be reselected in registerBlock.
data.clientId = clientId;
}
blocks.unregisterBlockType( name );
} );
}
export const unregisterPlugin = ( name, hot ) => {
if ( ! hot ) {
return;
}
hot.dispose( () => {
plugins.unregisterPlugin( name );
} );
}
/**
* Block registration helper which wraps registerBlockType and contextually
* attemptes to reselect the re-registered block.
*
* @param {String} name The name of the block being registered.
* @param {Object} options The options object for the block being registered.
* @param {Object} hot The module.hot instance, if the calling module is being reloaded.
*/
export const registerBlockType = ( name, options, hot ) => {
blocks.registerBlockType( name, options );
if ( hot && hot.data && hot.data.clientId ) {
dispatch( 'core/editor' ).selectBlock( hot.data.clientId );
}
};
export const registerPlugin = ( name, options ) => {
plugins.registerPlugin( name, options );
};
/**
* Dynamically locate, load & register all Editor Blocks & Plugins.
*
* Entry point for the "editor.js" bundle.
*/
import {
registerBlockType,
registerPlugin,
unregisterBlockType,
unregisterPlugin,
} from './hmr-helpers';
/**
* Given the results of a require.context() call, require and register all those files.
*
* @param {Object} requireContext The results of running require.context().
* @param {Function} register The function to use to register this module upon module acceptance.
* @param {Function} unregister The function to use to unregister this module on module disposal.
*/
const autoRegister = ( requireContext, registerFn, unregisterFn ) => {
requireContext.keys().forEach( modulePath => {
const { name, options } = requireContext( modulePath );
if ( module.hot ) {
module.hot.accept();
// When accepting hot updates we must unregister blocks before re-registering them.
unregisterFn( name, module.hot );
}
registerFn( name, options, module.hot );
} );
};
// Load all block index files.
autoRegister(
require.context( `${ __dirname }/blocks`, true, /index\.js$/ ),
registerBlockType,
unregisterBlockType
);
// Load all plugin files.
autoRegister(
require.context( `${ __dirname }/plugins`, true, /index\.js$/ ),
registerPlugin,
unregisterPlugin
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.