Skip to content

Commit c9357bf

Browse files
authored
Add JavaScript Documentation around setting up Webpack, Babel, and Building (#13629)
* Add JS Build Setup * Update docs/designers-developers/developers/tutorials/javascript/js-build-setup.md Co-Authored-By: mkaz <marcus@mkaz.com> * Whitespace and code brackets * Update with better npm install instructions using --save-dev * Update docs/designers-developers/developers/tutorials/javascript/versions-and-building.md Co-Authored-By: mkaz <marcus@mkaz.com> * Update docs/designers-developers/developers/tutorials/javascript/js-build-setup.md Co-Authored-By: mkaz <marcus@mkaz.com> * Updates node, cli, and pragma per review * Update why to use ESNext * Apply suggestions from code review Co-Authored-By: mkaz <marcus@mkaz.com> * Apply suggestions from code review Co-Authored-By: mkaz <marcus@mkaz.com>
1 parent 1481251 commit c9357bf

File tree

4 files changed

+299
-52
lines changed

4 files changed

+299
-52
lines changed
Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
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`

docs/designers-developers/developers/tutorials/javascript/versions-and-building.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ ES5 code is compatible with WordPress's minimum [target for browser support](htt
66

77
"ESNext" doesn't refer to a specific version of JavaScript, but is "dynamic" and refers to the next language definitions, whatever they might be. Because some browsers won't support these features yet (because they're new or proposed), an extra build step is required to transform the code to a syntax that works in all browsers. Webpack and babel are the tools that perform this transformation step.
88

9-
Additionally, the ESNext code examples in the Gutenberg handbook include [JSX syntax](https://reactjs.org/docs/introducing-jsx.html), a syntax that blends HTML and JavaScript. It makes it easier to read and write markup code, but likewise requires the build step using webpack and babel to transform into compatible code.
9+
Additionally, the ESNext code examples in the Gutenberg handbook include [JSX syntax](https://reactjs.org/docs/introducing-jsx.html), a syntax that blends HTML and JavaScript. It makes it easier to read and write markup code, but likewise requires the build step using Webpack and Babel to transform into compatible code.
10+
11+
For simplicity, the JavaScript tutorial uses the ES5 definition, without JSX. This code can run straight in your browser and does not require an additional build step. In many cases, it will be perfectly fine to follow the same approach to quickly start experimenting with your plugin or theme. As soon as your codebase grows to hundreds of lines it might be a good idea to get familiar with the [JavaScript Build Setup documentation](/docs/designers-developers/developers/tutorials/javascript/js-build-setup.md) for setting up a development environment to use ESNext syntax.
1012

11-
For simplicity, this tutorial uses the ES5 definition of JavaScript, without JSX. This code can run straight in your browser and does not require an additional build step.

docs/manifest.json

Lines changed: 48 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -161,48 +161,6 @@
161161
"markdown_source": "https://raw.githubusercontent.com/WordPress/gutenberg/master/docs/designers-developers/developers/tutorials/readme.md",
162162
"parent": "developers"
163163
},
164-
{
165-
"title": "Blocks",
166-
"slug": "block-tutorial",
167-
"markdown_source": "https://raw.githubusercontent.com/WordPress/gutenberg/master/docs/designers-developers/developers/tutorials/block-tutorial/readme.md",
168-
"parent": "tutorials"
169-
},
170-
{
171-
"title": "Writing Your First Block Type",
172-
"slug": "writing-your-first-block-type",
173-
"markdown_source": "https://raw.githubusercontent.com/WordPress/gutenberg/master/docs/designers-developers/developers/tutorials/block-tutorial/writing-your-first-block-type.md",
174-
"parent": "block-tutorial"
175-
},
176-
{
177-
"title": "Applying Styles From a Stylesheet",
178-
"slug": "applying-styles-with-stylesheets",
179-
"markdown_source": "https://raw.githubusercontent.com/WordPress/gutenberg/master/docs/designers-developers/developers/tutorials/block-tutorial/applying-styles-with-stylesheets.md",
180-
"parent": "block-tutorial"
181-
},
182-
{
183-
"title": "Introducing Attributes and Editable Fields",
184-
"slug": "introducing-attributes-and-editable-fields",
185-
"markdown_source": "https://raw.githubusercontent.com/WordPress/gutenberg/master/docs/designers-developers/developers/tutorials/block-tutorial/introducing-attributes-and-editable-fields.md",
186-
"parent": "block-tutorial"
187-
},
188-
{
189-
"title": "Block Controls: Toolbars and Inspector",
190-
"slug": "block-controls-toolbars-and-inspector",
191-
"markdown_source": "https://raw.githubusercontent.com/WordPress/gutenberg/master/docs/designers-developers/developers/tutorials/block-tutorial/block-controls-toolbars-and-inspector.md",
192-
"parent": "block-tutorial"
193-
},
194-
{
195-
"title": "Creating dynamic blocks",
196-
"slug": "creating-dynamic-blocks",
197-
"markdown_source": "https://raw.githubusercontent.com/WordPress/gutenberg/master/docs/designers-developers/developers/tutorials/block-tutorial/creating-dynamic-blocks.md",
198-
"parent": "block-tutorial"
199-
},
200-
{
201-
"title": "Generate Blocks with WP-CLI",
202-
"slug": "generate-blocks-with-wp-cli",
203-
"markdown_source": "https://raw.githubusercontent.com/WordPress/gutenberg/master/docs/designers-developers/developers/tutorials/block-tutorial/generate-blocks-with-wp-cli.md",
204-
"parent": "block-tutorial"
205-
},
206164
{
207165
"title": "Getting Started with JavaScript",
208166
"slug": "javascript",
@@ -245,6 +203,54 @@
245203
"markdown_source": "https://raw.githubusercontent.com/WordPress/gutenberg/master/docs/designers-developers/developers/tutorials/javascript/scope-your-code.md",
246204
"parent": "javascript"
247205
},
206+
{
207+
"title": "JavaScript Build Setup",
208+
"slug": "js-build-setup",
209+
"markdown_source": "https://raw.githubusercontent.com/WordPress/gutenberg/master/docs/designers-developers/developers/tutorials/javascript/js-build-setup.md",
210+
"parent": "javascript"
211+
},
212+
{
213+
"title": "Blocks",
214+
"slug": "block-tutorial",
215+
"markdown_source": "https://raw.githubusercontent.com/WordPress/gutenberg/master/docs/designers-developers/developers/tutorials/block-tutorial/readme.md",
216+
"parent": "tutorials"
217+
},
218+
{
219+
"title": "Writing Your First Block Type",
220+
"slug": "writing-your-first-block-type",
221+
"markdown_source": "https://raw.githubusercontent.com/WordPress/gutenberg/master/docs/designers-developers/developers/tutorials/block-tutorial/writing-your-first-block-type.md",
222+
"parent": "block-tutorial"
223+
},
224+
{
225+
"title": "Applying Styles From a Stylesheet",
226+
"slug": "applying-styles-with-stylesheets",
227+
"markdown_source": "https://raw.githubusercontent.com/WordPress/gutenberg/master/docs/designers-developers/developers/tutorials/block-tutorial/applying-styles-with-stylesheets.md",
228+
"parent": "block-tutorial"
229+
},
230+
{
231+
"title": "Introducing Attributes and Editable Fields",
232+
"slug": "introducing-attributes-and-editable-fields",
233+
"markdown_source": "https://raw.githubusercontent.com/WordPress/gutenberg/master/docs/designers-developers/developers/tutorials/block-tutorial/introducing-attributes-and-editable-fields.md",
234+
"parent": "block-tutorial"
235+
},
236+
{
237+
"title": "Block Controls: Toolbars and Inspector",
238+
"slug": "block-controls-toolbars-and-inspector",
239+
"markdown_source": "https://raw.githubusercontent.com/WordPress/gutenberg/master/docs/designers-developers/developers/tutorials/block-tutorial/block-controls-toolbars-and-inspector.md",
240+
"parent": "block-tutorial"
241+
},
242+
{
243+
"title": "Creating dynamic blocks",
244+
"slug": "creating-dynamic-blocks",
245+
"markdown_source": "https://raw.githubusercontent.com/WordPress/gutenberg/master/docs/designers-developers/developers/tutorials/block-tutorial/creating-dynamic-blocks.md",
246+
"parent": "block-tutorial"
247+
},
248+
{
249+
"title": "Generate Blocks with WP-CLI",
250+
"slug": "generate-blocks-with-wp-cli",
251+
"markdown_source": "https://raw.githubusercontent.com/WordPress/gutenberg/master/docs/designers-developers/developers/tutorials/block-tutorial/generate-blocks-with-wp-cli.md",
252+
"parent": "block-tutorial"
253+
},
248254
{
249255
"title": "Meta Boxes",
250256
"slug": "metabox",

docs/toc.json

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,15 @@
3030
{"docs/designers-developers/developers/backward-compatibility/meta-box.md": []}
3131
]},
3232
{"docs/designers-developers/developers/tutorials/readme.md": [
33+
{"docs/designers-developers/developers/tutorials/javascript/readme.md": [
34+
{"docs/designers-developers/developers/tutorials/javascript/plugins-background.md": []},
35+
{"docs/designers-developers/developers/tutorials/javascript/loading-javascript.md": []},
36+
{"docs/designers-developers/developers/tutorials/javascript/extending-the-block-editor.md": []},
37+
{"docs/designers-developers/developers/tutorials/javascript/troubleshooting.md": []},
38+
{"docs/designers-developers/developers/tutorials/javascript/versions-and-building.md": []},
39+
{"docs/designers-developers/developers/tutorials/javascript/scope-your-code.md": []},
40+
{"docs/designers-developers/developers/tutorials/javascript/js-build-setup.md": []}
41+
]},
3342
{"docs/designers-developers/developers/tutorials/block-tutorial/readme.md" :[
3443
{"docs/designers-developers/developers/tutorials/block-tutorial/writing-your-first-block-type.md" :[]},
3544
{"docs/designers-developers/developers/tutorials/block-tutorial/applying-styles-with-stylesheets.md" :[]},
@@ -38,14 +47,6 @@
3847
{"docs/designers-developers/developers/tutorials/block-tutorial/creating-dynamic-blocks.md" :[]},
3948
{"docs/designers-developers/developers/tutorials/block-tutorial/generate-blocks-with-wp-cli.md" :[]}
4049
]},
41-
{"docs/designers-developers/developers/tutorials/javascript/readme.md": [
42-
{"docs/designers-developers/developers/tutorials/javascript/plugins-background.md": []},
43-
{"docs/designers-developers/developers/tutorials/javascript/loading-javascript.md": []},
44-
{"docs/designers-developers/developers/tutorials/javascript/extending-the-block-editor.md": []},
45-
{"docs/designers-developers/developers/tutorials/javascript/troubleshooting.md": []},
46-
{"docs/designers-developers/developers/tutorials/javascript/versions-and-building.md": []},
47-
{"docs/designers-developers/developers/tutorials/javascript/scope-your-code.md": []}
48-
]},
4950
{"docs/designers-developers/developers/tutorials/metabox/readme.md": [
5051
{"docs/designers-developers/developers/tutorials/metabox/meta-block-1-intro.md": []},
5152
{"docs/designers-developers/developers/tutorials/metabox/meta-block-2-register-meta.md": []},

0 commit comments

Comments
 (0)