Skip to content

Commit 297c5bc

Browse files
TheDutchCoderskipjack
authored andcommitted
docs(guides): update output-management.md (#1344)
Rewrite of this guide as a logical follow up of the `Asset Management` guide. Manifest section will be expanded on later.
1 parent 92bec54 commit 297c5bc

File tree

1 file changed

+206
-55
lines changed

1 file changed

+206
-55
lines changed

content/guides/output-management.md

+206-55
Original file line numberDiff line numberDiff line change
@@ -3,85 +3,236 @@ title: Output Management
33
sort: 4
44
contributors:
55
- skipjack
6+
- TheDutchCoder
67
---
78

8-
Managing webpack's [output](/configuration/output) and including it in your HTML files may not seem tough at first, but once you start [using hashes in filenames](/guides/caching) and outputting [multiple bundles](/guides/code-splitting), things can start to get a bit hairy. However, there's no need to fear as a few plugins exist that will make this process much easier to manage.
9+
>T This guide extends on code examples found in the [`Asset Management`](/guides/asset-management) guide.
910
10-
First let's take a look at where you might stand without these plugins:
11+
So far we've manually included all our assets in our `index.html` file, but as your application grows and once you start [using hashes in filenames](/guides/caching) and outputting [multiple bundles](/guides/code-splitting), it will be difficult to keep managing your `index.html` file manually. However, there's no need to fear as a few plugins exist that will make this process much easier to manage.
1112

12-
__index.html__
13+
## Preparation
1314

14-
``` html
15-
<!doctype html>
15+
First, let's adjust our project a little bit:
1616

17-
<html>
18-
<head>
19-
<title>Output Management</title>
20-
<link rel="shortcut icon" href="/favicon.ico" />
21-
<link rel="stylesheet" href="/styles.min.css" />
22-
<script src="/vendor.bundle.js"></script>
23-
</head>
24-
<body>
25-
<script src="/app.bundle.js"></script>
26-
</body>
27-
</html>
17+
__project__
18+
19+
``` diff
20+
webpack-demo
21+
|- package.json
22+
|- webpack.config.js
23+
|- /dist
24+
|- /src
25+
|- index.js
26+
+ |- print.js
27+
|- /node_modules
28+
```
29+
30+
Let's add some logic to our `src/print.js` file:
31+
32+
__src/print.js__
33+
34+
``` js
35+
export default function printMe() {
36+
console.log('I get called from print.js!');
37+
}
2838
```
2939

30-
Here we've loaded a favicon, our stylesheet (extracted with the [`ExtractTextWebpackPlugin`](/plugins/extract-text-webpack-plugin)), any libraries (split into [a separate bundle](/guides/code-splitting)), and finally our main bundle (`app.bundle.js`). This is ok, but what happens if we change our entry point names? What if we decide to take advantage of [better caching practices](/guides/caching)?
40+
And use that function in our `src/index.js` file:
41+
42+
__src/index.js__
43+
44+
``` diff
45+
import _ from 'lodash';
46+
+ import printMe from './print.js';
47+
48+
function component() {
49+
var element = document.createElement('div');
50+
+ var btn = document.createElement('button');
51+
52+
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
53+
54+
+ btn.innerHTML = 'Click me and check the console!';
55+
+ btn.onclick = printMe;
56+
+
57+
+ element.appendChild(btn);
3158

59+
return element;
60+
}
3261

33-
## Auto-Generated HTML
62+
document.body.appendChild(component());
63+
```
64+
65+
Let's also update our `dist/index.html` file, in preparation for webpack to split out entries:
66+
67+
__dist/index.html__
68+
69+
``` diff
70+
<html>
71+
<head>
72+
- <title>Asset Management</title>
73+
+ <title>Output Management</title>
74+
+ <script src="./print.bundle.js"></script>
75+
</head>
76+
<body>
77+
- <script src="./bundle.js"></script>
78+
+ <script src="./app.bundle.js"></script>
79+
</body>
80+
</html>
81+
```
3482

35-
In comes the [`HtmlWebpackPlugin`](/plugins/html-webpack-plugin) to save the day. Using this plugin, you can stop hard-coding the output filenames into a manually-managed file and, instead, sit back as webpack auto-generates an `index.html` file for you. Let's take a look at what you'll need to add to your configuration:
83+
Now adjust the config. We'll be adding our `src/print.js` as a new entry point (`print`) and we'll change the output as well, so that it will dynamically generate bundle names, based on the entry point names:
3684

3785
__webpack.config.js__
3886

39-
``` js
40-
var path = require('path');
41-
var HtmlWebpackPlugin = require('html-webpack-plugin');
42-
43-
module.exports = {
44-
entry: {
45-
app: './src/index.js',
46-
vendor: [ 'react', 'react-dom' ]
47-
},
48-
49-
output: {
50-
path: path.resolve(__dirname, 'dist'),
51-
filename: '[name].bundle.js'
52-
},
53-
54-
plugins: [
55-
new HtmlWebpackPlugin({
56-
title: 'Output Management',
57-
favicon: './favicon.ico'
58-
})
59-
]
60-
};
87+
``` diff
88+
const path = require('path');
89+
90+
module.exports = {
91+
entry: {
92+
- index: './src/index.js',
93+
+ app: './src/index.js',
94+
+ print: './src/print.js'
95+
},
96+
output: {
97+
- filename: 'bundle.js',
98+
+ filename: '[name].bundle.js',
99+
path: path.resolve(__dirname, 'dist')
100+
}
101+
};
61102
```
62103

63-
This setup will generate the same HTML shown in the example above, excluding the extracted CSS. The plugin allows for many settings including extending your own template, minifying the output, and changing the script injection site. See [its documentation](/plugins/html-webpack-plugin) for more details.
104+
Let's run `npm run build` and see what this generates:
105+
106+
``` bash
107+
Hash: aa305b0f3373c63c9051
108+
Version: webpack 3.0.0
109+
Time: 536ms
110+
Asset Size Chunks Chunk Names
111+
app.bundle.js 545 kB 0, 1 [emitted] [big] app
112+
print.bundle.js 2.74 kB 1 [emitted] print
113+
[0] ./src/print.js 84 bytes {0} {1} [built]
114+
[1] ./src/index.js 403 bytes {0} [built]
115+
[3] (webpack)/buildin/global.js 509 bytes {0} [built]
116+
[4] (webpack)/buildin/module.js 517 bytes {0} [built]
117+
+ 1 hidden module
118+
```
64119

65-
T> Check out the [`HTMLWebpackTemplate`](https://github.com/jaketrent/html-webpack-template) extension for even more options including easy insertion of an `appMountId`, `meta` tags, and a `baseHref`.
120+
We can see that webpack generates our `print.bundle.js` and `app.bundle.js` files, which we also specified in our `index.html` file. if you open `index.html` in your browser, you can see what happens when you click the button.
66121

122+
But what would happen if we changed the name of one of our entry points, or even added a new one? The generated bundles would be renamed on a build, but our `index.html` file would still reference the old names. Let's fix that with the [`HtmlWebpackPlugin`](/plugins/html-webpack-plugin).
67123

68-
## Multiple HTML Files
69124

70-
To generate multiple HTML files, say for a multi-page web application, you can utilize the [`MultipageWebpackPlugin`](https://github.com/mutualofomaha/multipage-webpack-plugin). This plugin is similar to the `html-webpack-plugin`, in fact it uses that plugin under the hood, however it can be used to generate an HTML file per entry point.
125+
## Setting up HtmlWebpackPlugin
71126

127+
First install the plugin and adjust the `webpack.config.js` file:
72128

73-
## The Manifest
129+
``` bash
130+
npm install --save-dev html-webpack-plugin
131+
```
74132

75-
Let's step back for a second now and ask a more high-level question -- how do these plugins know what files are being spit out? The answer is in the manifest webpack keeps to track how all your modules map to the output bundles. If you're interested in managing webpack's [output](/configuration/output) in other ways, the manifest would be a good place to start.
133+
__webpack.config.js__
76134

77-
This data can be extracted into a json file for easy consumption using the [`WebpackManifestPlugin`](https://github.com/danethurber/webpack-manifest-plugin) or [`ChunkManifestPlugin`](https://github.com/soundcloud/chunk-manifest-webpack-plugin). Using the `ChunkManifestPlugin`, you would specify what to name it, what variable to expose it under, and whether or not to inline it via the `html-webpack-plugin`:
135+
``` diff
136+
const path = require('path');
137+
+ const HtmlWebpackPlugin = require('html-webpack-plugin');
138+
139+
module.exports = {
140+
entry: {
141+
app: './src/index.js',
142+
vendor: ['lodash']
143+
},
144+
+ plugins: [
145+
+ new HtmlWebpackPlugin({
146+
+ title: 'Output Management'
147+
+ })
148+
+ ],
149+
output: {
150+
filename: '[name].bundle.js',
151+
path: path.resolve(__dirname, 'dist')
152+
}
153+
};
154+
```
78155

79-
``` js
80-
new ChunkManifestPlugin({
81-
filename: 'manifest.json',
82-
manifestVariable: 'webpackManifest',
83-
inlineManifest: false
84-
})
156+
Before we do a build, you should know that the `HtmlWebpackPlugin` by default will generate its own `index.html` file, even though we already have one in the `dist/` folder. This means that it will replace our `index.html` file with a newly generated one. Let's see what happens when we do an `npm run build`:
157+
158+
``` bash
159+
Hash: 81f82697c19b5f49aebd
160+
Version: webpack 2.6.1
161+
Time: 854ms
162+
Asset Size Chunks Chunk Names
163+
vendor.bundle.js 544 kB 0 [emitted] [big] vendor
164+
app.bundle.js 2.81 kB 1 [emitted] app
165+
index.html 249 bytes [emitted]
166+
[0] ./~/lodash/lodash.js 540 kB {0} [built]
167+
[1] (webpack)/buildin/global.js 509 bytes {0} [built]
168+
[2] (webpack)/buildin/module.js 517 bytes {0} [built]
169+
[3] ./src/index.js 172 bytes {1} [built]
170+
[4] multi lodash 28 bytes {0} [built]
171+
Child html-webpack-plugin for "index.html":
172+
[0] ./~/lodash/lodash.js 540 kB {0} [built]
173+
[1] ./~/html-webpack-plugin/lib/loader.js!./~/html-webpack-plugin/default_index.ejs 538 bytes {0} [built]
174+
[2] (webpack)/buildin/global.js 509 bytes {0} [built]
175+
[3] (webpack)/buildin/module.js 517 bytes {0} [built]
176+
```
177+
178+
If you open `index.html` in your code editor, you'll see that the `HtmlWebpackPlugin` has created an entirely new file for you and that all the bundles are automatically added.
179+
180+
If you want to learn more about all the features and options that the `HtmlWebpackPlugin` provides, then you should read up on it on the [`HtmlWebpackPlugin`](https://github.com/jantimon/html-webpack-plugin) repo.
181+
182+
You can also take a look at [`html-webpack-template`](https://github.com/jaketrent/html-webpack-template) which provides a couple of extra features in addition to the default template.
183+
184+
185+
## Cleaning up the `/dist` folder
186+
187+
As you might have noticed over the past guides and code example, our `/dist` folder has become quite cluttered. Webpack will generate the files and put them in the `/dist` folder for you, but it doesn't keep track of which files are actually in use by your project.
188+
189+
In general it's good practice to clean the `/dist` folder before each build, so that only used files will be generated. Let's take care of that.
190+
191+
A popular plugin to manage this is the [`clean-webpack-plugin`](https://www.npmjs.com/package/clean-webpack-plugin) so let's install and configure it.
192+
193+
``` bash
194+
npm install clean-webpack-plugin --save-dev
195+
```
196+
197+
__webpack.config.js__
198+
199+
``` diff
200+
const path = require('path');
201+
const HtmlWebpackPlugin = require('html-webpack-plugin');
202+
const CleanWebpackPlugin = require('clean-webpack-plugin');
203+
204+
module.exports = {
205+
entry: {
206+
app: './src/index.js',
207+
vendor: ['lodash']
208+
},
209+
plugins: [
210+
+ new CleanWebpackPlugin(['dist']),
211+
new HtmlWebpackPlugin({
212+
      title: 'Output Management',
213+
      filename: 'index.html',
214+
template: 'src/index.html'
215+
})
216+
],
217+
output: {
218+
filename: '[name].bundle.js',
219+
path: path.resolve(__dirname, 'dist')
220+
}
221+
};
85222
```
86223

87-
See [the concepts page](/concepts/manifest) for more background information and the [caching guide](/guides/caching) guide to find out how this ties into long term caching.
224+
Now run an `npm run build` and inspect the `/dist` folder. If everything went well you should now only see the files generated from the build and no more old files!
225+
226+
227+
## The Manifest
228+
229+
You might be wondering how webpack and its plugins seem to "know" what files are being generated. The answer is in the manifest that webpack keeps to track how all the modules map to the output bundles. If you're interested in managing webpack's [`ouput`](/configuration/output) in other ways, the manifest would be a good place to start.
230+
231+
The manifest data can be extracted into a json file for easy consumption using the [`WebpackManifestPlugin`](https://github.com/danethurber/webpack-manifest-plugin).
232+
233+
We won't go through a full example of how to use this plugin within your projects, but you can read up on [the concept page](/concepts/manifest) and the [caching guide](/guides/caching) to find out how this ties into long term caching.
234+
235+
236+
## Conclusion
237+
238+
Now that you've learned about dynamically adding bundles to your HTML, let's dive into the next guide: [`Development`](/guides/development). If you want to dive into more advanced topics, we would recommend heading over to the [`Code Splitting`](/guides/code-splitting) guide.

0 commit comments

Comments
 (0)