-
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
Create Block: Create a more modular structure that is easier to extend to several blocks #25188
Comments
The plan is to make it possible to build and use external templates for Create Block as proposed in #23712. When it's implemented it should be much easier to share alternative configurations that go beyond the setup optimized for Block Directory (https://wordpress.org/support/article/block-directory/) publishing. |
|
Been dealing with this on and off over the past couple months and @bosconian-dynamics has offered some solutions |
It looks like it is a recurring request from the community that I see more often these days. The most recent one happened on Twitter and was started by @cr0ybot: https://twitter.com/cr0ybot/status/1435379030522478596
This requires that we add support to |
To add to what @gziolo pulled in from my tweet, while I do believe that the standard create-block template should offer a best-practice approach for multiple blocks, the main thing I'm struggling with in this context is the location of the block.json file. It doesn't look like create-block currently creates a block.json in the template, but I assume it would put it in the root of the plugin following the current single-block approach. I prefer to have all files related to each "feature" grouped together in a single folder when possible. This works fine for JS+CSS only, but when you throw block.json in the mix you suddenly need a separate folder/location for the main block metadata. The funny thing is the Gutenberg block-library package is structured the way I want: all files for a block in one folder, including the block.json file. I haven't dug in to see how those metadata files are handled on compile—are they copied to another location? |
It creates
Yes, they are copied (with webpack plugin) to the |
EDIT: Code below updated to include "-block.json" at the end of the custom metadata filenames so that they are recognized by I've written up a quick webpack config for my project that moves the block.json file into the build folder. My plugin looks like this:
webpack.config.js const { basename, dirname } = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const defaultConfig = require('@wordpress/scripts/config/webpack.config');
module.exports = {
...defaultConfig,
plugins: [
...defaultConfig.plugins,
new CopyWebpackPlugin({
patterns: [
{
// Copy block.json to build folder with name of block as filename
from: 'src/blocks/**/block.json',
to({ absoluteFilename }) {
// Get the block folder name
const blockName = basename(dirname(absoluteFilename));
// Output with original extension (.json)
return `./${blockName}-block[ext]`;
},
},
],
}),
],
}; This copies the block.json file into the root of /build, so the relative paths within are as simple as possible: {
...
"editorScript": "file:index.js",
"style": "file:style-index.css"
} EDIT: I've removed the preceding In I do need to apologize because this is starting to feel a little off-topic from the initial purpose of this issue. Sorry about that. 😓 |
@cr0ybot, thank you for sharing more details. It is very helpful to plan future iterations.
I agree that colocating JS, CSS, and |
@gziolo @cr0ybot would it make sense to have an entry point for each block? If I am understanding the code here, it seems that all of the blocks are being combined into a single JS file. So in theory, calling the |
@ryanwelcher Yea sorry, I left that part out. The main Here's where I've run into a weird hitch however, and I'm still determining if I've done something wrong: when I try using EDIT: I just realized what you meant when you specified "client side". Yes, since the main index.js file should be enqueued, even if you only registered one block server-side, I see now that they would all be registered client side (only). Sorry! |
@ryanwelcher, I would say it depends on the use case. If you have a parent block that needs some child blocks to be fully functional then I'd say bundling them together makes sense into one JS file. In that case, you probably need to manually register a script and pass the used script handle as a reference in
|
Let me also share the guidelines for The WordPress.org Plugin Directory related to single vs multiple blocks:
It's worth emphasizing that from the start the intention is to drive folks to submit their blocks to the Block Directory and this is why the documentation is organized around that idea. However, knowing that the motivation from plugin authors can differ, we should make |
@gziolo As an agency developer, my use case is that I generally want to put all of the custom blocks for a particular site into one plugin for organization, ease of development, and a minimal number of repos. I also was starting at the code in $filename = 'block.json';
$metadata_file = ( substr( $file_or_folder, -strlen( $filename ) ) !== $filename ) ?
trailingslashit( $file_or_folder ) . $filename :
$file_or_folder; Walking through the code:
Therefore, if my metadata file is
So currently, differently-named metadata files do not work, unless you happen to name your file with "block.json" at the end, i.e. "page-header-block.json". I'm going that route for now. I went to file this on trac but it looks like it's already being tracked: https://core.trac.wordpress.org/ticket/53806. Kinda disappointed it didn't make it into the 5.8.1 release. I've updated my custom Webpack config above to account for this. |
Now I don't remember if there was some rationale behind the current implementation that was incorrectly documented, or that's a bug that needs to be fixed 🤔 Thank you for sharing the Trac ticket. This behavior has been around from the start - WordPress 5.5. I need to research the initial discussion. Edit: In the initial implementation in the Gutenberg plugin, you would always have to name the file Lines 26 to 27 in 3345144
One thing that comes to my mind is integrations with the Plugin Directory or WP-CLI. A good example is WP-CLI command to extract translations, it restricts processing to files that have I don't remember how the Plugin Directory detects if the plugin contains blocks, but for sure it would be simpler if the presence of |
I just watched @ryanwelcher Twitch for Creating a plugin with @wordpress/create-blocks that has multiple blocks, and this is a long overdue tutorial for elevating the developer experience. 👏
@cr0ybot I believe it is even likely that non-agency developers have been grappling with this as well, and I would postulate that this hinderance (single block only) is likely keeping from everyday developers from submitting their blocks ideas. I do not have the means to back that with metrics, and merely speculating (never good, I know). However, as an agency developer I've seen this as a rather big roadblock for developer experience. |
I watched the stream as well. It was great to see all the options explained by @ryanwelcher 💯 The recording is now available also on YouTube: https://www.youtube.com/watch?v=lwXXckW3dT0 (on Twitch the content gets deleted after some time). |
I wanted to share my thoughts after watching the stream from @ryanwelcher. For full transparency, I discussed the same ideas with Ryan in a private chat to better organize my thoughts. Let me emphasize first that I fully agree that we should refactor
There is also a related topic related to how the build process from gutenberg/packages/scripts/config/webpack.config.js Lines 39 to 50 in 17e3641
The initial plan was to handle also In theory, we could achieve similar goals by changing One final thing to think about is also the structure of the build folder in the case it supports multiple blocks. In the stream, you could see the following output generated: As noted in #25188 (comment) by @cr0ybot, you could include a
|
@gziolo I agree with your final build folder structure, which also solves the issue of having to rename each Something else I'd like to point out related to the relative file paths in Anyways, I'd love to see a more flexible way of handling entrypoints in |
OK, it's possible but:
If there is better/simpler solution, I like to know about it. Thanks |
I think, the best solution would be setting glob rule for all block.json files. And in block.json set not only scripts and styles paths but also build path. Or generate build folder on same level as src. So And in packace.json something like this: But I understand that wp-scripts in not only for scaffold blocks, right? |
The Inside of the
This structure will detect all of the block.json files and output each block in its own directory in
The important note here is that you need to use |
Ah, OK, make sense. I will try it. Thanks |
You can use this utility I wrote to create multiple blocks automatically until it's available in core. It's a wrapper around the |
@ryanwelcher great! |
Hi @ryanwelcher @gziolo, I manage to handle multiple blocks. But multiple blocks do not work with --hot "Fast Refresh". It's through Any idea how to solve this issue. Thanks, |
@amjadr360, I can reproduce the same issue when using two blocks (entry points): |
I did some investigation on the case with multiple blocks (entry points) and it's fixable but there are some technical challenges. It's also why this feature needs to be activated with There is an explicit mention for the same use case in the React Fast Refresh Webpack Plugin documentation https://github.com/pmmmwh/react-refresh-webpack-plugin/blob/main/docs/TROUBLESHOOTING.md#component-not-updating-with-bundle-splitting-techniques:
I can confirm that adding this line to the webpack config resolves the issue but the challenge is that we now need to enqueue another script ( I hacked it by adding the following code in my plugin before lines that register blocks: wp_enqueue_script(
'webpack-runtime-my-block',
plugins_url( 'build/runtime.js', __FILE__ ),
); However, we would need something better that could be handled automatically. I would appreciate some ideas from people on how to integrate that into the existing projects. |
I'm not sure if this is the right place to ask, but I'm struggling to find any information about how to include external libraries as dependencies. Let's say I have a few blocks that rely on the Swiper slider. Swiper slider provides a way to import only specific modules, which reduces the final bundle. So if I import only specific modules inside of each block I'll end up with multiple copies of the same library in multiple blocks. If I simply copy the production bundle from /node_modules and enqueue it as a regular script, it will work, but the size of the script is very large since it includes all the modules. I also tried to import only specific modules of the Swiper inside of my scr/js/ folder, this looks a bit hacky. The script compiles only if I provide a block.json file. But my other scripts don't see Swiper instance anymore.
in PHP I enqueue the bundle of Swiper from /build/js/index.js, but my block-one script.js doesn't see the Swiper. What is the correct approach here? |
@DeoThemes The way that JavaScript is compiled with WebPack, each entrypoint and module is enclosed so that you avoid issues with everything being in the global scope. If you want the Swiper modules to be globally available on the page, you'll need to add them to the |
@cr0ybot Webpack supports sharing libraries between entrypoints if you use |
It seems this issue has been resolved, for the most part. I was able to create multiple blocks using this method stated by @ryanwelcher. The block registrations in the .php file just needs to point to the correct build directory.
The documentation for @wordpress/create-block should be updated to reflect these changes since I pretty much wasted my time trying to modify the package.json with several start/build scripts. |
@stefanfisk Oof, I should have looked into that a bit more before making a suggestion, thanks. Do you happen to know what kind of tooling would be required? Are you talking about WordPress script enqueuing or something else? |
@cr0ybot Here's the code I was using at the time https://gist.github.com/stefanfisk/bb4e045f3d15829a377916dc5fee9acc I am no longer using this as my needs changed, so YMMV. |
In the the last version published to npm you can find 2 new CLI options that should vastly improve the experience for extending existing projects with new blocks:
|
@colorful-tones I created a wrapper CLI tool around create-block to extend it's capabilities. e.g. named blocks, and full Tailwind integration compiling CSS at the block level (separate files). I'd be open to adding more features. 🙂 |
Trying this and I'm getting messages like |
Nevermind, I've figured it out and created an issue: #45792 |
Regarding the issue reported by @amjadr360 in #25188 (comment). I have a proposal that addresses it for React components: |
Is your feature request related to a problem? Please describe.
I've been struggling for days to set up a plugin that implements several blocks. I've looked at examples at github and around the net but most are outdated compared to newer block standards. I admit that my skills in using javascript/webpack/npm are fairly low.
Using the @wordpress/create-block script I quickly get a plugin with a single block up and running - but it's not easily extendable to several blocks. The php side of block init+setup is in the common "plugin.php" file. And when trying move stuff that is common to a block and place that in a subfolder to the src-folder I realize that the build/webpack scripts are not really supporting that.
What solution would you like
I would like the create-block script to generate a structure that is more modular and easier to extend to implementing more than a single block. Something like this:
Alternative solutions
The alternative would be to create as many plugins as you want blocks but this seems a bit unnecessary if creating several blocks.
The text was updated successfully, but these errors were encountered: