/`.
Check out [angular-cli-ghpages](https://github.com/angular-buch/angular-cli-ghpages), a full featured package that does all this for you and has extra functionality.
{@a server-configuration}
## Server configuration
This section covers changes you may have to make to the server or to files deployed on the server.
{@a fallback}
### Routed apps must fallback to `index.html`
Angular applications are perfect candidates for serving with a simple static HTML server.
You don't need a server-side engine to dynamically compose application pages because
Angular does that on the client-side.
If the application uses the Angular router, you must configure the server
to return the application's host page (`index.html`) when asked for a file that it does not have.
{@a deep-link}
A routed application should support "deep links".
A _deep link_ is a URL that specifies a path to a component inside the application.
For example, `http://www.mysite.com/heroes/42` is a _deep link_ to the hero detail page
that displays the hero with `id: 42`.
There is no issue when the user navigates to that URL from within a running client.
The Angular router interprets the URL and routes to that page and hero.
But clicking a link in an email, entering it in the browser address bar,
or merely refreshing the browser while on the hero detail page —
all of these actions are handled by the browser itself, _outside_ the running application.
The browser makes a direct request to the server for that URL, bypassing the router.
A static server routinely returns `index.html` when it receives a request for `http://www.mysite.com/`.
But it rejects `http://www.mysite.com/heroes/42` and returns a `404 - Not Found` error *unless* it is
configured to return `index.html` instead.
#### Fallback configuration examples
There is no single configuration that works for every server.
The following sections describe configurations for some of the most popular servers.
The list is by no means exhaustive, but should provide you with a good starting point.
* [Apache](https://httpd.apache.org/): add a
[rewrite rule](https://httpd.apache.org/docs/current/mod/mod_rewrite.html) to the `.htaccess` file as shown
(https://ngmilk.rocks/2015/03/09/angularjs-html5-mode-or-pretty-urls-on-apache-using-htaccess/):
RewriteEngine On
# If an existing asset or directory is requested go to it as it is
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]
# If the requested resource doesn't exist, use index.html
RewriteRule ^ /index.html
* [Nginx](https://nginx.org/): use `try_files`, as described in
[Front Controller Pattern Web Apps](https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#front-controller-pattern-web-apps),
modified to serve `index.html`:
```
try_files $uri $uri/ /index.html;
```
* [Ruby](https://www.ruby-lang.org/): create a Ruby server using ([sinatra](http://sinatrarb.com/)) with a basic Ruby file that configures the server `server.rb`:
```ruby
require 'sinatra'
# Folder structure
# .
# -- server.rb
# -- public
# |-- project-name
# |-- index.html
get '/' do
folderDir = settings.public_folder + '/project-name' # ng build output folder
send_file File.join(folderDir, 'index.html')
end
```
* [IIS](https://www.iis.net/): add a rewrite rule to `web.config`, similar to the one shown
[here](https://stackoverflow.com/a/26152011):
<system.webServer>
<rewrite>
<rules>
<rule name="Angular Routes" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="/index.html" />
</rule>
</rules>
</rewrite>
</system.webServer>
* [GitHub Pages](https://pages.github.com/): you can't
[directly configure](https://github.com/isaacs/github/issues/408)
the GitHub Pages server, but you can add a 404 page.
Copy `index.html` into `404.html`.
It will still be served as the 404 response, but the browser will process that page and load the application properly.
It's also a good idea to
[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)
and to
[create a `.nojekyll` file](https://www.bennadel.com/blog/3181-including-node-modules-and-vendors-folders-in-your-github-pages-site.htm)
* [Firebase hosting](https://firebase.google.com/docs/hosting/): add a
[rewrite rule](https://firebase.google.com/docs/hosting/url-redirects-rewrites#section-rewrites).
"rewrites": [ {
"source": "**",
"destination": "/index.html"
} ]
{@a mime}
### Configuring correct MIME-type for JavaScript assets
All of your application JavaScript files must be served by the server with the [`Content-Type` header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type) set to `text/javascript` or another [JavaScript-compatible MIME-type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#textjavascript).
Most servers and hosting services already do this by default.
Server with misconfigured mime-type for JavaScript files will cause an application to fail to start with the following error:
```
Failed to load module script: The server responded with a non-JavaScript MIME type of "text/plain". Strict MIME type checking is enforced for module scripts per HTML spec.
```
If this is the case, you will need to check your server configuration and reconfigure it to serve `.js` files with `Content-Type: text/javascript`. See your server's manual for instructions on how to do this.
{@a cors}
### Requesting services from a different server (CORS)
Angular developers may encounter a
cross-origin resource sharing error when making a service request (typically a data service request)
to a server other than the application's own host server.
Browsers forbid such requests unless the server permits them explicitly.
There isn't anything the client application can do about these errors.
The server must be configured to accept the application's requests.
Read about how to enable CORS for specific servers at
enable-cors.org.
{@a optimize}
## Production optimizations
The `production` configuration engages the following build optimization features.
* [Ahead-of-Time (AOT) Compilation](guide/aot-compiler): pre-compiles Angular component templates.
* [Production mode](#enable-prod-mode): deploys the production environment which enables _production mode_.
* Bundling: concatenates your many application and library files into a few bundles.
* Minification: removes excess whitespace, comments, and optional tokens.
* Uglification: rewrites code to use short, cryptic variable and function names.
* Dead code elimination: removes unreferenced modules and much unused code.
See [`ng build`](cli/build) for more about CLI build options and what they do.
{@a enable-prod-mode}
### Enable runtime production mode
In addition to build optimizations, Angular also has a runtime production mode. Angular applications run in development mode by default, as you can see by the following message on the browser console:
Angular is running in development mode. Call enableProdMode() to enable production mode.
_Production mode_ improves application performance by disabling development-only safety
checks and debugging utilities, such as the expression-changed-after-checked detection.
Building your application with the production configuration automatically enables Angular's
runtime production mode.
{@a lazy-loading}
### Lazy loading
You can dramatically reduce launch time by only loading the application modules that
absolutely must be present when the application starts.
Configure the Angular Router to defer loading of all other modules (and their associated code), either by
[waiting until the app has launched](guide/router-tutorial-toh#preloading "Preloading")
or by [_lazy loading_](guide/router#lazy-loading "Lazy loading")
them on demand.
Don't eagerly import something from a lazy-loaded module
If you mean to lazy-load a module, be careful not to import it
in a file that's eagerly loaded when the application starts (such as the root `AppModule`).
If you do that, the module will be loaded immediately.
The bundling configuration must take lazy loading into consideration.
Because lazy-loaded modules aren't imported in JavaScript, bundlers exclude them by default.
Bundlers don't know about the router configuration and can't create separate bundles for lazy-loaded modules.
You would have to create these bundles manually.
The CLI runs the
[Angular Ahead-of-Time Webpack Plugin](https://github.com/angular/angular-cli/tree/master/packages/ngtools/webpack)
which automatically recognizes lazy-loaded `NgModules` and creates separate bundles for them.
{@a measure}
### Measure performance
You can make better decisions about what to optimize and how when you have a clear and accurate understanding of
what's making the application slow.
The cause may not be what you think it is.
You can waste a lot of time and money optimizing something that has no tangible benefit or even makes the application slower.
You should measure the application's actual behavior when running in the environments that are important to you.
The
Chrome DevTools Network Performance page is a good place to start learning about measuring performance.
The [WebPageTest](https://www.webpagetest.org/) tool is another good choice
that can also help verify that your deployment was successful.
{@a inspect-bundle}
### Inspect the bundles
The source-map-explorer
tool is a great way to inspect the generated JavaScript bundles after a production build.
Install `source-map-explorer`:
npm install source-map-explorer --save-dev
Build your application for production _including the source maps_
ng build --source-map
List the generated bundles in the `dist/project-name/` folder.
ls dist/project-name/*.js
Run the explorer to generate a graphical representation of one of the bundles.
The following example displays the graph for the _main_ bundle.
node_modules/.bin/source-map-explorer dist/project-name/main*
The `source-map-explorer` analyzes the source map generated with the bundle and draws a map of all dependencies,
showing exactly which classes are included in the bundle.
Here's the output for the _main_ bundle of an example application called `cli-quickstart`.
{@a base-tag}
## The `base` tag
The HTML [_<base href="..."/>_](/guide/router)
specifies a base path for resolving relative URLs to assets such as images, scripts, and style sheets.
For example, given the ``, the browser resolves a URL such as `some/place/foo.jpg`
into a server request for `my/app/some/place/foo.jpg`.
During navigation, the Angular router uses the _base href_ as the base path to component, template, and module files.
See also the [*APP_BASE_HREF*](api/common/APP_BASE_HREF "API: APP_BASE_HREF") alternative.
In development, you typically start the server in the folder that holds `index.html`.
That's the root folder and you'd add `` near the top of `index.html` because `/` is the root of the application.
But on the shared or production server, you might serve the application from a subfolder.
For example, when the URL to load the application is something like `http://www.mysite.com/my/app/`,
the subfolder is `my/app/` and you should add `` to the server version of the `index.html`.
When the `base` tag is mis-configured, the application fails to load and the browser console displays `404 - Not Found` errors
for the missing files. Look at where it _tried_ to find those files and adjust the base tag appropriately.
{@a deploy-url}
## The `deploy` url
A command line option used to specify the base path for resolving relative URLs for assets such as images, scripts, and style sheets at _compile_ time. For example: `ng build --deploy-url /my/assets`.
The effects of defining a `deploy url` and `base href` can overlap.
* Both can be used for initial scripts, stylesheets, lazy scripts, and css resources.
However, defining a `base href` has a few unique effects.
* Defining a `base href` can be used for locating relative template (HTML) assets, and relative fetch/XMLHttpRequests.
The `base href` can also be used to define the Angular router's default base (see [APP_BASE_HREF](https://angular.io/api/common/APP_BASE_HREF)). Users with more complicated setups may need to manually configure the `APP_BASE_HREF` token within the application. (e.g., application routing base is / but assets/scripts/etc. are at /assets/).
Unlike the `base href` which can be defined in a single place, the `deploy url` needs to be hard-coded into an application at build time. This means specifying a `deploy url` will decrease build speed, but this is the unfortunate cost of using an option that embeds itself throughout an application. That is why a `base href` is generally the better option.
{@a differential-loading}
## Differential Loading
When building web applications, you want to make sure your application is compatible with the majority of browsers.
Even as JavaScript continues to evolve, with new features being introduced, not all browsers are updated with support for these new features at the same pace.
The code you write in development using TypeScript is compiled and bundled into ES2015, the JavaScript syntax that is compatible with most browsers.
All modern browsers support ES2015 and beyond, but in most cases, you still have to account for users accessing your application from a browser that doesn't.
When targeting older browsers, [polyfills](guide/browser-support#polyfills) can bridge the gap by providing functionality that doesn't exist in the older versions of JavaScript supported by those browsers.
To maximize compatibility, you could ship a single bundle that includes all your compiled code, plus any polyfills that may be needed.
Users with modern browsers, however, shouldn't have to pay the price of increased bundle size that comes with polyfills they don't need.
Differential loading, which is supported in Angular CLI version 8 and higher, can help solve this problem.
Differential loading is a strategy that allows your web application to support multiple browsers, but only load the necessary code that the browser needs. When differential loading is enabled the CLI builds two separate bundles as part of your deployed application.
* The first bundle contains modern ES2015 syntax. This bundle takes advantage of built-in support in modern browsers, ships fewer polyfills, and results in a smaller bundle size.
* The second bundle contains code in the old ES5 syntax, along with all necessary polyfills. This second bundle is larger, but supports older browsers.
### Differential builds
When you deploy using the Angular CLI build process, you can choose how and when to support differential loading.
The [`ng build` CLI command](cli/build) queries the browser configuration and the configured build target to determine if support for legacy browsers is required, and whether the build should produce the necessary bundles used for differential loading.
The following configurations determine your requirements.
* Browserslist
The Browserslist configuration file is included in your application [project structure](guide/file-structure#application-configuration-files) and provides the minimum browsers your application supports. See the [Browserslist spec](https://github.com/browserslist/browserslist) for complete configuration options.
* TypeScript configuration
In the TypeScript configuration file, the "target" option in the `compilerOptions` section determines the ECMAScript target version that the code is compiled to.
Modern browsers support ES2015 natively, while ES5 is more commonly used to support legacy browsers.
Differential loading is currently only supported when using `es2015` as a compilation target. When used with targets higher than `es2015`, the build process emits a warning.
For a development build, the output produced by `ng build` is simpler and easier to debug, allowing you to rely less on sourcemaps of compiled code.
For a production build, your configuration determines which bundles are created for deployment of your application.
When needed, the `index.html` file is also modified during the build process to include script tags that enable differential loading, as shown in the following example.
<body>
<app-root></app-root>
<script src="runtime-es2015.js" type="module"></script>
<script src="runtime-es5.js" nomodule></script>
<script src="polyfills-es2015.js" type="module"></script>
<script src="polyfills-es5.js" nomodule></script>
<script src="styles-es2015.js" type="module"></script>
<script src="styles-es5.js" nomodule></script>
<script src="vendor-es2015.js" type="module"></script>
<script src="vendor-es5.js" nomodule></script>
<script src="main-es2015.js" type="module"></script>
<script src="main-es5.js" nomodule></script>
</body>
Each script tag has a `type="module"` or `nomodule` attribute. Browsers with native support for ES modules only load the scripts with the `module` type attribute and ignore scripts with the `nomodule` attribute. Legacy browsers only load the scripts with the `nomodule` attribute, and ignore the script tags with the `module` type that load ES modules.
Some legacy browsers still download both bundles, but only execute the appropriate scripts based on the attributes mentioned above. You can read more on the issue [here](https://github.com/philipwalton/webpack-esnext-boilerplate/issues/1).
### Configuring differential loading
To include differential loading in your application builds, you must configure the Browserslist and TypeScript configuration files in your application project.
The following examples show a `.browserslistrc` and `tsconfig.json` file for a newly created Angular application. In this configuration, legacy browsers such as IE 9-11 are ignored, and the compilation target is ES2015.
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries
# For the full list of supported browsers by the Angular framework, please see:
# https://angular.io/guide/browser-support
# You can see what browsers were selected by your queries by running:
# npx browserslist
last 1 Chrome version
last 1 Firefox version
last 2 Edge major versions
last 2 Safari major versions
last 2 iOS major versions
Firefox ESR
not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"module": "esnext",
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"importHelpers": true,
"target": "es2015",
"typeRoots": [
"node_modules/@types"
],
"lib": [
"es2018",
"dom"
]
}
}
To see which browsers are supported and determine which settings meet to your browser support requirements, see the [Browserslist compatibility page](https://browserl.ist/?q=%3E+0.5%25%2C+last+2+versions%2C+Firefox+ESR%2C+not+dead%2C+not+IE+9-11).
The Browserslist configuration allows you to ignore browsers without ES2015 support. In this case, a single build is produced.
If your Browserslist configuration includes support for any legacy browsers, the build target in the TypeScript configuration determines whether the build will support differential loading.
{@a configuration-table }
| Browserslist | ES target | Build result |
| -------- | -------- | -------- |
| ES5 support disabled | es2015 | Single build, ES5 not required |
| ES5 support enabled | es5 | Single build w/conditional polyfills for ES5 only |
| ES5 support enabled | es2015 | Differential loading (two builds w/conditional polyfills) |
{@a test-and-serve}
## Local development in older browsers
Differential loading is not enabled by default for application projects that were generated with Angular CLI 10 and above.
The `ng serve`, `ng test`, and `ng e2e` commands, however, generate a single ES2015 build which cannot run in older browsers that don't support the modules, such as IE 11.
To maintain the benefits of differential loading, however, a better option is to define multiple configurations for `ng serve`, `ng e2e`, and `ng test`.
{@a differential-serve}
### Configuring serve for ES5
To do this for `ng serve`, create a new file, `tsconfig-es5.app.json` next to `tsconfig.app.json` with the following content.
{
"extends": "./tsconfig.app.json",
"compilerOptions": {
"target": "es5"
}
}
In `angular.json` add two new configuration sections under the `build` and `serve` targets to point to the new TypeScript configuration.
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
...
},
"configurations": {
"production": {
...
},
"es5": {
"tsConfig": "./tsconfig-es5.app.json"
}
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
...
},
"configurations": {
"production": {
...
},
"es5": {
"browserTarget": "<app-name>:build:es5"
}
}
},
You can then run the `ng serve` command with this configuration. Make sure to replace `` (in `":build:es5"`) with the actual name of the app, as it appears under `projects` in `angular.json`. For example, if your application name is `myAngularApp` the configuration will become `"browserTarget": "myAngularApp:build:es5"`.
ng serve --configuration es5
{@a differential-test}
### Configuring the test command
Create a new file, `tsconfig-es5.spec.json` next to `tsconfig.spec.json` with the following content.
{
"extends": "./tsconfig.spec.json",
"compilerOptions": {
"target": "es5"
}
}
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
...
},
"configurations": {
"es5": {
"tsConfig": "./tsconfig-es5.spec.json"
}
}
},
You can then run the tests with this configuration
ng test --configuration es5