Skip to content

docs(guides): rewrite of development.md #1405

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Jul 15, 2017
Merged
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
295 changes: 180 additions & 115 deletions content/guides/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,182 +5,247 @@ contributors:
- SpaceK33z
- rafde
- fvgs
- TheDutchCoder
---

On this page we'll explain how to get started with developing and how to choose one of three tools to develop. It is assumed you already have a webpack configuration file.
T> This guide uses examples from the [`Webpack Guides Code Examples`](https://github.com/TheDutchCoder/webpack-guides-code-examples) repo.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe hold off on mentioning this yet -- but definitely mention which guide is the prerequisite for this one if there is one.


W> Never use any of these tools in production. Ever.
If you've been following the guides, you should have a solid understanding of some of the webpack basics. Before we continue, let's look into setting up a development environment to make our lives a little easier.

W> The tools in this guide are meant for development **only**, do not ever use them in production!
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might sound better as:

The tools in this guide are __only meant for development___, please __avoid__ using them in production!


## Adjusting Your Text Editor

Some text editors have a "safe write" feature and enable this by default. As a result, saving a file will not always result in a recompile.
## Using Source Maps

Each editor has a different way of disabling this. For the most common ones:
When webpack creates bundles from your code, it can become difficult to track down errors and warnings in your JavaScript. For example, if you bundle three source files (`a.js`, `b.js`, and `c.js`) into one bundle (`bundle.js`) and one of the source files contains an error, you will see the error in your console coming from `bundle.js` which isn't always very helpful (you want to know which source file the error came from).
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rephrase this as:

When webpack bundles your source code, it can become difficult to track down errors and warnings to their original location. For example, if you bundle three source files (a.js, b.js, and c.js) into one bundle (bundle.js) and one of the source files contains an error, the stack trace will simply point to bundle.js. This isn't always very helpful as you probably want to know exactly which source file the error came from.


* **Sublime Text 3** - Add `"atomic_save": false` to your user preferences.
* **IntelliJ** - use search in the preferences to find "safe write" and disable it.
* **Vim** - add `:set backupcopy=yes` in your settings.
* **WebStorm** - uncheck `Use "safe write"` in Preferences > Appearance & Behavior > System Settings
In order to make it easier to track down errors and warnings, JavaScript offers Source Maps, which maps your compiled code back to your original source code. So if an error originates from `b.js`, the Source Map will tell you exactly that.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/s/So if/If


There are a lot of [different options](/configuration/devtool) available when it comes to Source Maps, be sure to check them out so you can configure them to your needs.

## Source Maps
For this guide, let's use the `inline-source-map` option, which is good for illustrative purposes(but don't use it in production):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're missing a space between purposes and the ( but I would also rephrase slightly:

For this guide, let's use the inline-source-map option, which is good for illustrative purposes (though not for production):


When a JavaScript exception occurs, you'll often want to know what file and line is generating this error. Since webpack outputs files into one or more bundles, it can be inconvenient to trace the file.
__webpack.config.js__

**Source maps** intend to fix this problem. There are a lot of [different options](/configuration/devtool) - each with their own advantages and disadvantages. To get started, we'll use this one:
``` diff
var path = require('path');

```js
devtool: "cheap-eval-source-map"
module.exports = {
entry: {
app: './src/index.js',
print: './src/print.js'
},
devtool: 'cheap-eval-source-map',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you mentioned inline-source-map above but ended up using a different one here. One way or the other, they should sync up.

output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
```

Now let's make sure we have something to debug, so let's create an error in our `print.js` file:

## Choosing a Tool

webpack can be used with **watch mode**. In this mode webpack will watch your files, and recompile when they change.
**webpack-dev-server** provides an easy to use development server with fast live reloading. If you already have a development server and want full flexibility, **webpack-dev-middleware** can be used as middleware.

webpack-dev-server and webpack-dev-middleware use in-memory compilation, meaning that the bundle will not be saved to disk. This makes compiling faster and results in less mess on your file system.

In most cases **you'll want to use webpack-dev-server**, since it's the easiest to get started with and offers much functionality out-of-the-box.


### webpack Watch Mode

webpack's watch mode watches files for changes. If any change is detected, it'll run the compilation again.
__src/print.js__

We also want a nice progress bar while it's compiling. Let's run the command:

```bash
webpack --progress --watch
``` diff
export default function printMe() {
- console.log('I get called from print.js!');
+ cosnole.log('I get called from print.js!');
}
```

Make a change in one of your files and hit save. You should see that it's recompiling.

Watch mode makes no assumptions about a server, so you will need to provide your own. An easy server to use is [`serve`](https://github.com/zeit/serve). After installing (`npm install --save-dev serve`), you can run it in the directory where the outputted files are:

```bash
`npm bin`/serve
Run an `npm run build`, it should compile to something like this:

``` bash
Hash: 7bf68ca15f1f2690e2d1
Version: webpack 3.1.0
Time: 1224ms
Asset Size Chunks Chunk Names
app.bundle.js 1.44 MB 0, 1 [emitted] [big] app
print.bundle.js 6.43 kB 1 [emitted] print
index.html 248 bytes [emitted]
[0] ./src/print.js 84 bytes {0} {1} [built]
[1] ./src/index.js 403 bytes {0} [built]
[3] (webpack)/buildin/global.js 509 bytes {0} [built]
[4] (webpack)/buildin/module.js 517 bytes {0} [built]
+ 1 hidden module
Child html-webpack-plugin for "index.html":
[2] (webpack)/buildin/global.js 509 bytes {0} [built]
[3] (webpack)/buildin/module.js 517 bytes {0} [built]
+ 2 hidden modules
```

You may find it more convenient to run `serve` using npm scripts. You can do so by first creating a `start` script in `package.json` as follows:
Now open the resulting `index.html` file in your browser. Click the button and look in your console where the error is displayed. The error should say something like this:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra space at the beginning of the sentence.


```json
...
"scripts": {
"start": "serve"
}
...
```
```
Uncaught ReferenceError: cosnole is not defined
at HTMLButtonElement.printMe (print.js:2)
```

You can then start the server by running `npm start` from within your project directory. After each compilation, you will need to manually refresh your browser to see the changes.
We can see that the error also contains a reference to the file (`print.js`) and line number (2) where the error occurred. This is great, because now we know exactly where to look to fix the issue.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra space at the beginning again.


T> You may find the `--single` option useful for serving single page apps.

## Choosing a Development Tool

### Watch Mode with Chrome DevTools Workspaces
W> Some text editors have a "safe write" function that might interfere with some of the following tools. Read [`Adjusting Your text Editor`](#adjusting-your-text-editor) for a solution to these issue.

If you set up Chrome to [persist changes when saving from the _Sources_ panel](https://medium.com/@rafaelideleon/webpack-your-chrome-devtools-workspaces-cb9cca8d50da)
so you don't have to refresh the page, you will have to setup webpack to use
It quickly becomes a hassle to manually run `npm run build` everytime you want to compile your code.

```javascript
devtool: "inline-source-map"
```
There are a couple of different options available in webpack that help you automatically compile your code whenever it changes:

to continue editing and saving your changes from Chrome or source files.
1. webpack's Watch Mode
2. webpack-dev-server
3. webpack-dev-middlware
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

webpack-dev-middlware => webpack-dev-middleware


There are some _gotchas_ about using workspaces with watch:
In most cases, you probably would want to use `webpack-dev-server`, but let's explore all of the above options.

* Large chunks (such as a common chunk that is over 1MB) that are rebuilt could cause the page to blank, which will force you to refresh the browser.
* Smaller chunks will be faster to build than larger chunks since `inline-source-map` is slower due to having to base64 encode the original source code.

### Using Webpack Watch Mode
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would leave "Webpack" out here, above, and below... probably webpack --watch in the list, "Using Watch Mode" in the title and on line 105 just saying:

You can instruct webpack to "watch" all files within your dependency graph for changes. If one of these files is updated, the code will be recompiled so you don't have to run the full build manually.


### webpack-dev-server
Webpack's Watch Mode allows you to watch a set of files for changing. Webpack will then automatically recompile your code for you, so you don't have to do this manually.

webpack-dev-server provides you with a server and live reloading. This is easy to setup.
Let's add an npm script that will start webpack's Watch Mode:

To prepare, make sure you have a `index.html` file that points to your bundle. Assuming that `output.filename` is `bundle.js`:
__package.json__

```html
<script src="/bundle.js"></script>
``` diff
{
"name": "asset-management",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe change this to "development"?

"version": "1.0.0",
"description": "",
"main": "webpack.config.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
+ "watch": "webpack --progress --watch",
"build": "webpack"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"css-loader": "^0.28.4",
"csv-loader": "^2.1.1",
"file-loader": "^0.11.2",
"html-webpack-plugin": "^2.29.0",
"style-loader": "^0.18.2",
"webpack": "^3.0.0",
"xml-loader": "^1.2.1"
}
}
```

Start with installing `webpack-dev-server` from npm:
Now you can run `npm run watch` from the command line and you will see that webpack compiles your code, but it doesn't exit to the command line (this is because the script is still watching your files).
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably better as:

You can now run npm run watch from the command line to see that webpack compiles your code, but doesn't exit to the command line. This is because the script is still watching your files.


```bash
npm install --save-dev webpack-dev-server
```
Let's make some changes to our code (let's remove the error we introduced):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about:

Now, with webpack watching, let's remove the error we introduced:


When it's done installing, you should be able to use `webpack-dev-server` like this:
__src/print.js__

```bash
webpack-dev-server --open
``` diff
export default function printMe() {
- cosnole.log('I get called from print.js!');
+ console.log('I get called from print.js!');
}
```

T> If your console says it can't find the command, try running `node_modules/.bin/webpack-dev-server`. Optimally you would add the command to your `package.json`, like this: `"scripts": { "start": "webpack-dev-server" }`.

The command above should automatically open your browser on `http://localhost:8080`.

Make a change in one of your files and hit save. You should see that the console is recompiling. After that's done, the page should be refreshed. If nothing happens in the console, you may need to fiddle with [`watchOptions`](/configuration/dev-server#devserver-watchoptions-).

Now you have live reloading working, you can take it even a step further: Hot Module Replacement. This is an interface that makes it possible to swap modules **without a page refresh**. See the [Hot Module Replacement guide](/guides/hot-module-replacement) for more information.
Now save your file and watch your command line, you should see webpack automatically recompile your code (but only the affected files)!
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now save your file and keep an eye on the terminal window. You should see webpack automatically recompile the changed module!


By default **inline mode** is used. This mode injects the client - needed for live reloading and showing build errors - in your bundle. With inline mode you will get build errors and warnings in your DevTools console.
The only downside is that you have te refresh your browser in order to see the changes. It would be much nicer if that would happen automatically as well, so let's take care of that.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/s/te/to

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also maybe instead of "so let's take care of that", say something like "so let's try webpack-dev-server".


webpack-dev-server can do many more things such as proxying requests to your backend server. For more configuration options, see the [**devServer documentation**](/configuration/dev-server).

### Using webpack-dev-server

### webpack-dev-middleware
The `webpack-dev-server` provides you with a simple web server and the ability to use live reloading. Let's set it up:

webpack-dev-middleware works for connect-based middleware stacks. This can be useful if you already have a Node.js server or if you want to have full control over the server.

The middleware will cause webpack to compile files in-memory. When a compilation is running, it will delay the request to a file until the compilation is done.

W> This is intended for advanced users. webpack-dev-server is much easier to use.
``` bash
npm install --save-dev webpack-dev-server
```

Start with installing the dependencies from npm:
Change your config file to tell the dev server where to look for files:

__webpack.config.js__

``` diff
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
entry: {
app: './src/index.js',
print: './src/print.js'
},
devtool: 'inline-source-map',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure you keep this in sync with whatever you decide above. Also it seems like this config changed a lot more (at least with the HtmlWebpackPlugin), maybe update the one above and be clear about which guide is the prequisite for this one.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this is probably not synced yet with my examples, will try to do that :)

+ devServer: {
+ contentBase: './dist'
+ },
plugins: [
new HtmlWebpackPlugin({
title: 'Development'
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
```

```bash
npm install --save-dev express webpack-dev-middleware
This tells the dev server to serve our files from the `dist` folder (where our files get generated) and serve them on `localhost:8080`.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could probably be simplified to:

This tells webpack-dev-server to serve the files from dist on localhost:8080.


Let's add a script to easily run the dev server as well:

__package.json__

``` diff
{
"name": "asset-management",
"version": "1.0.0",
"description": "",
"main": "webpack.config.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"watch": "webpack --progress --watch",
+ "server": "webpack-dev-server --open"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typically start is used. This allows you to just run npm start instead of the full npm run server.

"build": "webpack"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"css-loader": "^0.28.4",
"csv-loader": "^2.1.1",
"file-loader": "^0.11.2",
"html-webpack-plugin": "^2.29.0",
"style-loader": "^0.18.2",
"webpack": "^3.0.0",
"xml-loader": "^1.2.1"
}
}
```

After installing, you can use the middleware like this:
Now we can run `npm run server` from the command line and we will see our browser automatically loading up a new page (usually `localhost:8080`). If you now change any of the source files and save them, the web server will automatically reload after the code has been compiled. Give it a try!
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"usually localhost:8080"? Isn't it always localhost:8080?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough, it isn't in my case as I already run a dev server there and have to change the port, but it's 8080 out of the box of course. Will change! :)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless a port is specified, webpack-dev-server runs portfinder to find the first open port starting at 8080: https://github.com/webpack/webpack-dev-server/blob/140da4573c7d36771d2dae3e0925f66394b27522/bin/webpack-dev-server.js#L347-L362

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting, it would consistently fail on 8080 for me because there's my nginx proxy we use for docker.

Might be my setup though, so I took it out of the doc regardless :)

Thanks for explaining!


```js
var express = require("express");
var webpackDevMiddleware = require("webpack-dev-middleware");
var webpack = require("webpack");
var webpackConfig = require("./webpack.config");
The `webpack-dev-server` comes with many configurable options. Head over to the [`documentation`](/configuration/dev-server) to learn more.

