Skip to content
This repository was archived by the owner on Dec 4, 2017. It is now read-only.

Commit 8968e5e

Browse files
committed
feat(prod-deploy): add prod deploy chapter
1 parent 8cab0ef commit 8968e5e

File tree

2 files changed

+321
-0
lines changed

2 files changed

+321
-0
lines changed

public/docs/ts/latest/cookbook/_data.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@
1010
"intro": "Learn how to use Ahead-of-time compilation"
1111
},
1212

13+
"production-deploy": {
14+
"title": "Production Deploy",
15+
"intro": "Learn how to deploy your Angular app to production"
16+
},
17+
1318
"a1-a2-quick-reference": {
1419
"title": "Angular 1 to 2 Quick Reference",
1520
"navTitle": "Angular 1 to 2 Quick Ref",
Lines changed: 316 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,316 @@
1+
include ../_util-fns
2+
3+
:marked
4+
This cookbook describes how to optimize and deploy your Angular app to production.
5+
6+
a#toc
7+
:marked
8+
## Table of Contents
9+
* [Overview](#overview)
10+
* [Simplest deploy possible](#simplest-deploy-possible)
11+
* [Minimizing your payload](#minimizing-your-payload)
12+
* [Less files](#less-files)
13+
* [Smaller files](#smaller-files)
14+
* [Template compilation](#template-compilation)
15+
* [Angular configuration](#angular-configuration)
16+
* [The `base` tag](#the-base-tag)
17+
* [enableProdMode](#enableprodmode)
18+
* [Lazy loading](#lazy-loading)
19+
* [Server configuration](#server-configuration)
20+
* [Why fallback to `index.html`?](#why-fallback-to-index-html-)
21+
* [Fallback configuration examples](#fallback-configuration-examples)
22+
23+
a#overview
24+
.l-main-section
25+
:marked
26+
## Overview
27+
28+
After creating your brand new Angular app you'll want to put it online for the world to see.
29+
30+
Your development setup is optimized for build speed and rapid iteration, but when
31+
deployment to production you'll want to optimize for loading speed and payload size.
32+
33+
In this chapter you'll see how to deploy your app right now, techniques to reduce your
34+
payload size, plus Angular and server configuration.
35+
36+
.l-main-section
37+
:marked
38+
## Simplest deploy possible
39+
40+
The simplest possible way to deploy your app is to use your development environment.
41+
It is already working locally after all, so it should work live.
42+
43+
1. Copy over your local project folder to your server.
44+
2. In your server, edit `index.html` to have the right `<base href="/">` tag. If you are
45+
using a subfolder (e.g. `www.mysite.com/myapp/`) it should be `/myapp/` otherwise leave it as `/`.
46+
[More on this later](#angular-configuration).
47+
3. Configure your server to redirect requests for missing files to `index.html` instead.
48+
[More on this later](#server-configuration).
49+
50+
And this is all you need to publish your app!
51+
52+
It's not a very good production deploy though.
53+
There's more you can do to make our site fast for users.
54+
55+
.l-main-section
56+
:marked
57+
## Minimizing your payload
58+
59+
One of the easiest optimizations you can do is to reduce the code users have to download.
60+
61+
There are several techniques for achieving a smaller payload for your app:
62+
63+
- Bundling: concatenating several modules into a single file (bundle).
64+
- Inlining: add html and css as strings inside components.
65+
- Minification: removing all unnecessary whitespace and optional tokens.
66+
- Uglification: rewriting code to use shorter variable/function names.
67+
- Dead Code Elimination: removing code/variables that will never used.
68+
- Tree shaking: removing unused module exports.
69+
- Ahead-of-Time (AoT) Compilation: pre-compiling Angular templates.
70+
71+
Each of these do different things overall, but they all work together and their effects
72+
compound on each other.
73+
74+
### Less files
75+
Bundling and inlining reduce your app's load time smaller by serving less files and thus
76+
less round trips.
77+
For small files, the overwhelming majority of time it takes to get it is not spent downloading,
78+
but rather communicating with the server and coordinating the transfer.
79+
You can read more about resource timings in the
80+
[Chrome DevTools Network Performance page](https://developers.google.com/web/tools/chrome-devtools/network-performance/understanding-resource-timing)
81+
82+
### Smaller files
83+
Minification, Uglification and Dead Code Elimination all contribute to reduce the total size
84+
of your code to the smallest possible amount of bytes, which will result in a smaller
85+
transfer time.
86+
87+
Tree shaking also reduces the total size but does so by removing whole exports from modules.
88+
It was popularized by [Rollup](http://rollupjs.org/) and you can read more about it in
89+
[this post](https://medium.com/@Rich_Harris/tree-shaking-versus-dead-code-elimination-d3765df85c80#.15ih9cyvl).
90+
91+
### Template compilation
92+
AoT compilation reduces render time by pre-compiling Angular templates that otherwise would be
93+
compiled at runtime.
94+
It also reduces payload size since the Angular compiler itself is no longer needed, and nor are
95+
directives that are never used in templates. This allows Tree-Shaking to further remove exports.
96+
97+
You can read more about AoT Compilation in our [dedicated cookbook chapter](aot-compiler.html),
98+
where you'll also find instructions on how to use Rollup to do all the optimizations shown here.
99+
Another great choice is [Webpack 2](https://webpack.js.org/) together with the
100+
[Angular Ahead-of-Time Webpack Plugin](https://github.com/angular/angular-cli/tree/master/packages/%40ngtools/webpack).
101+
102+
You can use any build system you like however, the only important thing is to optimize your build.
103+
Whatever build system you choose make sure to automate it so that you can make a production
104+
build in a single step.
105+
106+
.l-main-section
107+
:marked
108+
## Angular configuration
109+
110+
### The `base` tag
111+
112+
There is an important configuration item in the Angular Router that needs to be adjusted for
113+
different environments:
114+
[the `base` tags `href` property](https://angular.io/docs/ts/latest/guide/router.html#!#base-href).
115+
This property tells the router how what the app root URL is so that the router can match routes.
116+
117+
On your development server, your app is most likely served at the root: `http://localhost:3000/`.
118+
Here you use `<base href="/">`, since `/` is the root of your app.
119+
120+
But depending on the server setup that you use, it can also be served in a subfolder like
121+
`http://localhost:3000/myapp/` or `http://www.mysite.com/myapp/`, where `/myapp/` is the subfolder.
122+
In this case you should use `<base href="/myapp/">`, since `/myapp/` is the root of your app and
123+
not `/`.
124+
125+
When your `base` tag is misconfigured your browser console will show several console, from
126+
missing files on wrong paths to router errors about missing routes.
127+
128+
### enableProdMode
129+
130+
You can also configure your Angular app to start on
131+
[production mode](https://angular.io/docs/ts/latest/api/core/index/enableProdMode-function.html),
132+
which will make it faster by disabling development specific checks.
133+
134+
Angular apps default do development move, as you can see by the following message on the browser
135+
console:
136+
137+
code-example(format="nocode").
138+
Angular 2 is running in the development mode. Call enableProdMode() to enable the production mode.
139+
140+
:marked
141+
To enable production mode, add this code to the start of your `main.ts`:
142+
143+
code-example().
144+
import { enableProdMode } from '@angular/core';
145+
enableProdMode();
146+
147+
:marked
148+
### Lazy loading
149+
150+
The Angular Router allows you to configure NgModules as being
151+
[Lazy Loaded](https://angular.io/docs/ts/latest/guide/router.html#!#asynchronous-routing),
152+
which means that particular NgModule (and all it's code) is not loaded on the very first load.
153+
This allows your app to have a smaller initial load time by not loading modules until they
154+
are needed.
155+
156+
A common mistake to make while lazy loading a module is to *also* have that module imported via
157+
a ES6 import.
158+
If you do that, the module will never really be lazy loaded since the import statement will cause
159+
it to be imported directly instead of being imported via the Router.
160+
161+
It's important to note that your bundling configuration must take lazy loading into consideration.
162+
Since there is no ES6 import for that module, normal bundlers don't know that they should also
163+
separately bundle to module listed in the router config.
164+
You have to manually create additional bundles for each lazy loaded route.
165+
166+
If you are using Webpack, the
167+
[Angular Ahead-of-Time Webpack Plugin](https://github.com/angular/angular-cli/tree/master/packages/%40ngtools/webpack)
168+
will automatically recognize lazy routes.
169+
170+
171+
.l-main-section
172+
:marked
173+
## Server configuration
174+
175+
Angular apps are
176+
[Single Page Applications](https://en.wikipedia.org/wiki/Single-page_application) (SPAs),
177+
which makes them the perfect candidates to be served by simple static HTML server.
178+
No preprocessors required!
179+
180+
There is only one configuration item required of a server hosting an Angular app:
181+
it needs to be able to fallback to `index.html` when being asked for a file the server
182+
does not have.
183+
184+
### Why fallback to `index.html`?
185+
186+
When using the Angular Router, it is the one in charge of the routing instead of your server.
187+
Angular routing defaults to
188+
[HTML 5 pushState](https://angular.io/docs/ts/latest/guide/router.html#!#browser-url-styles),
189+
where it manipulates the browser address and history directly.
190+
So, while the server has the responsability of serving the files, it is always the Angular app
191+
that will determine which routes are valid and construct the page accordingly.
192+
193+
Imagine you have the `admin/` route for your `www.my-awesome-app.com` Angular app.
194+
When you visit `www.my-awesome-app.com` most servers will respond with
195+
the `index.html` located at `www.my-awesome-app.com/index.html`.
196+
Then you click the link for `admin/` and the your address bar will change
197+
to `www.my-awesome-app.com/admin/` and you're taken to the admin page.
198+
199+
But if you don't have fallback to `index.html` configured and refresh the page, you will
200+
get a `404 - Not Found` page!
201+
Which doesn't make a lot of sense since you just saw that the admin page was there.
202+
203+
When you first clicked the link to `admin/` there was no server request for
204+
`www.my-awesome-app.com/admin/` because Angular manipulated the browser URL directly.
205+
206+
But when you refresh the `www.my-awesome-app.com/admin/` url, you are not asking *Angular*
207+
for the admin route but rather *the server*.
208+
And the server does not have a `www.my-awesome-app.com/admin/index.html` to serve, so it instead
209+
shows you a 404.
210+
211+
That is why the server needs to be configured to fallback to `index.html`.
212+
When a user asks the server for any route (that isn't a file), you want the server to *always*
213+
return default page that boots up Angular.
214+
After Angular is loaded and bootstrapped the router will look at the address bar and take
215+
the user where he needs to go.
216+
217+
### Fallback configuration examples
218+
219+
Different servers are configured in different ways so there is no single configuration that
220+
works everywhere.
221+
222+
Following are configurations for some of the most popular servers.
223+
The list is by no means exhausting, but should provide you with a good starting point.
224+
225+
#### Development servers
226+
227+
- [Lite-Server](https://github.com/johnpapa/lite-server): the default dev server used in the
228+
[Quickstart repo](https://github.com/angular/quickstart), and by default will fallback to
229+
`index.html`.
230+
231+
- [Webpack-Dev-Server](https://github.com/webpack/webpack-dev-server): you can use the
232+
`historyApiFallback` entry in the dev server options as follows:
233+
234+
code-example().
235+
historyApiFallback: {
236+
disableDotRule: true,
237+
htmlAcceptHeaders: ['text/html', 'application/xhtml+xml']
238+
}
239+
240+
:marked
241+
#### Production servers
242+
243+
- [Apache](https://httpd.apache.org/): simply add a
244+
[rewrite rule](http://httpd.apache.org/docs/current/mod/mod_rewrite.html)
245+
to your `.htaccess` file as show
246+
[here](https://ngmilk.rocks/2015/03/09/angularjs-html5-mode-or-pretty-urls-on-apache-using-htaccess/):
247+
code-example(format=".").
248+
RewriteEngine On
249+
# If an existing asset or directory is requested go to it as it is
250+
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
251+
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
252+
RewriteRule ^ - [L]
253+
254+
# If the requested resource doesn't exist, use index.html
255+
RewriteRule ^ /index.html
256+
257+
:marked
258+
- [NGinx](http://nginx.org/): you can use `try_files` similar to the one described in
259+
[Front Controller Pattern Web Apps](https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#front-controller-pattern-web-apps),
260+
modified for serving `index.html`:
261+
262+
code-example(format=".").
263+
try_files $uri $uri/ /index.html;
264+
265+
:marked
266+
- [IIS](https://www.iis.net/): you can add a rewrite rule on `web.config`, similar to the one shown
267+
[here](http://stackoverflow.com/a/26152011/2116927):
268+
code-example(format="." escape="html").
269+
<system.webServer>
270+
<rewrite>
271+
<rules>
272+
<rule name="Angular Routes" stopProcessing="true">
273+
<match url=".*" />
274+
<conditions logicalGrouping="MatchAll">
275+
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
276+
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
277+
</conditions>
278+
<action type="Rewrite" url="/" />
279+
</rule>
280+
</rules>
281+
</rewrite>
282+
</system.webServer>
283+
284+
:marked
285+
- [GitHub Pages](https://pages.github.com/): you can't
286+
[directly configure](https://github.com/isaacs/github/issues/408)
287+
the server used to serve GitHub Pages, but you can add a 404 page.
288+
Simply copy `index.html` into `404.html`.
289+
It will still be served with the 404 response, but the app will still load properly.
290+
It's also a good idea to
291+
[serve from `docs/` on master](https://help.github.com/articles/configuring-a-publishing-source-for-github-pages/#publishing-your-github-pages-site-from-a-docs-folder-on-your-master-branch)
292+
and to
293+
[create a `.nojekyll` file](https://www.bennadel.com/blog/3181-including-node-modules-and-vendors-folders-in-your-github-pages-site.htm)
294+
295+
- [Firebase hosting](https://firebase.google.com/docs/hosting/): you can use a simple
296+
[rewrite](https://firebase.google.com/docs/hosting/url-redirects-rewrites#section-rewrites).
297+
298+
code-example(format=".").
299+
"rewrites": [ {
300+
"source": "**",
301+
"destination": "/index.html"
302+
} ]
303+
304+
:marked
305+
### CORS
306+
307+
A common issue developers come across when working on SPAs is
308+
[Cross-origin resource sharing](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing)
309+
errors.
310+
These are not due to the SPA application itself but rather due to the configuration of APIs with
311+
which the SPA communicates.
312+
313+
These APIs need to send the `Access-Control-Allow-Origin: *` header on their HTTP responses,
314+
otherwise the SPA will not be able to call them.
315+
You can read more about how to enable CORS for specific servers in
316+
[enable-cors.org](http://enable-cors.org/server.html)

0 commit comments

Comments
 (0)