-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
Blocks: Defer registration of all core blocks until editor loads #4514
Conversation
@@ -23,8 +24,7 @@ describe( 'raw handling: integration', () => { | |||
beforeAll( () => { | |||
// Load all hooks that modify blocks | |||
require( 'blocks/hooks' ); | |||
// Load all blocks | |||
require( 'blocks/library' ); | |||
registerAllBlocks(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this all blocks or just the core library of blocks?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Core blocks. I guess registerCoreBlocks()
is the way to go then. I had it typed once, but reverted to all
keyword :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
blocks/library/audio/index.js
Outdated
@@ -20,7 +20,7 @@ import Editable from '../../editable'; | |||
import BlockControls from '../../block-controls'; | |||
import BlockAlignmentToolbar from '../../block-alignment-toolbar'; | |||
|
|||
registerBlockType( 'core/audio', { | |||
export const registerAudioBlock = () => registerBlockType( 'core/audio', { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems very verbose.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
export default () => registerBlockType( 'core/audio', {
is another way to go.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Either that or
export const Audio = () => registerBlockType( 'core/audio', {} );
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about exporting the name and the settings and loop over the blocks and call registerBlockType
when needed? I think we explored this possibility at some point can't recall why we dismissed it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@youknowriad can you give an example? How would it work with embeds file which contains dozen definitions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
import * as audio from 'audio';
import embeds from 'embed';
const blockConfigs = [
audio,
...embeds
];
blockConfigs.forEach( ( { name, settings } ) => registerBlockType( name, settings ) );
The embeds woud export an array [{ name, settings }]
, while the others would export { name, settings }
. I don't know if this is a good option though.
I guess the main advantage of this approach is the possibility to test the settings without registering the blocks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2c00ffc - I like name
& settings
pair. It gives us more flexibility when testing code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes me wonder if name
and settings
need to be separate at all, e.g.
export default {
name: 'core/foo',
// ...settings
};
We could overload registerBlockType
to support both this and the current implementation.
Thinking back to some of the original reasons for the API as it stands:
- Compatibility with similar APIs like
register_post_type
andregister_rest_route
† - More easy to identify name at a glance (also enforcing as first, which is not true as an object property)
To such API design generally, the string, object
argument signature seems best-suited in cases where the object contains properties none of which are necessarily required. An ordered set of arguments is good when all arguments are required and the set is limited in size (since otherwise the ordering loses its obviousness on what each value represents).
Here, it's a bit of an awkward mismatch. The name is required, but so are some of the options (e.g. save
). Conversely, not all block properties are required (e.g. supports
). To me, other APIs notwithstanding, the single object argument seems the most sensible.
</braindump>
† But this could serve as a counterpoint, since unlike in register_rest_route
, we don't separate the namespace and block name arguments.
2c00ffc
to
8fd0049
Compare
@youknowriad I'm refactoring towards your proposal. I will continue tomorrow. I think it looks nice. The diff will remain big because of the embeds file. |
ba8a385
to
c108c9b
Compare
This is ready for another review. I think it's solid now. |
editor/index.js
Outdated
@@ -22,6 +23,8 @@ import { initializeMetaBoxState } from './store/actions'; | |||
export * from './components'; | |||
import store from './store'; // Registers the state tree | |||
|
|||
registerCoreBlocks(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should move this inside the "initialize" function since we do not support multiple instances anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Happy to move it there. I wasn't sure what is the best place to put it :)
In the long run, we could mirror what WP core uses and introduce some global hooks like init
to take advantage of the priority
param and be sure that registerCoreBlocks
is always called last after all other hooks coming from the plugins are registered.
|
||
setDefaultBlockName( paragraph.name ); | ||
setUnknownTypeHandlerName( freeform.name ); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this personally, I think it clarifies the config of the editor's block by centralizing them.
I'm not certain this solves all the "deferring issues" but it makes it clear when this initialization is happening (where this function is being called).
I'd also be open to refactor registerBlockType
to move the name as part of the settings object like suggested by @aduth . But this could be a separate PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I also like what @aduth proposed, but this might be too much for this PR. It's already big enough and we would have to update all docs to reflect this relatively small change. We would also have to promote it over the current API which can be found in a few example repositories, blog posts, online courses, etc :)
c108c9b
to
a9c1839
Compare
This looks good to me. Seems like a nice starting point for a number of subsequent improvements, as already mentioned: combining blocktype name and settings, tweaking consumable hooks, etc. |
@mcsf righto, I see a lot of possibilities for improvements & customization that can happen in user land if Gutenberg gets all of this stuff right. Also, not requiring plugin JavaScript to be loaded at a certain time in editor lifecycle is a big win. Plugins will be able to do conditional code splitting, lazy loading of their customizations & other awesome stuff. |
I think it's in good shape to merge it as it is. Let's iterate further on this in the follow-up PRs. Thanks for all reviews everyone 🙇 |
This commit is towards rendering a front end preview for shortcode blocks. The shortcode block now implements a tabbed preview option, similar to HTML blocks. The user can edit their shortcodes, and previewing again will re-render the edited shortcode. Works for embed shortcodes too. Known issues - (1) playlist shortcode doesn't work (2) the iframe height/width in the preview tab needs to wrap content size. For example, the iframe is too big when previewing an audio player using audio shortcode (3) gallery shortcode preview stacks the images vertically instead of horizontally (4) video shortcode doesn't work for URLs supported by oembed
This broke shortcode paste (e.g. caption). The order of block registration is important for that. See #3610 (comment). Cc @mcsf @aduth @jorgefilipecosta. |
It's easy to reorder this manually, but is there any way we could make the registration of blocks independent from the paste functionality? |
IMHO we should remove the block. It seems odd to just match any shortcode. Falling back to text seems fine if there is no handling in my opinion... It also breaks inline shortcodes. |
The problem with falling back to text is that we break parameter handling in shortcodes. Per #3610:
Inline shortcodes are also affected by this, and obviously requiring usage of the Shortcode block is not a long-term solution; #4049, on the other hand, is. I'm fine with simply reverting #3610, but it'd be interesting to look at priority-based registration of blocks. |
Correct me if I'm wrong, but could we solve the original issue simply by extracting core block registration separate from the block API bundle? As part of #2751, I'd like to create individual bundles for each core block (related: #2756, #4500 (comment)), meaning we could revert to the original behavior while still addressing the challenge noted in #3800. This would also avoid those individual bundles needing to expose anything to the global namespace (and having a As noted in #4097, there's an open question as to whether the relationship between registration and the editor is:
The latter is "easier" in that we can always call |
This would be still a bit complicated to achieve because you would always have to explicitly enforce loading order of the modules. In this particular case, it would have to load Another use case is for plugin blocks and their hookable parts. How do we want to enable all the modifications for the block registered by the plugin. Should the moment of registration of all blocks happen when the editor is ready to launch to make everything easier? Should we convert
This is the most important question we need to answer first :) It's hard to predict without having a real-life use cases. We can only speculate at the moment, so maybe we should start simple and register only those blocks that are whitelisted? This will help us to discover if for instance reusable blocks will work as expected. |
Isn't this not as complex as it sounds? Merely a combination of |
So |
Description
My first attempt to resolve one of the issues raised in #3800 by @andreiglingeanu:
This PR refactors the library of blocks to expose the function
registerCoreBlocks
that registers all core block rather than doing it as a side effect at the time of declaration. This simple change allows us to have a much better control over when we want to register blocks. My initial proposal is to register all core blocks at the same time when Store instance for the editor is created. I'm open for discussion here and happy to hear how we can tackle it differently.I like this refactoring because it revealed that some code assumes that blocks are globally available. I had to modify a few failing tests where importing from
@wordpress/blocks
magically bootstraps core blocks.Sidenote: It's much easier to review this code using diff without unnecessary whitespace changes:
How Has This Been Tested?
Manually and
npm run test-unit
. There should be no visual changes introduced.Checklist: