How to Create Gutenberg Block Plugin using wp-scripts with PostCSS Build Process

How to Create Gutenberg Block Plugin using wp-scripts with PostCSS Build Process

I’ve been writing tutorials on how to extend Gutenberg Block Editor and having a lot of requests to create one for “Creating Block and Build Processes”. In this article, I’ll be very happy to do something about this request with added PostCSS build processing to make it more useful and extra special. I hope this will be very helpful.

But first, I would really appreciate it if you could upvote my EditorsKit plugin at ProductHunt. I’ve built this plugin to provide set of tools to easily navigate the editor and improve writing and page creation workflow. Thank you in advance. 

EditorsKit - Page Building Toolkit for the Gutenberg Block Editor. | Product Hunt Embed

Adding wp-scripts Package to the Plugin

Assuming you haven’t created the plugin folder yet, let’s create a new folder inside wp-content > plugins and call it my-custom-plugin.

wp-scripts or @wordpress/scripts

You can learn more about this package on the npm documentation. It’s stated there that wp-scripts is a collection of reusable scripts for WordPress development. For convenience, every tool provided in this package comes with a recommended configuration.

Installing Package with npm

I’m also assuming here that you are already familiar with npm. If not, please use this link to learn more and install npm.

Now let’s install wp-scripts package by running the code below to your console or terminal.

npm install --save-dev @wordpress/scripts

If you open package.json file under my-custom-block folder you will see that @wordpress/scripts has been added to it.

"devDependencies": {
    "@wordpress/scripts": "^3.4.0"
}

Setting Up wp-scripts

@wordpress/scripts packages are designed to be configured using scripts section in the package.json file. Add the following under scripts to take advantage of the configurations that have already been setup by the Gutenberg WordPress team for build processes, linting and more.

{
    "scripts": {
        "build": "wp-scripts build",
        "check-engines": "wp-scripts check-engines",
        "check-licenses": "wp-scripts check-licenses",
        "lint:css": "wp-scripts lint-style",
        "lint:js": "wp-scripts lint-js",
        "lint:pkg-json": "wp-scripts lint-pkg-json",
        "start": "wp-scripts start",
        "test:e2e": "wp-scripts test-e2e",
        "test:unit": "wp-scripts test-unit-js"
    }
}
  • build : Transform your code to minified version optimized for production with best performance.
  • check-engines : Check npm compatibility.
  • check-licenses : Validate that all dependencies of a project are compatible with the project’s own license.
  • lint-css : Enforce coding standards for CSS files.
  • lint-js : Enforce coding standards for Javascript files.
  • start : Start compiling javascript and stylesheets according to the configurations. Automatically rebuild if you make changes to the code and you will see errors on console, if there are any.
  • test:e2e : Running end to end tests.
  • test:unit : Running unit tests.

As always, please refer to the documentation in order to check the scripts information.

Adding PostCSS to Handle .css, .scss or .sass Build Processing

Next is to make sure that when running npm start, stylesheets will run the build processing too and will be rebuild when making changes. Files with .css, .scss or .sass will automatically be included.

Installing Packages

Install the required packages for PostCSS configuration by running the following command on your console or terminal.

npm install --save-dev postcss-preset-env mini-css-extract-plugin path css-loader node-sass sass-loader postcss-loader ignore-emit-webpack-plugin

If you check package.json again, you will now see the dependencies installed.

"devDependencies": {
    "@wordpress/scripts": "^3.4.0",
    "css-loader": "^3.1.0",
    "ignore-emit-webpack-plugin": "^2.0.2",
    "mini-css-extract-plugin": "^0.8.0",
    "node-sass": "^4.12.0",
    "path": "^0.12.7",
    "postcss-loader": "^3.0.0",
    "postcss-preset-env": "^6.7.0",
    "sass-loader": "^7.1.0"
}

Modify WebPack Configuration

wp-scripts can be modified easily by creating webpack.config.js on my-custom-block folder, so go ahead and create this file. Then, add the following inside:

Configuration is now complete. 💪 Let’s start creating our custom test block.

How to Create Custom Block Plugin

In this tutorial, you need to create and make sure the following files and folders are available on my-custom-block folder. wp-scripts expects index.js javascript entry point located inside src folder.

+—— my-custom-block
|  +—— plugin.php
|  +—— src
   |   +—— index.js
   |   +—— editor.scss
   |   +—— style.scss
   |   +—— blocks
       |   +—— container
           |   +—— index.js
           |   +—— editor.scss
           |   +—— style.scss
|   +—— build

In this sample plugin, we will create “Custom Container” block which will accept any blocks as inner content. To demonstrate that the stylesheets are working and processes are running, I’ve included few lines of CSS to add padding and shadow on the container element.

Then add the following codes inside the designated files:

plugin.php

src/index.js

src/editor.scss

src/style.scss

src/blocks/container/index.js

src/blocks/container/editor.scss

src/blocks/container/style.scss

Custom Block Created!

Now open your console or terminal again and run npm start to start the build process.

Next, go to your WordPress installation now and activate the My Custom Block plugin. Then, head over and create a new post. You will now see that our Custom Container block is available under Common Blocks category.

You can view the full plugin codes and files on this Github repository.

Final Thoughts

Though wp-scripts help a lot to ease the webpack configurations, it’s a huge question why they didn’t add PostCSS build processing?. Perhaps they will add that in the near future, but for now you can use this article as a solution. If you want to learn more about my other tutorials, I’ve listed them below.

  1. Great tutorial! Just one question, using your code, in addition to the index.js file, two more files (editor.js and style.js) are generated inside the /build folder with the following code inside:

    (window.webpackJsonp=window.webpackJsonp||[]).push([[0],[,function(n,w,o){}]]);

    Is there a way to avoid generating these?

    Thanks in advance

  2. Thanks for the excellent tutorial. For what it’s worth there seems to be a clash with an update to one of the dependencies. If I run the commands as above I get, in my `package.json`:

    “`
    “devDependencies”: {
    “@wordpress/scripts”: “4.1.0”,
    “css-loader”: “^3.2.0”,
    “ignore-emit-webpack-plugin”: “^2.0.2”,
    “mini-css-extract-plugin”: “^0.8.0”,
    “node-sass”: “^4.12.0”,
    “path”: “^0.12.7”,
    “postcss-loader”: “^3.0.0”,
    “postcss-preset-env”: “^6.7.0”,
    “sass-loader”: “^8.0.0”
    }
    “`

    which is different to yours in terms of `sass-loader` and `css-loader` versions.

    And with that config, whenever I run `npm run build` or `npm run start` I get an error which looks like the following:

    “`
    ERROR in ./src/editor.scss
    Module build failed: ModuleBuildError: Module build failed: TypeError: this.getResolve is not a function
    at Object.loader (/path/to/plugins/ubc-select-editor-template/node_modules/sass-loader/dist/index.js:52:26)
    “`
    for each of the scss files. However, if I force the versions of the dependencies to be as you have, then all works well!

    Something might need a tweak with an update to one of the deps?

    1. My apology for late response Rich! It’s weird, I’m using the same setup and mine is up-to-date. I’m not getting similar issue. You can use the version that’s working though 🙂 Thanks!

    2. I’m running into the same problem. It seems to be a problem with the sass-loader v8.0.0. Trying to figure out what’s wrong here but using v7.1.0 works.

    3. I had the same problem but the solution with copying the dependencies is also not working for me. That’s why I am stucked and can’t continue :/

  3. Thanks a lot for your article, Jeffrey! It helped me to finally get `wp-scripts` to work 🙂 Just wanted to ask you: what are the PHP files generated in the `build` folder for? I specifically mean `editor.asset.php`, `index.asset.php` and `style.asset.php`.

    I also wanted to mentioned that there was an error during the build process that I managed to solve by reordering the loaders like this: `MiniCssExtractPlugin.loader`, `css-loader`, `postcss-loader`, `sass-loader` (this is also the recommended order in the `MiniCssExtractPlugin` website).

    1. Thanks a lot Rodrigo! I’ve updated the gist for everyone to have working version as well. I really appreciate the help. Regarding the .php files, it’s from the latest `wp-scripts` version. You can just add them to .gitignore 😉

  4. Hey Jeffrey,

    Can the webpack file be tweaked so that each of the compiled files be written into different folders as opposed to having all of them in just one folder?

  5. Hey Jeffrey,

    Awesome guide, I’m curious, I saw you included the MiniCssExtractPlugin plugin here, but when I try to use it to process import “./editor.scss”; inside a index.js file there seem to be some issues.

    1. I had to remove the entry path array from custom config.
    2. It properly bundles editor.scss from all imports into a single editor.css file.
    3. It does however not ignore the import statements when bundling the JS itself which results in require_module statements pointing to scss files and the blocks & formats never work properly.

    Found this, and it seems pretty close if not exactly the same issue, though the proposed solutions all negate to answer the question and simply propose they use the method you do initially here.

    https://stackoverflow.com/questions/55677070/webpack-mini-css-extract-plugin-output-multiple-css-files-on-single-entry

    I should add that I this is what is added to our bundled JS

    “`/* harmony import */ var _editor_scss__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./editor.scss */ “./src/formats/popup-trigger/editor.scss”);
    /* harmony import */ var _editor_scss__WEBPACK_IMPORTED_MODULE_13___default = /*#__PURE__*/__webpack_require__.n(_editor_scss__WEBPACK_IMPORTED_MODULE_13__);“`

    I also tried excluding these imports from the main JS bundler with this:

    “`config.module.rules[ 1 ].exclude = config.module.rules[ 1 ].exclude || [];
    if ( ! Array.isArray( config.module.rules[ 1 ].exclude ) ) {
    config.module.rules[ 1 ].exclude = [ config.module.rules[ 1 ].exclude ];
    }
    config.module.rules[ 1 ].exclude.push( /\/(style|editor)\.(sc|sa|c)ss$/ );“`

    Really hoping to get some insights on either how to fix this, or at least why it won’t work as expected.

  6. Thanks a lot for the suggestions Daniel! I’ve decided to follow the Gutenberg format when it comes to stylesheets inclusion : https://github.com/WordPress/gutenberg/blob/master/packages/block-library/src/style.scss . Since this guide is using `wp-scripts`, I’m mainly focus on how the Gutenberg devs are doing things. This will also be helpful, so users can easily understand how Gutenberg plugin works when they view the source code on Github. Thanks again!

Leave a Reply

Your email address will not be published. Required fields are marked *

Up Next:

Introducing EditorsKit Block Styling, Utility Classes Features and more!

Introducing EditorsKit Block Styling, Utility Classes Features and more!