|
| 1 | +# JavaScript Build Setup |
| 2 | + |
| 3 | +This page covers how to set up your development environment to use the ESNext syntax. ESNext is JavaScript code written using features that are only available in a specification greater than ECMAScript 5 (ES5 for short) or that includes a custom syntax such as [JSX](https://reactjs.org/docs/introducing-jsx.html). |
| 4 | + |
| 5 | +This documentation covers development for your plugin to work with Gutenberg. If you want to setup a development environment for developing Gutenberg itself, see the [CONTRIBUTING.md](https://github.com/WordPress/gutenberg/blob/master/CONTRIBUTING.md) documentation. |
| 6 | + |
| 7 | +Most browsers can not interpret or run ESNext and JSX syntaxes, so we use a transformation step to convert these syntaxes to code that browsers can understand. |
| 8 | + |
| 9 | +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. |
| 10 | + |
| 11 | +There are many tools that can perform this transformation or build step, but in this tutorial we will focus on Webpack and Babel. |
| 12 | + |
| 13 | +[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. |
| 14 | + |
| 15 | +## Quick Start |
| 16 | + |
| 17 | +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. |
| 18 | + |
| 19 | +## Setup |
| 20 | + |
| 21 | +Both Webpack and Babel are tools written in JavaScript and run using [Node.js](https://nodejs.org/) (node). Node.js is a runtime environment for JavaScript outside of a browser. Simply put, node allows you to run JavaScript code on the command-line. |
| 22 | + |
| 23 | +First, you need to set up node for your development environment. The steps required change depending on your operating system, but if you have a package manager installed, setup can be as straightforward as: |
| 24 | + |
| 25 | +- Ubuntu: `apt install node` |
| 26 | +- macOS: `brew install node` |
| 27 | +- Windows: `choco install node` |
| 28 | + |
| 29 | +Additionally, the [Node.js download page](https://nodejs.org/en/download/) includes installers and binaries. |
| 30 | + |
| 31 | +**Note:** The build tools and process occur on the command-line, so some basic familiarity using a terminal application is required. Some text editors have a terminal built-in which is fine to use; Visual Studio Code and PhpStorm are two popular options. |
| 32 | + |
| 33 | +### Node Package Manager (npm) |
| 34 | + |
| 35 | +The Node Package Manager (npm) is a tool included with node. npm allows you to install and manage JavaScript packages. npm can also generate and process a special file called `package.json`, which contains some information about your project and the packages your project uses. |
| 36 | + |
| 37 | +To start a new node project, first create a directory to work in. |
| 38 | + |
| 39 | +``` |
| 40 | +mkdir myguten-block |
| 41 | +``` |
| 42 | + |
| 43 | +You create a new package.json running `npm init` in your terminal. This will walk you through creating your package.json file: |
| 44 | + |
| 45 | +``` |
| 46 | +npm init |
| 47 | +
|
| 48 | +package name: (myguten-block) myguten-block |
| 49 | +version: (1.0.0) |
| 50 | +description: Test block |
| 51 | +entry point: (index.js) block.js |
| 52 | +test command: |
| 53 | +git repository: |
| 54 | +keywords: |
| 55 | +author: mkaz |
| 56 | +license: (ISC) GPL-2.0-only |
| 57 | +About to write to /home/mkaz/src/wp/scratch/package.json: |
| 58 | +
|
| 59 | +{ |
| 60 | + "name": "myguten-block", |
| 61 | + "version": "1.0.0", |
| 62 | + "description": "Test block", |
| 63 | + "main": "block.js", |
| 64 | + "scripts": { |
| 65 | + "test": "echo \"Error: no test specified\" && exit 1" |
| 66 | + }, |
| 67 | + "author": "mkaz", |
| 68 | + "license": "GPL-2.0-only" |
| 69 | +} |
| 70 | +
|
| 71 | +
|
| 72 | +Is this OK? (yes) yes |
| 73 | +``` |
| 74 | + |
| 75 | +### Using npm to install packages |
| 76 | + |
| 77 | +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. |
| 78 | + |
| 79 | +Run `npm install --save-dev webpack` |
| 80 | + |
| 81 | +After installing, a `node_modules` directory is created with the webpack module and its dependencies. |
| 82 | + |
| 83 | +Also, if you look at package.json file it will include a new section: |
| 84 | + |
| 85 | +```json |
| 86 | +"dependencies": { |
| 87 | + "webpack": "^4.29.0" |
| 88 | +} |
| 89 | +``` |
| 90 | + |
| 91 | +## Webpack & Babel |
| 92 | + |
| 93 | +Next, we will configure webpack to process the `block.js` file and run babel to transform the JSX within it. |
| 94 | + |
| 95 | +Create the file `webpack.config.js` |
| 96 | + |
| 97 | +```js |
| 98 | +// sets mode webpack runs under |
| 99 | +const NODE_ENV = process.env.NODE_ENV || 'development'; |
| 100 | + |
| 101 | +module.exports = { |
| 102 | + mode: NODE_ENV, |
| 103 | + |
| 104 | + // entry is the source script |
| 105 | + entry: './block.js', |
| 106 | + |
| 107 | + // output is where to write the built file |
| 108 | + output: { |
| 109 | + path: __dirname, |
| 110 | + filename: 'block.build.js', |
| 111 | + }, |
| 112 | + module: { |
| 113 | + // the list of rules used to process files |
| 114 | + // this looks for .js files, exclude files |
| 115 | + // in node_modules directory, and uses the |
| 116 | + // babel-loader to process |
| 117 | + rules: [ |
| 118 | + { |
| 119 | + test: /.js$/, |
| 120 | + exclude: /node_modules/, |
| 121 | + loader: 'babel-loader', |
| 122 | + }, |
| 123 | + ], |
| 124 | + }, |
| 125 | +}; |
| 126 | +``` |
| 127 | + |
| 128 | +Next, you need to install babel, the webpack loader, and the JSX plugin using: |
| 129 | + |
| 130 | +``` |
| 131 | +npm install --save babel-loader babel-core babel-plugin-transform-react-jsx |
| 132 | +``` |
| 133 | + |
| 134 | +You configure babel by creating a `.babelrc` file: |
| 135 | + |
| 136 | +``` |
| 137 | +{ |
| 138 | + "plugins": [ |
| 139 | + [ "transform-react-jsx", { |
| 140 | + "pragma": "wp.element.createElement" |
| 141 | + } ] |
| 142 | + ] |
| 143 | +} |
| 144 | +``` |
| 145 | + |
| 146 | +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 )`. |
| 147 | + |
| 148 | +With both configs in place, you can now run webpack. |
| 149 | + |
| 150 | +First you need a basic block.js to build. Create `block.js` with the following content: |
| 151 | + |
| 152 | +```js |
| 153 | +const { registerBlockType } = wp.blocks; |
| 154 | + |
| 155 | +registerBlockType( 'myguten/test-block', { |
| 156 | + title: 'Basic Example', |
| 157 | + icon: 'smiley', |
| 158 | + category: 'layout', |
| 159 | + edit() { |
| 160 | + return <div>Hola, mundo!</div>; |
| 161 | + }, |
| 162 | + save() { |
| 163 | + return <div>Hola, mundo!</div>; |
| 164 | + }, |
| 165 | +} ); |
| 166 | +``` |
| 167 | + |
| 168 | +To configure npm to run a script, you use the scripts section in `package.json` webpack: |
| 169 | + |
| 170 | +```json |
| 171 | + "scripts": { |
| 172 | + "build": "webpack" |
| 173 | + }, |
| 174 | +``` |
| 175 | + |
| 176 | +You can then run the build using: `npm run build`. |
| 177 | + |
| 178 | +After the build finishes, you will see the built file created at `block.build.js`. |
| 179 | + |
| 180 | +## Finishing Touches |
| 181 | + |
| 182 | +### Development Mode |
| 183 | + |
| 184 | +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. |
| 185 | + |
| 186 | +The mode is setup so it can be configured using environment variables, which can be added in the scripts section of `package.json`. |
| 187 | + |
| 188 | +```json |
| 189 | + "scripts": { |
| 190 | + "dev": "webpack --watch", |
| 191 | + "build": "cross-env NODE_ENV=production webpack" |
| 192 | + }, |
| 193 | +``` |
| 194 | + |
| 195 | +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 cross-env`. |
| 196 | + |
| 197 | +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. |
| 198 | + |
| 199 | +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. |
| 200 | + |
| 201 | +**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. |
| 202 | + |
| 203 | +### Babel Browser Targeting |
| 204 | + |
| 205 | +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. |
| 206 | + |
| 207 | +WordPress has a preset default you can use to target the minimum supported browsers by WordPress. |
| 208 | + |
| 209 | +Install the module using: `npm install --save @wordpress/babel-preset-default` |
| 210 | + |
| 211 | +You then update `.babelrc` by adding a "presets" section: |
| 212 | + |
| 213 | +``` |
| 214 | +{ |
| 215 | + "presets": [ "@wordpress/babel-preset-default" ], |
| 216 | + "plugins": [ |
| 217 | + [ "transform-react-jsx", { |
| 218 | + "pragma": "wp.element.createElement" |
| 219 | + } ] |
| 220 | + ] |
| 221 | +} |
| 222 | +``` |
| 223 | + |
| 224 | +### Source Control |
| 225 | + |
| 226 | +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. |
| 227 | + |
| 228 | +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. |
| 229 | + |
| 230 | +## Summary |
| 231 | + |
| 232 | +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. |
| 233 | + |
| 234 | +With a setup in place, the standard workflow is: |
| 235 | + |
| 236 | +- Install dependencies: `npm install` |
| 237 | +- Start development builds: `npm run dev` |
| 238 | +- Develop. Test. Repeat. |
| 239 | +- Create production build: `npm run build` |
0 commit comments