Building ESNext on WordPress, Simplified

ESNext-on-WordPress-0

WordPress is currently going through a sort of renaissance in terms of content editing and development. The release of the Block editor created a lot of commotion in the entire WordPress ecosystem, and it’s still present.

New kid on the the Block Editor

The Block Editor enables a new way of creating pages and posts and a whole new framework for developers to create custom site components. For the full story on Block Editors release, criticisms, and exciting new features, see Denis’ blog post on the future of WordPress themes.

In this article, we will focus on a package that’s supposed to simplify the build process. But why is it complicated in the first place?

Challenges using Block Editor and developing custom blocks

Developing new blocks requires an entirely different setup from what most WordPress developers are used to.

One of the reasons for not using the Block Editor and developing custom blocks is a drastic change in technology that is used for developing blocks. The Block Editor and all of its blocks are built with React.js, a JavaScript library that is “relatively new” on the scene and requires a different approach in development.

On top of that, some sort of build process is recommended for developing custom blocks, so the code can be split up into smaller logical pieces, which will improve the overall codebase’ maintainability.

In addition, a build process is necessary for using the ESNext syntax of JS, because the written code will be transpiled through the build process into code that can run on any browser.

A new development stack from the WordPress team

To make the development of custom blocks easier, a couple of neat JS packages were made available. One of those packages is @wordpress/scripts.

It comes with pre-configured scripts for building and bundling JS assets, linting your JS code against WordPress coding standards, and performing E2E tests.

We’ll focus on build script and go through basic concepts of others.

Installation and configuration

To install and use @wordpress/scripts package in your existing WordPress project, you need to have Node.js installed and configured.

If you already used some packages from npm repository, there should be a package.json file in your projects directory. If that is not the case, you will need to create it by navigating to your projects directory with terminal, enter: npm init command and fill out the details of your project.

Once you have a package.json file, you can go back to the terminal and install @wordpress/scripts package by entering the following:

	npm install --save-dev  @wordpress/scripts

Wait for the installation to finish. Once the installation is done, you can start setting up your npm scripts that @wordpress/scripts package provides.

To do that, edit your package.json file and change the scripts object to look like this:

	"scripts": {
   "build": "wp-scripts build"
   "start": "wp-scripts start",
}

Usage and examples

Both of these scripts, by default, will search for src/index.js as their source file to compile from and will create a compiled file in build/index.js. This compiled file will be the one that should be registered and enqueued in WordPress using the wp_register_script function and wp_enqueue_script.

Build script will run the build process and create a minified and production-ready file. For any changes in src/ directory this script will need to be rerun.

To run this script, go back to the terminal and enter:

	npm run build

For active development on a project, it is recommended to use start script. It will start an ongoing build process and build a new compiled file on every change in src/ directory. The compiled file will not have minified code, and any errors in JS code will pause that process (fixing those errors will resume it).

To run it, write the following:

	npm start

Once we know how to run build processes, we can start building the rest of the JS file structure in the src/ directory. You can split each functionality in separate directories, but all of them need to be included in index.js file.

Let’s look at a real-world example of registering a custom block:

	// src/blocks/custom-block/index.js

import { registerBlockType } from ’@wordpress/blocks’;
import { customBlockEdit } from ’./edit’;
import { customBlockSave } from ’./save’;

export customBlockInit () => {
  registerBlockType(’custom-namespace/custom-block’, {
    title: ’Custom Block’,
    icon: ’heading’,
    category: ’common’,
    edit: () => customBlockEdit(),
    save: () => customBlockSave(),
  } );
}

// src/index.js

import { customBlockInit } from ’./blocks/custom-block’;

customBlockInit();

These examples on importing and exporting modules are just the start of the modernization process of JS code in WordPress projects. After the code has been written, it is a good thing to make sure that it is written well and is following some coding standard. Other scripts form @wordpress/scripts package will help us with that.

Other features and extending features

Building JS files is not the only feature this package enables. With @wordpress/scripts it is possible to lint and format JS, CSS files.

To add linting and formating scripts, we need to update the scripts property of package.json file:

	"scripts": {
    "lint:js": "wp-scripts lint-js",
    "lint:js:src": "wp-scripts lint-js ./src"
    "lint:style": "wp-scripts lint-style",
    "lint:css:src": "wp-scripts lint-style ’src/**/*.css’"
    "format:js": "wp-scripts format-js",
    "format:js:src": "wp-scripts format-js ./src"
}

Commands lint:js and lint:style will go through the entire project and lint all JS and CSS files that they find and lint:js:src and lint:css:src will only lint files in src/ directory. Default linting rules for JS files are located in @wordpress/eslint-plugin npm package and for CSS in stylelint-config-wordpress package.

These default linting rulesets can be overridden to accommodate all coding preferences. Manually fixing errors and warnings reported by the linting process can be tedious, but there is a neat tool for JS files. We can format the JS files to adhere to the same coding standards with the format:js and format:js:src scripts.

Last major thing that @wordpress/scripts can do is running unit and end-to-end tests on JS files. Tests should be located in spec/ directory or have a .spec.js suffix for E2E tests and in test/ directory or have a .test.js suffix for unit tests. All tests are run by Jest in addition to Puppeteer for E2E tests.

To enable testing scripts update package.json file:

	"scripts": {
    "test:e2e": "wp-scripts test-e2e",
    "test:unit": "wp-scripts test-unit-js"
}

Extending the webpack configuration

All of these scripts are powered by webpack, that can do a lot more things than what is covered by @wordpress/package scripts. It is possible to add additional, project-specific, features while keeping all the functions of the initial package.

Extending WordPress webpack configuration starts with creating a webpack.config.js file in the root of the project (where package.json file is located), then importing default configuration and adding parts of the default configuration in new, custom configuration. It is mostly done by using the JS spread operator.

Here’s an example:

	const defaultConfig = require("@wordpress/scripts/config/webpack.config");

module.exports = {
  ...defaultConfig,
  module: {
    ...defaultConfig.module,
    rules: [
      ...defaultConfig.module.rules,
      {
        test: /\.custom-pattern$/,
        use: ["custom-webpack-package"]
      },
    ]
  }
};

One step towards more modern WordPress themes

@wordpress/scripts was developed to be a good starting point in modernization of the JS code in WordPress, introducing asset building, linting and testing to every project.

It’s an easy configuration for those who want to dip their toes in custom block development, and have no prior experience with ESNext syntax.

One thing that could be problematic while using @wordpress/scripts is the size of the node_modules folder. Because the package supports running E2E tests, Chromium is required for running those tests. Its size inflates the total size of the node_modules folder to around 400+ MB. For some users, that could be too much bloat for something that is not even planned to be used.

Nevertheless, this package is a step in the right direction for creating more modern WordPress themes or plugins and enforcing good coding practices.