Gutenberg introduces the modern JavaScript stack into the WordPress ecosystem, which means some new tooling should be learned. Although tools like create-guten-block are incredibly useful, it’s also handy to know what’s going on under the hood.
Article Series:
Series Introduction
What is Gutenberg, Anyway?
A Primer with create-guten-block
Modern JavaScript Syntax
React 101
Setting up a Custom webpack (This Post)
A Custom “Card” Block
The files we will be configuring here should be familiar from what we covered in the Part 2 Primer with create-guten-block. If you’re like me (before reading Andy’s tutorial, that is!) and would rather not dive into the configuration part just yet, the scaffold created by create-guten-block matches what we are about to create here, so you can certainly use that as well.
Let’s jump in!
Getting started
Webpack takes the small, modular aspects of your front-end codebase and smooshes them down into one efficient file. It’s highly extendable and configurable and works as the beating heart of some of the most popular products and projects on the web. It’s very much a JavaScript tool, although it can be used for pretty much whatever you want. For this tutorial, it’s sole focus is JavaScript though.
What we’re going to get webpack doing is watch for our changes on some custom block files and compile them with Babel to generate JavaScript files that can be read by most browsers. It’ll also merge any dependencies that we import.
But first, we need a place to store our actual webpack setup and front-end files. In Part 2, when we poked around the files generated by create-guten-block, we saw that it created an infrastructure for a WordPress plugin that enqueued our front-end files in a WordPress way, and enabled us to activate the plugin through WordPress. I’m going to take this next section to walk us through setting up the infrastructure for a WordPress plugin for our custom block.
Setting up a plugin
Hopefully you still have a local WordPress instance running from our primer in Part 2, but if not, you’ll need to have one installed to continue with what we’re about to do. In that install, navigate to wp-content/plugins and create a fresh directory called card-block (spoiler alert: we’re going to make a card block… who doesn’t like cards?).
Then, inside card-block, create a file called card-block.php. This will be the equivalent to plugin.php from create-guten-block. Next, drop in this chunk of comments to tell WordPress to acknowledge this directory as a plugin and display it in the Plugins page of the Dashboard:
gutenberg-card-block,
editor_style => gutenberg-card-block-edit-style,
style => gutenberg-card-block-edit-style
));
}
add_action(init, my_register_gutenberg_card_block);
As the above comments indicate, we first register our script with WordPress using the handle gutenberg-card-block with two dependencies: wp-blocks and wp-elements. This function only registers a script, it does not enqueue it. We do something similar for out edit and main stylesheets.
Our final function, register_block_type, does the enqueuing for us. It also gives the block a name, card-block/main, which identifies this block as the main block within the namespace card-block, then identifies the script and styles we just registered as the main editor script, editor stylesheet, and primary stylesheet for the block.
If you are familiar with theme development, you’ve probably used get_template_directory() to handle file paths in hooks like the ones above. For plugin development, we use the function plugins_url() which does pretty much the same thing, except instead of concatenating a path like this: get_template_directory() . /script.js, plugins_url() accepts a string path as a parameter and does the concatenation for us. The second parameter, _ FILE _, is one of PHP’s magic constants that equates to the full file path of the current file.
Finally, if you want to add more blocks to this plugin, you’d need a version of this function for each block. You could work out what’s variable and generate some sort of loop to keep it nice and DRY, further down the line. Now, I’ll walk us through getting Babel up and running.
Getting Babel running
Babel turns our ES6 code into better-supported ES5 code, so we need to install some dependencies. In the root of your plugin (wp-content/plugins/card-block), run the following:
npm install babel-core babel-loader babel-plugin-add-module-exports babel-plugin-transform-react-jsx babel-preset-env –save-dev
Update April 2019: We’ve had a lot of updates to this over the last many months because of the big change in Babel from 6 to 7. Thanks to Nina Regli, Rick Hughs, and Bryan Chong.<.p>
Nina had luck with:
npm install –save-dev @babel/core @babel/preset-env
Rick had luck with:
npm install @babel/core babel-loader babel-plugin-add-module-exports babel-plugin-transform-react-jsx @babel/preset-env –save-dev
Bryan had luck with:
npm install –save-dev @babel/preset-react babel-preset-minify @babel/core @babel/cli @babel/preset-en
Bryan also renamed `.babelrc` to `babel.config.js` and configured it like this:
module.exports = function (api) {
return {
presets: [
[
@babel/preset-react,
{
pragma: wp.element.createElement
}
],
minify,
@babel/env
]
};
}
That big ol’ npm install adds all the Babel dependencies. Now we can add our .babelrc file which stores some settings for us. It prevents us from having to repeat them over and over in the command line.
While still in your theme folder, add the following file: .babelrc.
Now open it up and paste the following:
{
presets: [env],
plugins: [
[transform-react-jsx, {
pragma: wp.element.createElement
}]
]
}
Update April 2019: With Babel 7, you probably need presets: [@babel/preset-env],
So, what we’ve got there are two things:
presets: [env] is basically magic. It automatically determines which ES features to use to generate your ES5 code. We used to have to add different presets for all the different ES versions (e.g. ES2015), but it’s been simplified.
In the plugins, you’ll notice that there’s a React JSX transformer. That’s sorting out our JSX and turning it into proper JavaScript, but what we’re doing is telling it to generate WordPress elements, rather than React elements, which JSX is more commonly associated with.
Generate stub files
The last thing we’re going to do is generate some stub files and test that our webpack and WordPress setup is all good.
Go into your plugin directory and create a folder called blocks and, within that, create two folders: one called src and one called dist.
Inside the src folder, create the following files. We’ve added the paths, too, so you put them in the right place:
blocks.js
common.scss
block/block.js
block/editor.scss
block/style.scss
Now that you’ve created those files, open up blocks.js and add this one-liner and save:
import ./block/block;
OK, so now we’ve generated the minimum amount of things, let’s run webpack. Open up your terminal and move into your current plugin folder—then we can run the following, which will fire-up webpack:
npx webpack
Pretty dang straightforward, huh? If you go ahead and look in your dist folder, you should see some compiled goodies in there!
Wrapping up
A lot of setup has been done, but all of our ducks are in a row. We’ve set up webpack, Babel and WordPress to all work as a team to build out or custom Gutenberg block (and future blocks). Hopefully now you feel more comfortable working with webpack and feel like you could dive in and make customizations to fit your projects.
Article Series:
Series Introduction
What is Gutenberg, Anyway?
A Primer with create-guten-block
Modern JavaScript Syntax
React 101
Setting up a Custom webpack (This Post)
A Custom “Card” Block