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

Release v1.0 targeting wp-scripts single-block builds? #13

Open
kadamwhite opened this issue Mar 6, 2024 · 0 comments
Open

Release v1.0 targeting wp-scripts single-block builds? #13

kadamwhite opened this issue Mar 6, 2024 · 0 comments

Comments

@kadamwhite
Copy link
Owner

Compared to the v0 line, in a wp-scripts build each block should be its own bundle. We can accomplish hot reloading with a wp-scripts start --hot build by adding this code to the block index.js file (see // Block HMR boilerplate comment and below):

import { registerBlockType } from '@wordpress/blocks';
import metadata from './block.json';
import Edit from './edit.js';

registerBlockType( metadata.name, {
	...metadata,
	edit: Edit,
} );

// Block HMR boilerplate.
if ( module.hot ) {
	module.hot.accept();
	const { deregister, refresh } = require( '../../helpers/hot-blocks.js' );
	module.hot.dispose( deregister( metadata.name ) );
	refresh( metadata.name, module.hot.data );
}

the implementation of this hot-blocks module in our test project looks like this:

/**
 * Provide helper methods to dynamically reload & reregister blocks in hot-
 * reloading contexts. Inspired by "block-editor-hmr" NPM package.
 */
import { unregisterBlockType } from '@wordpress/blocks';
import { dispatch, select } from '@wordpress/data';

/**
 * Deregister a block that's being hot-swapped out, so that the updated version
 * can be registered afresh without "block already registered" errors.
 *
 * Also keeps track of the selected block client ID, which is needed because
 * we have to deselect a block before unregistering it to swap without error.
 * The active block will be reselected in the refresh function.
 *
 * @param {string} hotBlockName Name of block being hot-reloaded.
 */
export const deregister = ( hotBlockName ) => ( data ) => {
	unregisterBlockType( hotBlockName );

	const selectedBlockId =
		select( 'core/block-editor' ).getSelectedBlockClientId();

	if ( selectedBlockId ) {
		dispatch( 'core/block-editor' ).clearSelectedBlock();
	}

	// Pass selected ID through hot-reload cycle.
	data.value = selectedBlockId;
};

/**
 * Process an updated block module, refreshing the editor view as needed.
 *
 * @param {string}           hotBlockName Name of block being hot-reloaded.
 * @param {{value?: string}} [data]       module.hot.data object, if present.
 */
export const refresh = ( hotBlockName, data ) => {
	// Refresh all copies of our changed block by iteratively selecting them.
	select( 'core/block-editor' )
		.getBlocks()
		.forEach( ( { name, clientId } ) => {
			if ( name === hotBlockName ) {
				dispatch( 'core/block-editor' ).selectBlock( clientId );
			}
		} );

	// Reselect whatever block was selected in the beginning.
	if ( data?.value ) {
		// Reselect within a timeout to allow other hot-reloaded blocks to finish
		// processing before changing focus.
		setTimeout( () => {
			dispatch( 'core/block-editor' ).selectBlock( data.value );
		} );
	}
};

This adapts our existing logic but lets it work efficiently in the context of a single block, and a world where WP Scripts does the directory scanning for us. I think this would be less overhead to maintain going forward, though it does require additional testing on different types of block and different selection states.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant