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

Add the block registration RFC #13693

Merged
merged 33 commits into from Jun 18, 2019
Merged

Add the block registration RFC #13693

merged 33 commits into from Jun 18, 2019

Conversation

@youknowriad
Copy link
Contributor

@youknowriad youknowriad commented Feb 6, 2019

This RFC is intended to serve both as a specification and as documentation for the implementation of runtime-agnostic block type registration.

For more details, read the RFC :)

Refs #2751.

Next steps outlined in #16209.

Copy link
Member

@danielbachhuber danielbachhuber left a comment

Great start! I've left several comments inline. Because they'll eventually get lost when you make edits, here's a recap:

  • It'd be useful to include more detail on why runtime-agnostic registration is necessary (e.g. descriptions of the specific use-cases to be solved) so we can continue to evaluate the RFC and attached code against solving those use-cases.
  • I don't know what lazy-loading block types means, in a practical sense. Clarification there would be helpful.
  • I wonder to what degree we'd like to leave the door open for runtime-agnostic save, render, and transform callbacks. Some of it may be technically impossible but might foster creative thinking to keep a part of the conversation.

@@ -0,0 +1,369 @@
This RFC is intended to serve both as a specification and as documentation for the implementation of runtime-agnostic block type registration.
Copy link
Member

@danielbachhuber danielbachhuber Feb 8, 2019

Would it be useful to include more detail on why runtime-agnostic registration is perceived to be necessary, and which specific audiences this implementation will serve?

Copy link
Contributor Author

@youknowriad youknowriad Feb 8, 2019

Some important aspects here:

  • The block library package are served as an npm package, we don't know where these will be run
  • The block repository (one of the 9 projects) need to be able to get block information outside of WordPress

I guess this could be added somewhere


## Requirements

Behind any block type registration is some abstract concept of a unit of content. This content type can be described without consideration of any particular technology. In much the same way, we should be able to describe the core constructs of a block type in a way which can be interpreted in any runtime.
Copy link
Member

@danielbachhuber danielbachhuber Feb 8, 2019

Can you include a couple examples of these units of content?

docs/rfc/block-registration.md Outdated Show resolved Hide resolved
docs/rfc/block-registration.md Outdated Show resolved Hide resolved
docs/rfc/block-registration.md Outdated Show resolved Hide resolved
docs/rfc/block-registration.md Outdated Show resolved Hide resolved
docs/rfc/block-registration.md Outdated Show resolved Hide resolved
docs/rfc/block-registration.md Outdated Show resolved Hide resolved
{ "transforms": "my-block-transforms.js" }
```

This property is a pointer to a JavaScript file containing the save function of the block transforms. The save function defines the way in which the different attributes should be combined into the final markup, which is then serialized by Gutenberg into `post_content`.
Copy link
Member

@danielbachhuber danielbachhuber Feb 8, 2019

I think it's really important that we eventually are able to define server-side transforms.

Copy link
Contributor Author

@youknowriad youknowriad Feb 8, 2019

Can you expand more?

Copy link
Member

@danielbachhuber danielbachhuber Feb 8, 2019

The most immediate use-case that comes to mind is:

  1. Developer creates a block type which saves markup variation A. Developer also implements styling for variation A.
  2. Editorial publish dozens of blocks with markup variation A.
  3. Due to changing business requirements, developer modifies original block type to save markup variation B.

Currently, the developer must keep the styling around for markup variation A as well as implement styling for markup variation B. There's no way to programmatically transform all blocks with variation A into variation B.

Styling isn't the only dependency on markup. If the site has analytics tied to the markup, the associated logic for both variations will need to be kept around (growing in complexity over time).

If we had server-side transform definitions, the developer would be able to run a WP-CLI command that batch transforms all markup variation A into markup variation B.

The less-preferable workaround we have right now is to use dynamic blocks, which means markup isn't ever stored in the post content.

Copy link
Contributor Author

@youknowriad youknowriad Feb 8, 2019

Got it this ties to the deprectatedVersions api we have right now. I do think this workflow deservers improvements but I think it should be addressed separately from this RFC. The solution might be to add a new property here but I think it's a complex problem on its own to warrant a separate RFC/PR

Copy link
Member

@danielbachhuber danielbachhuber Feb 11, 2019

Got it this ties to the deprectatedVersions api we have right now. I do think this workflow deservers improvements but I think it should be addressed separately from this RFC. The solution might be to add a new property here but I think it's a complex problem on its own to warrant a separate RFC/PR

Fair enough, this works for me. Do you want to open a new issue for it? I'm not sure of the best contents for it.

I've thought of another use-case today: migrating (or importing) content into WordPress from another source. I'd prefer to migrate (import) to block-native format. At the moment, I'm left with either migrating to Classic editor format or hand-forming blocks.

Copy link
Member

@gziolo gziolo Feb 21, 2019

Fair enough, this works for me. Do you want to open a new issue for it? I'm not sure of the best contents for it.

I've thought of another use-case today: migrating (or importing) content into WordPress from another source. I'd prefer to migrate (import) to block-native format. At the moment, I'm left with either migrating to Classic editor format or hand-forming blocks.

Yes, those are both very good points. I think with this RFC we want to start the process of moving all basic metadata to JSON file to make it easy to consume by PHP code. This will surely open new options for further investigation. Definitely, deprecations and transformations are those aspects which might be somehow encoded in a way that could work on both sides. I also want to echo what @youknowriad said, this is complex and we want to keep this RFC very focused so we could finish the very first iteration in a few weeks so we could land it in let's say optimistically in WordPress 5.3 :)

@youknowriad youknowriad requested a review from notnownikki as a code owner Feb 8, 2019
Copy link
Member

@gziolo gziolo left a comment

I'm personally very happy about the current state of this proposal. This is obviously only the first step which should allow us to be able to expose the same definitions through REST API. What is proposed here is a nicely scoped actionable refactoring which we could implement and promote quite quickly. This should also remove some confusion around blocks which use render_callback to handle save method on the server because at the moment it is unclear whether many properties should be included in JS or PHP file.

@youknowriad
Copy link
Contributor Author

@youknowriad youknowriad commented Feb 11, 2019

After some thinking, it seems like this PR falls short in the way the script dependencies are discovered. At the moment, there's no way to know which dependencies are required by each JavaScript file used in the block.json.

The question is:

1- Do we optimize the scripts for WordPress (which means they use wp.* modules and any wordpress script). and if this is the case, how do we statically analyze the dependencies of these scripts? should we have a separate assets.json to solve it?

2- Or do we optimize for "npm-like" contexts, which mean the scripts use import/require syntax for the dependencies? in which case WordPress can't load these without a build tool.


Initially, I think we should take the first approach here and introduce a assets.json file where each file path maps to script/styles dependencies (handles).

Thoughts?

docs/rfc/block-registration.md Outdated Show resolved Hide resolved
@aduth
Copy link
Member

@aduth aduth commented Feb 18, 2019

After some thinking, it seems like this PR falls short in the way the script dependencies are discovered. At the moment, there's no way to know which dependencies are required by each JavaScript file used in the block.json.

My gut reaction is to avoid yet-another file with assets.json, though admittedly I'm not entirely clear what format and role it would take.

An earlier thought was that if the value of a script property as defined in the manifest would be simply the script handle assumed to be registered by the plugin author elsewhere, then it would be fairly trivial for WordPress to resolve the dependencies. This, of course, does not work well outside a wp-admin context for the "generic" block.

I'd not like to set any expectation that all wp.* are available, especially if we don't yet have a plan for how to determine the specific dependencies of a given script. We should assume that as additional screens are implemented, we may introduce more script handles which ought only be loaded within the context of the specific screen (i.e. not all scripts for all screens).

The second proposal is not great if it were to require a build step, but part of me wonders if that would be strictly necessary (vs. some maybe-naive string replacement script preparation). There's an interesting alignment between a behavior implied with WPDefinedPropertyFile to assign some named export, if we could pair this with dependencies to align to the ES2015 import / export semantics.

import { createElement } from '@wordpress/element';
export const edit = () => createElement( 'input' );

There's many forms we could apply to create some manifest for individual scripts to declare their inputs (dependencies) and outputs (exported properties). We could even adopt the plugin / theme comment-based approach, which has an advantage in that it may be more okay to have WordPress-specific assumptions, as long as those assumptions are merely overlooked by virtue of being a code comment.

/**
 * Exposes: edit
 * Dependencies: wp-element
 */

Finally, I wonder if we could inherit npm's dependencies pattern, either literally as in each block is a package, with perhaps its manifest defined within the package.json:

{
	"name": "@wordpress/block-library-heading",
	"block": {
		"name": "core/heading",
		"title": "Heading"
	},
	"dependencies": {
		"@wordpress/element": "*"
	}
}

...or by inspiration where block.json has a dependencies definition which takes a similar shape:

{
	"name": "core/heading",
	"title": "Heading",
	"dependencies": {
		"@wordpress/element": "*"
	}
}

@youknowriad
Copy link
Contributor Author

@youknowriad youknowriad commented Feb 19, 2019

The second proposal is not great if it were to require a build step, but part of me wonders if that would be strictly necessary (vs. some maybe-naive string replacement script preparation).

Maybe, it does feel fragile though 🤷‍♂️

Finally, I wonder if we could inherit npm's dependencies pattern, either literally as in each block is a package, with perhaps its manifest defined within the package.json:

That's exactly what I had in mind with the assets.json file, the idea is that a block is not a single file and the same file could be shared across blocks too which means it's file dependencies and not block dependencies and that's why I proposed a separate assets.json

gziolo and others added 9 commits Jun 18, 2019
@gziolo gziolo force-pushed the add/block-registration-rfc branch from 768c672 to f3456fe Jun 18, 2019
gziolo
gziolo approved these changes Jun 18, 2019
Copy link
Member

@gziolo gziolo left a comment

I'm approving this PR on behalf of @youknowriad, see related comment in #13693 (review):

I think the RFC is in a good state to be merged. Still a draft though. I think I still have concerns with some of its content. Some things that come to mind for instance are:

  • script and editorScript are confusing, especially script. Is it really necessary? BC could be solved without having the property in block.json
  • I don't like making WP handles part of the block.json APIs as it's too WP specific but I understand the dependencies management concerns. Moving to implementation will help us clear this out.
  • I think we need a solution for the "render_callback" alternative before making the block.json API a public one. The templating idea is a good one.

Ultimately, I think merging this will allow us to refine it bit by bit in targeted PRs as we move forward with the implementation before making the block.json based registration a public API.

I can't approve the PR @gziolo though as I'm the one who started the PR :)

I want to add that the points listed were addressed in the meantime. In addition, I opened #16209 which documents all items that were discussed and should be further investigated as a follow-up task.

@gziolo gziolo merged commit 43730e8 into master Jun 18, 2019
3 checks passed
3 checks passed
@github-actions[bot]
Filter merged Filter merged
Details
@github-actions[bot]
Filter merged Filter merged
Details
@travis-ci[bot]
Travis CI - Pull Request Build Passed
Details
@gziolo gziolo deleted the add/block-registration-rfc branch Jun 18, 2019
@youknowriad youknowriad added this to the Gutenberg 6.0 milestone Jun 24, 2019
@aduth
Copy link
Member

@aduth aduth commented Apr 10, 2020

  • Should these asset keys be camelCased rather than snake_cased ? While there are no other properties proposed in the RFC for precedent, it may be fair to lean on attributes naming conventions (reference and package.json (reference) as examples for prior art.

    • A counter-point could be made if, per the above question of finite vs. runtime-specific assets, these are considered WordPress-specific to satisfy the editor_script key of register_block_type settings.

Sure, we can make them camelCased. I followed PHP implementation and forgot about the differences. It also depends on whether we decide to keep the type of asset as the key here. Even then, I think it's fine to map it for consistency in the definition.

If these keys are camelCased (which they are as of today), how do we want to proceed with referencing these properties in PHP code?

  • Should they be mapped automatically to a snake case format during load? e.g. editorScript -> editor_script
    • Currently, the block registration only supports naming as editor_script.
  • I encountered some conflict with this in 0d47558 , since the coding standards try to enforce snake case. We can either accept this and make those exceptions, deferring to the name used in the block manifest. Or we could do this mapping. Or we could opt to standardize on snake case (for all properties, or for specific properties).

@gziolo
Copy link
Member

@gziolo gziolo commented Apr 16, 2020

@aduth, it's always been an issue to keep those conventions work for both PHP and JS knowing that those objects are shared between the client and server. The same issue applies to the REST API payload, but in that case, the source of truth comes from PHP so it was easier to pick the convention :)

I would be in favor of using camelCase convention for JSON files to follow package.json and other config files that we use in the project. In PHP we can always convert it all automatically to snake_case. What do you think?

@aduth
Copy link
Member

@aduth aduth commented Apr 16, 2020

In PHP we can always convert it all automatically to snake_case. What do you think?

Where do you think this should happen? During register_block_from_metadata ?

Do you worry that it might be a bit too "magical", if the developer only sees the configuration as providesContext, but for some reason its only available as provides_context in PHP?

As noted in my previous comment, it's possible impactful for me in the work at #21467, since I am currently referencing the providesContext property named as such in PHP. If we think we want to have this snake-cased, I could try to find some temporary fix so that it's named provides_context in PHP and providesContext in JavaScript and JSON.

@gziolo
Copy link
Member

@gziolo gziolo commented Apr 17, 2020

Where do you think this should happen? During register_block_from_metadata ?

Yes, I think it's the place for doing it. A similar trick will have to happen for translatable strings read from the config file. I think it's a good compromise.

Do you worry that it might be a bit too "magical", if the developer only sees the configuration as providesContext, but for some reason its only available as provides_context in PHP?

On the WP_Block_Type object we already have a few snake_case public properties:

https://github.com/WordPress/wordpress-develop/blob/23704571754c162d3a863a30c9249e59f0378c47/src/wp-includes/class-wp-block-type.php#L32

https://github.com/WordPress/wordpress-develop/blob/23704571754c162d3a863a30c9249e59f0378c47/src/wp-includes/class-wp-block-type.php#L48

https://github.com/WordPress/wordpress-develop/blob/23704571754c162d3a863a30c9249e59f0378c47/src/wp-includes/class-wp-block-type.php#L64

Should we add provides_context and context there as well to make it easier to discover?

@aduth
Copy link
Member

@aduth aduth commented Apr 17, 2020

I'm still on the fence, to be honest. There are good reasons to reference it as in the camel-case form (providesContext, etc.):

  • It identifies the JSON form as elevated to being the de facto source of truth, where if in JSON we choose to adopt the JavaScript naming conventions, camel-case is the correct form.
  • It remains constant, regardless of conventions in the languages from which it is referenced.

I'm reluctant to let this decision block the otherwise unrelated work ongoing in #21467. For now, I think I will proceed to merge the code referencing providesContext. I don't think this is irreversible if we decide later to take a more firm stance of one or the other of these two naming conventions. At most, I think it would require supporting both properties for a short time in the plugin. Since it is a property of the WP_Block_Type class, we can even include warnings of a deprecation using the __get magic method.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment