Skip to content

Commit

Permalink
Revise developing chapters
Browse files Browse the repository at this point in the history
Still splitting configuration chapter to go.
  • Loading branch information
bebraw committed Jan 18, 2017
1 parent d4300b1 commit 5946222
Show file tree
Hide file tree
Showing 7 changed files with 275 additions and 246 deletions.
58 changes: 28 additions & 30 deletions manuscript/developing_with_webpack/01_getting_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ module.exports = {

The `entry` path could be given as a relative one. The [context](https://webpack.js.org/configuration/entry-context/#context) field can be used to configure that lookup. Given plenty of places expect absolute paths, I prefer to use absolute paths everywhere to avoid confusion and keep it simple.

T> I will use **trailing commas** in the book examples on purpose as it gives cleaned diffs. I will show you how to enforce this in the *Linting JavaScript* chapter.
T> I use **trailing commas** in the book examples on purpose as it gives cleaner diffs for the code examples. I will show you how to enforce this rule in the *Linting JavaScript* chapter.

T> `[name]` is a placeholder. Placeholders are discussed in greater detail in the *Adding Hashes to Filenames* chapter.

Expand All @@ -149,27 +149,27 @@ T> I like to use `path.join`, but `path.resolve` would be a good alternative. Se
If you execute `node_modules/.bin/webpack`, you should see output:

```bash
Hash: dabda4c88d9b4a4dee76
Version: webpack 2.2.0-rc.3
Time: 390ms
Hash: d9b3a26d51481993359e
Version: webpack 2.2.0
Time: 375ms
Asset Size Chunks Chunk Names
app.js 3.06 kB 0 [emitted] app
app.js 3.12 kB 0 [emitted] app
index.html 180 bytes [emitted]
[0] ./app/component.js 135 bytes {0} [built]
[1] ./app/index.js 77 bytes {0} [built]
Child html-webpack-plugin for "index.html":
[0] ./~/lodash/lodash.js 540 kB {0} [built]
[1] (webpack)/buildin/global.js 506 bytes {0} [built]
[2] (webpack)/buildin/module.js 548 bytes {0} [built]
[1] (webpack)/buildin/global.js 509 bytes {0} [built]
[2] (webpack)/buildin/module.js 517 bytes {0} [built]
[3] ./~/html-webpack-plugin/lib/loader.js!./~/html-webpack-plugin/default_index.ejs 540 bytes {0} [built]
```

The output tells us a lot. I've annotated it below:

* `Hash: 54c437ee9dcc8fee36de` - The hash of the build. You can use this to invalidate assets through `[hash]` placeholder. We'll discuss hashing in detail in the *Adding Hashes to Filenames* chapter.
* `Version: webpack 2.2.0-rc.3` - Webpack version.
* `Time: 390ms` - Time it took to execute the build.
* `app.js 3.06 kB 0[emitted] app` - Name of the generated asset, size, the ids of the **chunks** into which it is related, status information telling how it was generated, name of the chunk.
* `Hash: d9b3a26d51481993359e` - The hash of the build. You can use this to invalidate assets through `[hash]` placeholder. We'll discuss hashing in detail in the *Adding Hashes to Filenames* chapter.
* `Version: webpack 2.2.0` - Webpack version.
* `Time: 375ms` - Time it took to execute the build.
* `app.js 3.12 kB 0 [emitted] app` - Name of the generated asset, size, the ids of the **chunks** into which it is related, status information telling how it was generated, name of the chunk.
* `index.html 180 bytes [emitted]` - Another generated asset that was emitted by the process.
* `[0] ./app/component.js 135 bytes {0} [built]` - The id of the entry asset, name, size, entry chunk id, the way it was generated.
* `Child html-webpack-plugin for "index.html":` - This is plugin-related output. In this case *html-webpack-plugin* is doing output of its own.
Expand All @@ -178,18 +178,6 @@ Examine the output below `build/`. If you look closely, you can see the same ids

T> It can be convenient to use a tool like *serve* (`npm i serve -g`) to serve the build directory. In this case, execute `serve` at the output directory and head to `localhost:3000` at your browser. You can configure the port through the `--port` parameter.

### Useful *html-webpack-plugin* Extensions

[html-webpack-template](https://www.npmjs.com/package/html-webpack-template) or [html-webpack-template-pug](https://www.npmjs.com/package/html-webpack-template-pug) complement *html-webpack-plugin* and provide more powerful templates to use with it.

There are also specific plugins that extend *html-webpack-plugin*'s functionality. I've listed a few of these below:

* [favicons-webpack-plugin](https://www.npmjs.com/package/favicons-webpack-plugin) is able to generate favicons.
* [script-ext-html-webpack-plugin](https://www.npmjs.com/package/script-ext-html-webpack-plugin) gives you more control over script tags and allows you to tune script loading further.
* [html-webpack-cdn-plugin](https://www.npmjs.com/package/html-webpack-cdn-plugin) makes it easier to use popular open source CDNs with it.
* [multipage-webpack-plugin](https://www.npmjs.com/package/multipage-webpack-plugin) builds on top of *html-webpack-plugin* and makes it easier to manage multi-page configurations.
* [resource-hints-webpack-plugin](https://www.npmjs.com/package/resource-hints-webpack-plugin) adds [resource hints](https://www.w3.org/TR/resource-hints/) to your HTML files to speed up loading time.

## Adding a Build Shortcut

Given executing `node_modules/.bin/webpack` is a little verbose, we should do something about it. npm and *package.json* double as a task runner with some configuration. Adjust it as follows:
Expand All @@ -204,17 +192,17 @@ Given executing `node_modules/.bin/webpack` is a little verbose, we should do so
...
```

Run `npm run build`. As a result, you should get the same output as before.

You can execute these scripts through *npm run*. If you run it as is, it will give you the listing of available scripts.
Run `npm run build`. You should see the same output as before.

This works because npm adds *node_modules/.bin* temporarily to the path. As a result, rather than having to write `"build": "node_modules/.bin/webpack"`, we can do just `"build": "webpack"`.

You can execute these kind of scripts through *npm run*. If you run it as is, it will give you the listing of available scripts.

T> There are shortcuts like *npm start* and *npm test*. We can run these directly without *npm run* although that will work too. For those in hurry, you can use *npm t* to run your tests.

T> It is possible to execute *npm run* anywhere within the project. It doesn't have to be run in the project root in order to work. npm will figure out the project root for you.

## Useful Plugins for Development
## Useful Development Plugins

As webpack plugin ecosystem is quite diverse, there are a lot of plugins that can help specifically with development. I've listed a few of these below to give you a better idea of what's available:

Expand All @@ -227,8 +215,18 @@ As webpack plugin ecosystem is quite diverse, there are a lot of plugins that ca

In addition to plugins like these, it can be worth your while to set up linting to enforce coding standards. The *Linting* chapter digs into that topic in greater detail.

## Conclusion
## Useful *html-webpack-plugin* Extensions

[html-webpack-template](https://www.npmjs.com/package/html-webpack-template) or [html-webpack-template-pug](https://www.npmjs.com/package/html-webpack-template-pug) complement *html-webpack-plugin* and provide more powerful templates to use with it.

There are also specific plugins that extend *html-webpack-plugin*'s functionality. I've listed a few of these below:

* [favicons-webpack-plugin](https://www.npmjs.com/package/favicons-webpack-plugin) is able to generate favicons.
* [script-ext-html-webpack-plugin](https://www.npmjs.com/package/script-ext-html-webpack-plugin) gives you more control over script tags and allows you to tune script loading further.
* [html-webpack-cdn-plugin](https://www.npmjs.com/package/html-webpack-cdn-plugin) makes it easier to use popular open source CDNs with it.
* [multipage-webpack-plugin](https://www.npmjs.com/package/multipage-webpack-plugin) builds on top of *html-webpack-plugin* and makes it easier to manage multi-page configurations.
* [resource-hints-webpack-plugin](https://www.npmjs.com/package/resource-hints-webpack-plugin) adds [resource hints](https://www.w3.org/TR/resource-hints/) to your HTML files to speed up loading time.

Even though we've managed to get webpack up and running, it's not that much yet. Developing against it would be painful. Each time we wanted to check out our application, we would have to build it manually using `npm run build` and then refresh the browser.
## Conclusion

That's where webpack's more advanced features come in. To make room for these features, I will show you how to split your webpack configuration in the next chapter.
Even though we've managed to get webpack up and running, it's not that much yet. Developing against it would be painful. Each time we wanted to check out our application, we would have to build it manually using `npm run build` and then refresh the browser. That's where webpack's more advanced features come in and we'll look into enabling automatic browser refresh in the next chapter.
93 changes: 61 additions & 32 deletions manuscript/developing_with_webpack/02_automatic_browser_refresh.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ W> You should use *webpack-dev-server* strictly for development. If you want to
To get started with WDS, execute:

```bash
npm i webpack-dev-server@2.2.0-rc.0 --save-dev
npm i webpack-dev-server@beta --save-dev
```

As before, this command will generate a command below the `npm bin` directory. You could try running *webpack-dev-server* from there. The quickest way to enable automatic browser refresh for our project is to run `webpack-dev-server`. After that, you have a development server running at `localhost:8080`.

## Attaching *webpack-dev-server* to the Project

To integrate WDS to our project, we can follow the same idea as in the previous chapter and define a new command to the `scripts` section of *package.json*:
To integrate WDS to our project, we should define a npm script for it. To follow npm conventions, we can call it as *start*. To tell our targets apart, we should pass information about the environment to webpack configuration. This will allow us specialize the configuration as needed:

**package.json**

Expand All @@ -39,8 +39,11 @@ To integrate WDS to our project, we can follow the same idea as in the previous
"scripts": {
leanpub-start-insert
"start": "webpack-dev-server --env development",
leanpub-end-insert
"build": "webpack --env production"
leanpub-end-insert
leanpub-start-delete
"build": "webpack"
leanpub-end-delete
},
...
```
Expand All @@ -52,9 +55,9 @@ If you execute either *npm run start* or *npm start* now, you should see somethi

Project is running at http://localhost:8080/
webpack output is served from /
Hash: 5901f1c1c0de0a563d85
Version: webpack 2.2.0-rc.3
Time: 731ms
Hash: a6629a1f55a2c758876b
Version: webpack 2.2.0
Time: 727ms
Asset Size Chunks Chunk Names
app.js 247 kB 0 [emitted] app
index.html 180 bytes [emitted]
Expand All @@ -67,55 +70,81 @@ The output means that the development server is running. If you open *http://loc

![Hello world](images/hello_01.png)

If you try modifying the code, you should see output at your terminal. The problem is that the browser doesn't catch these changes without a hard refresh. That's something we need to resolve next through configuration.
If you try modifying the code, you should see output at your terminal. The browser should also perform a hard refresh on change.

T> WDS will try to run in another port in case the default one is being used. Keep an eye on the terminal output to figure out where it ends up running. You can debug the situation with a command like `netstat -na | grep 8080`. If there's something running in the port 8080, it should display a message. The exact command may depend on the platform.

## Making Module Ids More Debuggable
## Verifying that `--env` Works

When webpack generates a bundle, it needs to tell different modules apart. By default, it uses numbers for this purpose. The problem is that this makes it difficult to debug the code if you must inspect the resulting code. It can also lead to issues with hashing behavior.

To overcome this problem, it is a good idea to use an alternative module id scheme. As it happens, webpack provides a plugin that's ideal for debugging. This plugin, `NamedModulesPlugin`, emits module paths over numeric ids. This information is useful for development.

You can enable this better behavior as follows:
Webpack configuration receives the result of `--env` if if exposes a function. To verify that the correct environment is passed, adjust the configuration as follows:

**webpack.config.js**

```javascript
const path = require('path');
leanpub-start-insert
const webpack = require('webpack');
leanpub-end-insert
const HtmlWebpackPlugin = require('html-webpack-plugin');
const merge = require('webpack-merge');

const PATHS = {
app: path.join(__dirname, 'app'),
build: path.join(__dirname, 'build'),
};

...

module.exports = function(env) {
leanpub-start-delete
return merge(common);
module.exports = {
leanpub-end-delete
leanpub-start-insert
return merge([
common,
{
plugins: [
new webpack.NamedModulesPlugin(),
],
},
]);
const config = {
leanpub-end-insert
// Entry accepts a path or an object of entries.
// We'll be using the latter form given it's
// convenient with more complex configurations.
//
// Entries have to resolve to files! It relies on Node.js
// convention by default so if a directory contains *index.js*,
// it will resolve to that.
entry: {
app: PATHS.app,
},
output: {
path: PATHS.build,
filename: '[name].js',
},
plugins: [
new HtmlWebpackPlugin({
title: 'Webpack demo',
}),
],
};

leanpub-start-insert
module.exports = function(env) {
console.log('env', env);

return config;
};
leanpub-end-insert
```
If you make your code crash somehow and examine the resulting code, you should see familiar paths in the output. Even though a small change, enabling this behavior is useful for development.
If you run the npm commands now, you should see a different terminal output depending on which one you trigger.
## Understanding `--env`
Even though `--env` allows us to pass strings to configuration, it can do a bit more. Consider the following example:
We will perform a similar trick for production usage later in this book in the *Adding Hashes to Filenames* chapter.
**package.json**
```json
...
"scripts": {
"start": "webpack-dev-server --env development",
"build": "webpack --env.target production"
}
...
```
Instead of a string, we should receive an object `{ target: 'production' }` at configuration now. We could pass more key-value pairs and they would go to the `env` object. It is important to note that if you set `--env foo` while setting `--env.target`, the string will override the object.
W> Webpack 2 changed argument behavior compared to webpack 1. You are not allowed to pass custom parameters through the CLI anymore. Instead, it's better to go through the `--env` mechanism if you need to do this.
## Accessing the Development Server from Network
Expand Down Expand Up @@ -149,7 +178,7 @@ To get it to work, you will have to install it first through `npm i nodemon --sa
...
"scripts": {
"start": "nodemon --watch webpack.config.js --exec \"webpack-dev-server --env development\"",
...
"build": "webpack --env production"
},
...
```
Expand Down
Loading

0 comments on commit 5946222

Please sign in to comment.