var app = express();
var compiler = webpack(webpackConfig);
T> Now that your server is working, you might want to give [`Hot Module Replacement`](/guides/hot-module-replacement) a try. It's a logical next step!
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would leave off the last bit and just end the first sentence with the exclamation point, e.g.

... a try!


app.use(webpackDevMiddleware(compiler, {
publicPath: "/" // Same as `output.publicPath` in most cases.
}));

app.listen(3000, function () {
console.log("Listening on port 3000!");
});
```
### Using webpack-dev-middleware

Depending on what you've used in `output.publicPath` and `output.filename`, your bundle should now be available on `http://localhost:3000/bundle.js`.
W> This section is currently not working out of the box.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me give this some thought. webpack-dev-middleware is what webpack-dev-server uses under the hood so it could just be mentioned in that respect but a small example probably wouldn't be bad either.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I like an example here, as people might have a need for middleware.

I'll take another stab at it later (maybe it was my node version again)


By default, **watch mode** is used. It's also possible to use **lazy mode**, which will only recompile on a request to the entry point.

To compile only on a request to the entry `bundle.js`:
## Adjusting Your Text Editor

```js
app.use(webpackDevMiddleware(compiler, {
lazy: true,
filename: "bundle.js" // Same as `output.filename` in most cases.
}));
```
When using automatic compilation of your code, you could run into issues when saving your files. Some editors have a "safe write "feature that can potentially interfere with recompilation.

To disable this feature in some common editors, see the list below:

There are many more options you can use. For all configuration options, see the [**devServer documentation**](/configuration/dev-server).
* **Sublime Text 3** - Add `atomic_save: "false"` to your user preferences.
* **IntelliJ** - use search in the preferences to find "safe write" and disable it.
* **Vim** - add `:set backupcopy=yes` to your settings.
* **WebStorm** - uncheck Use `"safe write"` in `Preferences > Appearance & Behavior > System Settings`.


## References
## Conclusion
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra space?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Friggin auto formatting 😄


* [SurviveJS - Automatic Browser Refresh](http://survivejs.com/webpack/developing-with-webpack/automatic-browser-refresh/)
* [webpack your Chrome DevTools Workspaces](https://medium.com/@rafaelideleon/webpack-your-chrome-devtools-workspaces-cb9cca8d50da)
Now that you've learned how to automatically compile your code whenever you save a file, and how to run a simple development server, you can check out the next guide that covers [`Hot Module Replacement`](/guides/hot-module-replacement).
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra space?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can leave out the second "how to" in this sentence and probably the "whenever you save a file bit" as well...

Now that you've learned how to automatically compile your code and run a simple development server, you can check out...