2017-05-26 15:28:06 -04:00
# Webpack: An Introduction
2017-03-30 15:04:18 -04:00
2017-02-22 13:09:39 -05:00
< style >
2017-03-31 19:57:13 -04:00
h4 {font-size: 17px !important; text-transform: none !important;}
.syntax { font-family: Consolas, 'Lucida Sans', Courier, sans-serif; color: black; font-size: 85%; }
2017-02-22 13:09:39 -05:00
< / style >
2017-03-31 19:57:13 -04:00
2017-02-22 13:09:39 -05:00
[**Webpack** ](https://webpack.github.io/ ) is a popular module bundler,
2017-03-27 11:08:53 -04:00
a tool for bundling application source code in convenient _chunks_
2017-02-22 13:09:39 -05:00
and for loading that code from a server into a browser.
It's an excellent alternative to the *SystemJS* approach used elsewhere in the documentation.
This guide offers a taste of Webpack and explains how to use it with Angular applications.
2017-03-31 19:57:13 -04:00
{@a top}
2017-05-04 12:46:43 -04:00
<!--
2017-03-31 19:57:13 -04:00
2017-03-27 11:08:53 -04:00
# Contents
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
* [What is Webpack? ](guide/webpack#what-is-webpack )
2017-03-31 19:57:13 -04:00
2017-03-11 10:36:40 -05:00
* [Entries and outputs ](guide/webpack#entries-outputs )
2017-03-27 11:08:53 -04:00
* [Multiple bundles ](guide/webpack#multiple-bundles )
2017-03-11 10:36:40 -05:00
* [Loaders ](guide/webpack#loaders )
* [Plugins ](guide/webpack#plugins )
2017-03-31 19:57:13 -04:00
2017-03-27 11:08:53 -04:00
* [Configuring Webpack ](guide/webpack#configure-webpack )
2017-03-31 19:57:13 -04:00
2017-03-27 11:08:53 -04:00
* [Polyfills ](guide/webpack#polyfills )
2017-03-11 10:36:40 -05:00
* [Common configuration ](guide/webpack#common-configuration )
2017-03-27 11:08:53 -04:00
* [Inside `webpack.common.js` ](guide/webpack#inside-webpack-commonjs )
2017-03-31 19:57:13 -04:00
* [entry ](guide/webpack#common-entries )
* [resolve extension-less imports ](guide/webpack#common-resolves )
* [`module.rules` ](guide/webpack#common-rules )
* [Plugins ](guide/webpack#plugins )
* [`CommonsChunkPlugin` ](guide/webpack#commons-chunk-plugin )
* [`HtmlWebpackPlugin` ](guide/webpack#html-webpack-plugin )
2017-03-27 11:08:53 -04:00
* [Environment specific configuration ](guide/webpack#environment-configuration )
2017-03-11 10:36:40 -05:00
* [Development configuration ](guide/webpack#development-configuration )
* [Production configuration ](guide/webpack#production-configuration )
* [Test configuration ](guide/webpack#test-configuration )
2017-05-03 08:55:00 -04:00
2017-03-27 11:08:53 -04:00
* [Trying it out ](guide/webpack#try )
* [Highlights ](guide/webpack#highlights )
* [Conclusion ](guide/webpack#conclusion )
2017-03-06 05:43:33 -05:00
2017-05-04 12:46:43 -04:00
-->
2017-05-03 08:55:00 -04:00
You can also < a href = "generated/zips/webpack/webpack.zip" target = "_blank" > download the final result.< / a >
2017-03-06 05:43:33 -05:00
2017-03-31 19:57:13 -04:00
{@a what-is-webpack}
## What is Webpack?
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
Webpack is a powerful module bundler.
A _bundle_ is a JavaScript file that incorporates _assets_ that *belong* together and
2017-02-22 13:09:39 -05:00
should be served to the client in a response to a single file request.
A bundle can include JavaScript, CSS styles, HTML, and almost any other kind of file.
2017-03-27 11:08:53 -04:00
Webpack roams over your application source code,
looking for `import` statements, building a dependency graph, and emitting one or more _bundles_ .
With plugins and rules, Webpack can preprocess and minify different non-JavaScript files such as TypeScript, SASS, and LESS files.
2017-02-22 13:09:39 -05:00
You determine what Webpack does and how it does it with a JavaScript configuration file, `webpack.config.js` .
{@a entries-outputs}
2017-03-31 19:57:13 -04:00
2017-02-22 13:09:39 -05:00
### Entries and outputs
2017-03-27 11:08:53 -04:00
You supply Webpack with one or more *entry* files and let it find and incorporate the dependencies that radiate from those entries.
The one entry point file in this example is the application's root file, `src/main.ts` :
2017-02-22 13:09:39 -05:00
2017-03-31 19:57:13 -04:00
< code-example path = "webpack/config/webpack.common.js" region = "one-entry" title = "webpack.config.js (single entry)" linenums = "false" >
2017-03-27 11:08:53 -04:00
< / code-example >
2017-02-22 13:09:39 -05:00
2017-03-31 19:57:13 -04:00
2017-02-22 13:09:39 -05:00
Webpack inspects that file and traverses its `import` dependencies recursively.
2017-03-31 19:57:13 -04:00
< code-example path = "webpack/src/app/app.component.ts" region = "component" title = "src/main.ts" linenums = "false" >
2017-03-27 11:08:53 -04:00
< / code-example >
2017-02-22 13:09:39 -05:00
2017-03-31 19:57:13 -04:00
2017-03-27 11:08:53 -04:00
It sees that you're importing `@angular/core` so it adds that to its dependency list for potential inclusion in the bundle.
It opens the `@angular/core` file and follows _its_ network of `import` statements until it has built the complete dependency graph from `main.ts` down.
2017-02-22 13:09:39 -05:00
Then it **outputs** these files to the `app.js` _bundle file_ designated in configuration:
2017-05-09 16:01:04 -04:00
< code-example name = "webpack.config.js (single output)" language = "javascript" >
output: {
filename: 'app.js'
}
2017-03-30 15:04:18 -04:00
2017-05-09 16:01:04 -04:00
< / code-example >
2017-03-31 19:57:13 -04:00
2017-03-27 11:08:53 -04:00
This `app.js` output bundle is a single JavaScript file that contains the application source and its dependencies.
You'll load it later with a `<script>` tag in the `index.html` .
{@a multiple-bundles}
2017-03-31 19:57:13 -04:00
2017-02-22 13:09:39 -05:00
#### Multiple bundles
You probably don't want one giant bundle of everything.
It's preferable to separate the volatile application app code from comparatively stable vendor code modules.
2017-03-27 11:08:53 -04:00
Change the configuration so that it has two entry points, `main.ts` and `vendor.ts` :
2017-03-30 15:04:18 -04:00
2017-05-09 16:01:04 -04:00
< code-example language = "javascript" >
entry: {
app: 'src/app.ts',
vendor: 'src/vendor.ts'
},
2017-03-31 19:57:13 -04:00
2017-05-09 16:01:04 -04:00
output: {
filename: '[name].js'
}
2017-02-22 13:09:39 -05:00
2017-05-09 16:01:04 -04:00
< / code-example >
2017-03-31 19:57:13 -04:00
2017-02-22 13:09:39 -05:00
Webpack constructs two separate dependency graphs
2017-03-27 11:08:53 -04:00
and emits *two* bundle files, one called `app.js` containing only the application code and
2017-02-22 13:09:39 -05:00
another called `vendor.js` with all the vendor dependencies.
2017-03-27 11:08:53 -04:00
2017-04-10 11:51:13 -04:00
< div class = "l-sub-section" >
2017-03-27 11:08:53 -04:00
2017-03-31 19:57:13 -04:00
2017-02-22 13:09:39 -05:00
The `[name]` in the output name is a *placeholder* that a Webpack plugin replaces with the entry names,
2017-03-11 10:36:40 -05:00
`app` and `vendor` . Plugins are [covered later ](guide/webpack#commons-chunk-plugin ) in the guide.
2017-03-27 11:08:53 -04:00
2017-04-10 11:51:13 -04:00
< / div >
2017-03-27 11:08:53 -04:00
2017-03-31 19:57:13 -04:00
2017-03-27 11:08:53 -04:00
To tell Webpack what belongs in the vendor bundle,
2017-02-22 13:09:39 -05:00
add a `vendor.ts` file that only imports the application's third-party modules:
2017-03-31 19:57:13 -04:00
< code-example path = "webpack/src/vendor.ts" title = "src/vendor.ts" linenums = "false" >
2017-03-27 11:08:53 -04:00
< / code-example >
2017-02-22 13:09:39 -05:00
{@a loaders}
2017-03-31 19:57:13 -04:00
2017-02-22 13:09:39 -05:00
### Loaders
2017-03-27 11:08:53 -04:00
Webpack can bundle any kind of file: JavaScript, TypeScript, CSS, SASS, LESS, images, HTML, fonts, whatever.
2017-02-22 13:09:39 -05:00
Webpack _itself_ only understands JavaScript files.
2017-03-27 11:08:53 -04:00
Teach it to transform non-JavaScript file into their JavaScript equivalents with *loaders* .
2017-02-22 13:09:39 -05:00
Configure loaders for TypeScript and CSS as follows.
2017-03-30 15:04:18 -04:00
2017-05-09 16:01:04 -04:00
< code-example language = "javascript" >
rules: [
{
test: /\.ts$/,
loader: 'awesome-typescript-loader'
},
{
test: /\.css$/,
loaders: 'style-loader!css-loader'
}
]
2017-02-22 13:09:39 -05:00
2017-05-09 16:01:04 -04:00
< / code-example >
2017-02-22 13:09:39 -05:00
2017-03-31 19:57:13 -04:00
2017-05-03 08:55:00 -04:00
When Webpack encounters `import` statements like the following,
it applies the `test` RegEx patterns.
2017-02-22 13:09:39 -05:00
2017-03-30 15:04:18 -04:00
2017-05-09 16:01:04 -04:00
< code-example language = "typescript" >
import { AppComponent } from './app.component.ts';
2017-03-31 19:57:13 -04:00
2017-05-09 16:01:04 -04:00
import 'uiframework/dist/uiframework.css';
2017-03-27 11:08:53 -04:00
2017-05-09 16:01:04 -04:00
< / code-example >
2017-03-27 11:08:53 -04:00
2017-03-31 19:57:13 -04:00
2017-03-27 11:08:53 -04:00
When a pattern matches the filename, Webpack processes the file with the associated loader.
2017-02-22 13:09:39 -05:00
The first `import` file matches the `.ts` pattern so Webpack processes it with the `awesome-typescript-loader` .
2017-03-27 11:08:53 -04:00
The imported file doesn't match the second pattern so its loader is ignored.
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
The second `import` matches the second `.css` pattern for which you have *two* loaders chained by the (!) character.
Webpack applies chained loaders *right to left* . So it applies
2017-05-03 08:55:00 -04:00
the `css` loader first to flatten CSS `@import` and `url(...)` statements.
2017-03-27 11:08:53 -04:00
Then it applies the `style` loader to append the css inside `<style>` elements on the page.
2017-02-22 13:09:39 -05:00
{@a plugins}
2017-03-31 19:57:13 -04:00
2017-02-22 13:09:39 -05:00
### Plugins
Webpack has a build pipeline with well-defined phases.
Tap into that pipeline with plugins such as the `uglify` minification plugin:
2017-05-09 16:01:04 -04:00
< code-example language = "javascript" >
plugins: [
new webpack.optimize.UglifyJsPlugin()
]
2017-03-30 15:04:18 -04:00
2017-05-09 16:01:04 -04:00
< / code-example >
2017-02-22 13:09:39 -05:00
{@a configure-webpack}
2017-03-31 19:57:13 -04:00
2017-03-27 11:08:53 -04:00
## Configuring Webpack
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
After that brief orientation, you are ready to build your own Webpack configuration for Angular apps.
2017-02-22 13:09:39 -05:00
Begin by setting up the development environment.
2017-03-27 11:08:53 -04:00
Create a new project folder.
2017-03-30 15:04:18 -04:00
2017-02-22 13:09:39 -05:00
< code-example language = "sh" class = "code-shell" >
2017-03-31 19:57:13 -04:00
mkdir angular-webpack
cd angular-webpack
2017-02-22 13:09:39 -05:00
< / code-example >
2017-03-31 19:57:13 -04:00
2017-03-06 05:43:33 -05:00
Add these files:
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
< code-tabs >
< code-pane title = "package.json" path = "webpack/package.webpack.json" >
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
< / code-pane >
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
< code-pane title = "src/tsconfig.json" path = "webpack/src/tsconfig.1.json" >
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
< / code-pane >
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
< code-pane title = "webpack.config.js" path = "webpack/webpack.config.js" >
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
< / code-pane >
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
< code-pane title = "karma.conf.js" path = "webpack/karma.webpack.conf.js" >
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
< / code-pane >
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
< code-pane title = "config/helpers.js" path = "webpack/config/helpers.js" >
< / code-pane >
< / code-tabs >
2017-04-10 11:51:13 -04:00
< div class = "l-sub-section" >
2017-03-27 11:08:53 -04:00
2017-03-31 19:57:13 -04:00
2017-02-22 13:09:39 -05:00
Many of these files should be familiar from other Angular documentation guides,
2017-03-27 11:08:53 -04:00
especially the [Typescript configuration ](guide/typescript-configuration ) and
[npm packages ](guide/npm-packages ) guides.
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
Webpack, the plugins, and the loaders are also installed as packages.
2017-02-22 13:09:39 -05:00
They are listed in the updated `packages.json` .
2017-03-27 11:08:53 -04:00
2017-04-10 11:51:13 -04:00
< / div >
2017-03-27 11:08:53 -04:00
2017-03-31 19:57:13 -04:00
2017-03-27 11:08:53 -04:00
Open a terminal window and install the npm packages.
2017-03-30 15:04:18 -04:00
2017-02-22 13:09:39 -05:00
< code-example language = "sh" class = "code-shell" >
2017-03-31 19:57:13 -04:00
npm install
2017-02-22 13:09:39 -05:00
< / code-example >
{@a polyfills}
2017-03-31 19:57:13 -04:00
2017-02-22 13:09:39 -05:00
### Polyfills
You'll need polyfills to run an Angular application in most browsers as explained
2017-03-27 11:08:53 -04:00
in the [Browser Support ](guide/browser-support ) guide.
2017-02-22 13:09:39 -05:00
Polyfills should be bundled separately from the application and vendor bundles.
Add a `polyfills.ts` like this one to the `src/` folder.
2017-03-31 19:57:13 -04:00
< code-example path = "webpack/src/polyfills.ts" title = "src/polyfills.ts" linenums = "false" >
2017-03-27 11:08:53 -04:00
< / code-example >
2017-02-22 13:09:39 -05:00
2017-04-10 11:51:13 -04:00
< div class = "callout is-critical" >
2017-02-22 13:09:39 -05:00
2017-03-30 15:04:18 -04:00
2017-02-22 13:09:39 -05:00
< header >
Loading polyfills
< / header >
2017-03-31 19:57:13 -04:00
2017-02-22 13:09:39 -05:00
Load `zone.js` early within `polyfills.ts` , immediately after the other ES6 and metadata shims.
2017-04-10 11:51:13 -04:00
< / div >
2017-02-22 13:09:39 -05:00
2017-03-31 19:57:13 -04:00
2017-03-27 11:08:53 -04:00
Because this bundle file will load first, `polyfills.ts` is also a good place to configure the browser environment
2017-02-22 13:09:39 -05:00
for production or development.
{@a common-configuration}
2017-03-31 19:57:13 -04:00
2017-03-27 11:08:53 -04:00
### Common configuration
2017-02-22 13:09:39 -05:00
Developers typically have separate configurations for development, production, and test environments.
All three have a lot of configuration in common.
Gather the common configuration in a file called `webpack.common.js` .
2017-03-31 19:57:13 -04:00
< code-example path = "webpack/config/webpack.common.js" title = "config/webpack.common.js" linenums = "false" >
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
< / code-example >
{@a inside-webpack-commonjs}
2017-03-31 19:57:13 -04:00
2017-02-22 13:09:39 -05:00
### Inside _webpack.common.js_
2017-03-27 11:08:53 -04:00
Webpack is a NodeJS-based tool that reads configuration from a JavaScript commonjs module file.
2017-02-22 13:09:39 -05:00
The configuration imports dependencies with `require` statements
and exports several objects as properties of a `module.exports` object.
2017-03-27 11:08:53 -04:00
* [`entry` ](guide/webpack#common-entries )— the entry-point files that define the bundles.
2017-04-30 16:10:32 -04:00
* [`resolve` ](guide/webpack#common-resolves )— how to resolve file names when they lack extensions.
2017-03-27 11:08:53 -04:00
* [`module.rules` ](guide/webpack#common-rules )— `module` is an object with `rules` for deciding how files are loaded.
* [`plugins` ](guide/webpack#common-plugins )— creates instances of the plugins.
2017-02-22 13:09:39 -05:00
{@a common-entries}
2017-03-31 19:57:13 -04:00
2017-03-27 11:08:53 -04:00
#### _entry_
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
The first export is the `entry` object:
2017-02-22 13:09:39 -05:00
2017-03-31 19:57:13 -04:00
< code-example path = "webpack/config/webpack.common.js" region = "entries" title = "config/webpack.common.js" linenums = "false" >
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
< / code-example >
2017-03-31 19:57:13 -04:00
2017-03-27 11:08:53 -04:00
This `entry` object defines the three bundles:
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
* `polyfills` — the polyfills needed to run Angular applications in most modern browsers.
* `vendor` — the third-party dependencies such as Angular, lodash, and bootstrap.css.
* `app` — the application code.
2017-02-22 13:09:39 -05:00
2017-04-30 16:10:32 -04:00
{@a common-resolves}
2017-03-31 19:57:13 -04:00
2017-02-22 13:09:39 -05:00
#### _resolve_ extension-less imports
2017-03-27 11:08:53 -04:00
The app will `import` dozens if not hundreds of JavaScript and TypeScript files.
2017-02-22 13:09:39 -05:00
You could write `import` statements with explicit extensions like this example:
2017-05-09 16:01:04 -04:00
< code-example language = "typescript" >
import { AppComponent } from './app.component.ts';
2017-03-30 15:04:18 -04:00
2017-05-09 16:01:04 -04:00
< / code-example >
2017-03-31 19:57:13 -04:00
2017-02-22 13:09:39 -05:00
But most `import` statements don't mention the extension at all.
Tell Webpack to resolve extension-less file requests by looking for matching files with
`.ts` extension or `.js` extension (for regular JavaScript files and pre-compiled TypeScript files).
2017-03-31 19:57:13 -04:00
< code-example path = "webpack/config/webpack.common.js" region = "resolve" title = "config/webpack.common.js" linenums = "false" >
2017-03-27 11:08:53 -04:00
< / code-example >
2017-02-22 13:09:39 -05:00
2017-04-10 11:51:13 -04:00
< div class = "l-sub-section" >
2017-02-22 13:09:39 -05:00
2017-03-31 19:57:13 -04:00
2017-02-22 13:09:39 -05:00
If Webpack should resolve extension-less files for styles and HTML,
add `.css` and `.html` to the list.
2017-04-10 11:51:13 -04:00
< / div >
2017-03-27 11:08:53 -04:00
2017-02-22 13:09:39 -05:00
{@a common-rules}
2017-03-31 19:57:13 -04:00
2017-02-22 13:09:39 -05:00
#### _module.rules_
2017-03-27 11:08:53 -04:00
Rules tell Webpack which loaders to use for each file, or module:
2017-02-22 13:09:39 -05:00
2017-03-31 19:57:13 -04:00
< code-example path = "webpack/config/webpack.common.js" region = "loaders" title = "config/webpack.common.js" linenums = "false" >
2017-03-27 11:08:53 -04:00
< / code-example >
2017-03-31 19:57:13 -04:00
2017-03-27 11:08:53 -04:00
* `awesome-typescript-loader` — a loader to transpile the Typescript code to ES5, guided by the `tsconfig.json` file.
* `angular2-template-loader` — loads angular components' template and styles.
* `html-loader` — for component templates.
* images/fonts— Images and fonts are bundled as well.
2017-05-03 08:55:00 -04:00
* CSS— the first pattern matches application-wide styles; the second handles
2017-03-27 11:08:53 -04:00
component-scoped styles (the ones specified in a component's `styleUrls` metadata property).
2017-04-10 11:51:13 -04:00
< div class = "l-sub-section" >
2017-02-22 13:09:39 -05:00
2017-03-31 19:57:13 -04:00
2017-03-06 05:43:33 -05:00
The first pattern is for the application-wide styles. It excludes `.css` files within the `src/app` directory
where the component-scoped styles sit. The `ExtractTextPlugin` (described below) applies the `style` and `css`
loaders to these files.
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
The second pattern filters for component-scoped styles and loads them as strings via the `raw-loader` ,
2017-02-22 13:09:39 -05:00
which is what Angular expects to do with styles specified in a `styleUrls` metadata property.
2017-03-27 11:08:53 -04:00
2017-04-10 11:51:13 -04:00
< / div >
2017-03-27 11:08:53 -04:00
2017-04-10 11:51:13 -04:00
< div class = "l-sub-section" >
2017-03-27 11:08:53 -04:00
2017-03-31 19:57:13 -04:00
2017-02-22 13:09:39 -05:00
Multiple loaders can be chained using the array notation.
2017-04-10 11:51:13 -04:00
< / div >
2017-03-27 11:08:53 -04:00
2017-02-22 13:09:39 -05:00
{@a common-plugins}
2017-03-31 19:57:13 -04:00
2017-02-22 13:09:39 -05:00
#### _plugins_
Finally, create instances of three plugins:
2017-03-31 19:57:13 -04:00
< code-example path = "webpack/config/webpack.common.js" region = "plugins" title = "config/webpack.common.js" linenums = "false" >
2017-03-27 11:08:53 -04:00
< / code-example >
2017-02-22 13:09:39 -05:00
{@a commons-chunk-plugin}
2017-03-31 19:57:13 -04:00
2017-02-22 13:09:39 -05:00
#### *CommonsChunkPlugin*
2017-03-27 11:08:53 -04:00
The `app.js` bundle should contain only application code. All vendor code belongs in the `vendor.js` bundle.
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
Of course the application code imports vendor code.
On its own, Webpack is not smart enough to keep the vendor code out of the `app.js` bundle.
The `CommonsChunkPlugin` does that job.
2017-04-10 11:51:13 -04:00
< div class = "l-sub-section" >
2017-03-27 11:08:53 -04:00
2017-03-31 19:57:13 -04:00
2017-03-27 11:08:53 -04:00
The `CommonsChunkPlugin` identifies the hierarchy among three _chunks_ : `app` -> `vendor` -> `polyfills` .
2017-02-22 13:09:39 -05:00
Where Webpack finds that `app` has shared dependencies with `vendor` , it removes them from `app` .
2017-03-27 11:08:53 -04:00
It would remove `polyfills` from `vendor` if they shared dependencies, which they don't.
2017-04-10 11:51:13 -04:00
< / div >
2017-03-27 11:08:53 -04:00
2017-02-22 13:09:39 -05:00
{@a html-webpack-plugin}
2017-03-31 19:57:13 -04:00
2017-03-27 11:08:53 -04:00
#### _HtmlWebpackPlugin_
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
Webpack generates a number of js and CSS files.
2017-02-22 13:09:39 -05:00
You _could_ insert them into the `index.html` _manually_ . That would be tedious and error-prone.
Webpack can inject those scripts and links for you with the `HtmlWebpackPlugin` .
{@a environment-configuration}
2017-03-31 19:57:13 -04:00
2017-02-22 13:09:39 -05:00
### Environment-specific configuration
2017-03-27 11:08:53 -04:00
The `webpack.common.js` configuration file does most of the heavy lifting.
2017-02-22 13:09:39 -05:00
Create separate, environment-specific configuration files that build on `webpack.common`
by merging into it the peculiarities particular to the target environments.
These files tend to be short and simple.
{@a development-configuration}
2017-03-31 19:57:13 -04:00
2017-03-27 11:08:53 -04:00
### Development configuration
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
Here is the `webpack.dev.js` development configuration file.
2017-02-22 13:09:39 -05:00
2017-03-31 19:57:13 -04:00
< code-example path = "webpack/config/webpack.dev.js" title = "config/webpack.dev.js" linenums = "false" >
2017-03-27 11:08:53 -04:00
< / code-example >
2017-02-22 13:09:39 -05:00
2017-03-31 19:57:13 -04:00
2017-02-22 13:09:39 -05:00
The development build relies on the Webpack development server, configured near the bottom of the file.
Although you tell Webpack to put output bundles in the `dist` folder,
the dev server keeps all bundles in memory; it doesn't write them to disk.
2017-03-27 11:08:53 -04:00
You won't find any files in the `dist` folder, at least not any generated from *this development build* .
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
The `HtmlWebpackPlugin` , added in `webpack.common.js` , uses the `publicPath` and the `filename` settings to generate
appropriate `<script>` and `<link>` tags into the `index.html` .
2017-02-22 13:09:39 -05:00
The CSS styles are buried inside the Javascript bundles by default. The `ExtractTextPlugin` extracts them into
2017-03-27 11:08:53 -04:00
external `.css` files that the `HtmlWebpackPlugin` inscribes as `<link>` tags into the `index.html` .
2017-02-22 13:09:39 -05:00
2017-05-03 08:55:00 -04:00
Refer to the [Webpack documentation ](https://webpack.github.io/docs/ ) for details on these and
2017-03-27 11:08:53 -04:00
other configuration options in this file.
2017-02-22 13:09:39 -05:00
Grab the app code at the end of this guide and try:
2017-03-30 15:04:18 -04:00
2017-02-22 13:09:39 -05:00
< code-example language = "sh" class = "code-shell" >
2017-03-31 19:57:13 -04:00
npm start
2017-02-22 13:09:39 -05:00
< / code-example >
{@a production-configuration}
2017-03-31 19:57:13 -04:00
2017-03-27 11:08:53 -04:00
### Production configuration
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
Configuration of a *production* build resembles *development* configuration with a few key changes.
2017-02-22 13:09:39 -05:00
2017-03-31 19:57:13 -04:00
< code-example path = "webpack/config/webpack.prod.js" title = "config/webpack.prod.js" linenums = "false" >
2017-03-27 11:08:53 -04:00
< / code-example >
2017-02-22 13:09:39 -05:00
2017-03-31 19:57:13 -04:00
2017-02-22 13:09:39 -05:00
You'll deploy the application and its dependencies to a real production server.
You won't deploy the artifacts needed only in development.
Put the production output bundle files in the `dist` folder.
Webpack generates file names with cache-busting hash.
2017-03-27 11:08:53 -04:00
Thanks to the `HtmlWebpackPlugin` , you don't have to update the `index.html` file when the hash changes.
2017-02-22 13:09:39 -05:00
There are additional plugins:
2017-03-27 11:08:53 -04:00
* *`NoEmitOnErrorsPlugin`— stops the build if there is an error.
* *`UglifyJsPlugin`— minifies the bundles.
* *`ExtractTextPlugin`— extracts embedded css as external files, adding cache-busting hash to the filename.
* *`DefinePlugin`— use to define environment variables that you can reference within the application.
* *`LoaderOptionsPlugins`— to override options of certain loaders.
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
Thanks to the `DefinePlugin` and the `ENV` variable defined at top, you can enable Angular production mode like this:
2017-02-22 13:09:39 -05:00
2017-03-31 19:57:13 -04:00
< code-example path = "webpack/src/main.ts" region = "enable-prod" title = "src/main.ts" linenums = "false" >
2017-03-27 11:08:53 -04:00
< / code-example >
2017-02-22 13:09:39 -05:00
2017-03-31 19:57:13 -04:00
2017-02-22 13:09:39 -05:00
Grab the app code at the end of this guide and try:
2017-03-30 15:04:18 -04:00
2017-02-22 13:09:39 -05:00
< code-example language = "sh" class = "code-shell" >
2017-03-31 19:57:13 -04:00
npm run build
2017-02-22 13:09:39 -05:00
< / code-example >
{@a test-configuration}
2017-03-31 19:57:13 -04:00
2017-03-27 11:08:53 -04:00
### Test configuration
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
You don't need much configuration to run unit tests.
2017-02-22 13:09:39 -05:00
You don't need the loaders and plugins that you declared for your development and production builds.
You probably don't need to load and process the application-wide styles files for unit tests and doing so would slow you down;
you'll use the `null` loader for those CSS files.
You could merge the test configuration into the `webpack.common` configuration and override the parts you don't want or need.
But it might be simpler to start over with a completely fresh configuration.
2017-03-31 19:57:13 -04:00
< code-example path = "webpack/config/webpack.test.js" title = "config/webpack.test.js" linenums = "false" >
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
< / code-example >
2017-02-22 13:09:39 -05:00
2017-03-31 19:57:13 -04:00
2017-03-27 11:08:53 -04:00
Reconfigure [Karma ](https://karma-runner.github.io/1.0/index.html ) to use Webpack to run the tests:
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
2017-03-31 19:57:13 -04:00
< code-example path = "webpack/config/karma.conf.js" title = "config/karma.conf.js" linenums = "false" >
2017-03-27 11:08:53 -04:00
< / code-example >
2017-02-22 13:09:39 -05:00
2017-03-31 19:57:13 -04:00
2017-02-22 13:09:39 -05:00
You don't precompile the TypeScript; Webpack transpiles the Typescript files on the fly, in memory, and feeds the emitted JS directly to Karma.
There are no temporary files on disk.
2017-03-27 11:08:53 -04:00
The `karma-test-shim` tells Karma what files to pre-load and
2017-02-22 13:09:39 -05:00
primes the Angular test framework with test versions of the providers that every app expects to be pre-loaded.
2017-03-31 19:57:13 -04:00
< code-example path = "webpack/config/karma-test-shim.js" title = "config/karma-test-shim.js" linenums = "false" >
2017-03-27 11:08:53 -04:00
< / code-example >
2017-02-22 13:09:39 -05:00
2017-03-31 19:57:13 -04:00
2017-02-22 13:09:39 -05:00
Notice that you do _not_ load the application code explicitly.
You tell Webpack to find and load the test files (the files ending in `.spec.ts` ).
2017-03-27 11:08:53 -04:00
Each spec file imports all— and only— the application source code that it tests.
2017-02-22 13:09:39 -05:00
Webpack loads just _those_ specific application files and ignores the other files that you aren't testing.
2017-03-31 19:57:13 -04:00
2017-02-22 13:09:39 -05:00
Grab the app code at the end of this guide and try:
2017-03-30 15:04:18 -04:00
2017-02-22 13:09:39 -05:00
< code-example language = "sh" class = "code-shell" >
2017-03-31 19:57:13 -04:00
npm test
2017-02-22 13:09:39 -05:00
< / code-example >
2017-03-31 19:57:13 -04:00
{@a try}
## Trying it out
2017-02-22 13:09:39 -05:00
Here is the source code for a small application that bundles with the
Webpack techniques covered in this guide.
2017-03-27 11:08:53 -04:00
< code-tabs >
< code-pane title = "src/index.html" path = "webpack/src/index.html" >
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
< / code-pane >
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
< code-pane title = "src/main.ts" path = "webpack/src/main.ts" >
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
< / code-pane >
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
< code-pane title = "src/assets/css/styles.css" path = "webpack/src/assets/css/styles.css" >
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
< / code-pane >
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
< / code-tabs >
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
< code-tabs >
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
< code-pane title = "src/app/app.component.ts" path = "webpack/src/app/app.component.ts" >
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
< / code-pane >
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
< code-pane title = "src/app/app.component.html" path = "webpack/src/app/app.component.html" >
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
< / code-pane >
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
< code-pane title = "src/app/app.component.css" path = "webpack/src/app/app.component.css" >
< / code-pane >
< code-pane title = "src/app/app.component.spec.ts" path = "webpack/src/app/app.component.spec.ts" >
< / code-pane >
< code-pane title = "src/app/app.module.ts" path = "webpack/src/app/app.module.ts" >
< / code-pane >
< / code-tabs >
2017-02-22 13:09:39 -05:00
2017-03-31 19:57:13 -04:00
2017-03-06 05:43:33 -05:00
The < code > app.component.html< / code > displays this downloadable Angular logo
2017-04-24 14:23:45 -04:00
< a href = "assets/images/logos/angular/angular.png" >
2017-03-31 05:50:15 -04:00
< img src = "assets/images/logos/angular/angular.png" height = "40px" title = "download Angular logo" > < / a > .
2017-05-03 08:55:00 -04:00
Create a folder called `images` under the project's `assets` folder, then right-click (Cmd+click on Mac)
2017-03-27 11:08:53 -04:00
on the image and download it to that folder.
2017-02-22 13:09:39 -05:00
{@a bundle-ts}
2017-03-31 19:57:13 -04:00
2017-02-22 13:09:39 -05:00
Here again are the TypeScript entry-point files that define the `polyfills` and `vendor` bundles.
2017-03-27 11:08:53 -04:00
< code-tabs >
< code-pane title = "src/polyfills.ts" path = "webpack/src/polyfills.ts" >
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
< / code-pane >
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
< code-pane title = "src/vendor.ts" path = "webpack/src/vendor.ts" >
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
< / code-pane >
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
< / code-tabs >
2017-03-31 19:57:13 -04:00
{@a highlights}
2017-05-26 15:28:06 -04:00
< h3 class = "no-toc" > Highlights< / h3 >
2017-03-27 11:08:53 -04:00
* There are no `<script>` or `<link>` tags in the `index.html` .
2017-02-22 13:09:39 -05:00
The `HtmlWebpackPlugin` inserts them dynamically at runtime.
2017-03-27 11:08:53 -04:00
2017-02-22 13:09:39 -05:00
* The `AppComponent` in `app.component.ts` imports the application-wide css with a simple `import` statement.
2017-03-27 11:08:53 -04:00
* The `AppComponent` itself has its own html template and css file. WebPack loads them with calls to `require()` .
2017-02-22 13:09:39 -05:00
Webpack stashes those component-scoped files in the `app.js` bundle too.
2017-03-27 11:08:53 -04:00
You don't see those calls in the source code;
they're added behind the scenes by the `angular2-template-loader` plug-in.
2017-02-22 13:09:39 -05:00
* The `vendor.ts` consists of vendor dependency `import` statements that drive the `vendor.js` bundle.
The application imports these modules too; they'd be duplicated in the `app.js` bundle
if the `CommonsChunkPlugin` hadn't detected the overlap and removed them from `app.js` .
2017-03-31 19:57:13 -04:00
{@a conclusion}
## Conclusion
2017-02-22 13:09:39 -05:00
2017-03-27 11:08:53 -04:00
You've learned just enough Webpack to configurate development, test and production builds
2017-02-22 13:09:39 -05:00
for a small Angular application.
_You could always do more_. Search the web for expert advice and expand your Webpack knowledge.
2017-04-20 07:33:31 -04:00
[Back to top ](guide/webpack#top )