Skip to content

Commit

Permalink
Docs: Update JavaScript build and setup with wp-scripts updates (#14440)
Browse files Browse the repository at this point in the history
  • Loading branch information
mkaz authored and youknowriad committed Mar 20, 2019
1 parent 99309c4 commit 4a7497f
Showing 1 changed file with 22 additions and 100 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ Most browsers can not interpret or run ESNext and JSX syntaxes, so we use a tran

There are a few reasons to use ESNext and the extra step. First, it makes for simpler code that is easier to read and write. Using a transformation step allows for tools to optimize the code to work on the widest variety of browsers. Also, by using a build step you can organize your code into smaller modules and files that can be bundled together into a single download.

There are many tools that can perform this transformation or build step, but in this tutorial we will focus on Webpack and Babel.
There are different tools that can perform this transformation or build step, but WordPress uses Webpack and Babel.

[Webpack](https://webpack.js.org/) is a pluggable tool that processes JavaScript creating a compiled bundle that runs in a browser. [Babel](https://babeljs.io/) transforms JavaScript from one format to another. You use Babel as a plugin to Webpack to transform both ESNext and JSX to JavaScript.

The [@wordpress/scripts](https://www.npmjs.com/package/@wordpress/scripts) package abstracts these libraries away to standardize and simplify development, so you won't need to handle the details for configuring those libraries.

## Quick Start

For a quick start, you can use one of the examples from the [Gutenberg Examples repository](https://github.com/wordpress/gutenberg-examples/). Each one of the `-esnext` directories contain the necessary files for working with ESNext and JSX.
Expand All @@ -38,6 +40,7 @@ To start a new node project, first create a directory to work in.

```
mkdir myguten-block
cd myguten-block
```

You create a new package.json running `npm init` in your terminal. This will walk you through creating your package.json file:
Expand All @@ -48,7 +51,7 @@ npm init
package name: (myguten-block) myguten-block
version: (1.0.0)
description: Test block
entry point: (index.js) block.js
entry point: (index.js) build/index.js
test command:
git repository:
keywords:
Expand Down Expand Up @@ -76,76 +79,23 @@ Is this OK? (yes) yes

The next step is to install the packages required. You can install packages using the npm command `npm install`. If you pass the `--save-dev` parameter, npm will write the package as a dev dependency in the package.json file. The `--save-exact` parameter instructs npm to save an exact version of a dependency, not a range of valid versions. See [npm install documentation](https://docs.npmjs.com/cli/install) for more details.

Run `npm install --save-dev --save-exact webpack webpack-cli`
Run `npm install --save-dev --save-exact @wordpress/scripts`

After installing, a `node_modules` directory is created with the webpack module and its dependencies.
After installing, a `node_modules` directory is created with the modules and their dependencies.

Also, if you look at package.json file it will include a new section:

```json
"dependencies": {
"webpack": "4.29.0"
"@wordpress/scripts": "3.1.0"
}
```

## Webpack & Babel

Next, we will configure webpack to process the `block.js` file and run babel to transform the JSX within it.

Create the file `webpack.config.js`

```js
// sets mode webpack runs under
const NODE_ENV = process.env.NODE_ENV || 'development';

module.exports = {
mode: NODE_ENV,

// entry is the source script
entry: './block.js',

// output is where to write the built file
output: {
path: __dirname,
filename: 'block.build.js',
},
module: {
// the list of rules used to process files
// this looks for .js files, exclude files
// in node_modules directory, and uses the
// babel-loader to process
rules: [
{
test: /.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
},
],
},
};
```

Next, you need to install babel, the webpack loader, and the JSX plugin using:

`npm install --save-dev --save-exact babel-loader @babel/core @babel/plugin-transform-react-jsx`

You configure babel by creating a `.babelrc` file:

```json
{
"plugins": [
[ "@babel/plugin-transform-react-jsx", {
"pragma": "wp.element.createElement"
} ]
]
}
```

This pragma setting instructs Babel that any JSX syntax such as `<Hello />` should be transformed into `wp.element.createElement( Hello )`. The name of the setting (`transform-react-jsx`) is derived from the fact that it overrides the default assumption to transform to `React.createElement( Hello )`.

With both configs in place, you can now run webpack.
The `@wordpress/scripts` package handles the dependencies and default configuration for Webpack and Babel. The scripts package expects the source file to compile to be found at `src/index.js`, and will save the compiled output to `build/index.js`.

First you need a basic block.js to build. Create `block.js` with the following content:
With that in mind, let's set up a basic block. Create a file at `src/index.js` with the following content:

```js
const { registerBlockType } = wp.blocks;
Expand All @@ -154,84 +104,56 @@ registerBlockType( 'myguten/test-block', {
title: 'Basic Example',
icon: 'smiley',
category: 'layout',
edit() {
return <div>Hola, mundo!</div>;
},
save() {
return <div>Hola, mundo!</div>;
},
edit: () => <div>Hola, mundo!</div>,
save: () => <div>Hola, mundo!</div>,
} );
```

To configure npm to run a script, you use the scripts section in `package.json` webpack:

```json
"scripts": {
"build": "webpack"
"build": "wp-scripts build"
},
```

You can then run the build using: `npm run build`.

After the build finishes, you will see the built file created at `block.build.js`.
After the build finishes, you will see the built file created at `build/index.js`.

## Finishing Touches

### Development Mode

The basics are in place to build. You might have noticed the webpack.config.js sets a default mode of "development". Webpack can also run in a "production" mode, which shrinks the code down so it downloads faster, but makes it difficult to read.
The **build** command in `@wordpress/scripts` runs in a "production" mode. This shrinks the code down so it downloads faster, but makes it difficult to read in the process. You can use the **start** command which runs a development mode that does not shrink the code, and additionally continues a running process to watch the source file for more changes and rebuild as you develop.

The mode is setup so it can be configured using environment variables, which can be added in the scripts section of `package.json`.
The start command can be added to the same scripts section of `package.json`:

```json
"scripts": {
"dev": "webpack --watch",
"build": "cross-env NODE_ENV=production webpack"
"start": "wp-scripts start",
"build": "wp-scripts build"
},
```

This sets the environment variables, but different environments handle these settings in different ways. Using the `cross-env` helper module can help to handle this. Be sure to install the `cross-env` package using `npm install --save-dev --save-exact cross-env`.

Additionally, webpack has a `--watch` flag that will keep the process running, watching for any changes to the `block.js` file and re-building as changes occur. This is useful during development, when you might have a lot of changes in progress.

You can start the watcher by running `npm run dev` in a terminal. You can then edit away in your text editor; after each save, webpack will automatically build. You can then use the familiar edit/save/reload development process.
Now, when you run `npm run start` a watcher will run in the terminal. You can then edit away in your text editor; after each save, it will automatically build. You can then use the familiar edit/save/reload development process.

**Note:** keep an eye on your terminal for any errors. If you make a typo or syntax error, the build will fail and the error will be in the terminal.

### Babel Browser Targeting

Babel has the ability to build JavaScript using rules that target certain browsers and versions. By setting a reasonable set of modern browsers, Babel can optimize the JavaScript it generates.

WordPress has a preset default you can use to target the minimum supported browsers by WordPress.

Install the module using: `npm install --save-dev --save-exact @wordpress/babel-preset-default`

You then update `.babelrc` by adding a "presets" section:

```
{
"presets": [ "@wordpress/babel-preset-default" ],
"plugins": [
[ "@babel/plugin-transform-react-jsx", {
"pragma": "wp.element.createElement"
} ]
]
}
```

### Source Control

Because a typical `node_modules` folder will contain thousands of files that change with every software update, you should exclude `node_modules/` from your source control. If you ever start from a fresh clone, simply run `npm install` in the same folder your `package.json` is located to pull your required packages.

Likewise, you do not need to include `node_modules` or any of the above configuration files in your plugin because they will be bundled inside the file that webpack builds. **Be sure to enqueue the `block.build.js` file** in your plugin PHP. This is the only JavaScript file needed for your block to run.
Likewise, you do not need to include `node_modules` or any of the above configuration files in your plugin because they will be bundled inside the file that webpack builds. **Be sure to enqueue the `build/index.js` file** in your plugin PHP. This is the only JavaScript file needed for your block to run.

## Summary

Yes, the initial setup is rather tedious, and there are a number of different tools and configs to learn. However, as the quick start alluded to, copying an existing config is the typical way most people start.
Yes, the initial setup is a bit more involved, but the additional features and benefits are usually worth the trade off in setup time.

With a setup in place, the standard workflow is:

- Install dependencies: `npm install`
- Start development builds: `npm run dev`
- Start development builds: `npm run start`
- Develop. Test. Repeat.
- Create production build: `npm run build`

0 comments on commit 4a7497f

Please sign in to comment.