Angular DevTools is a browser extension that provides debugging and profiling capabilities for Angular applications. Angular DevTools supports Angular v12 and later when compiled with the optimization configuration option disabled ({optimization:false}).
You can find Angular DevTools in the Chrome Web Store and in Firefox Addons.
After installing Angular DevTools, find the extension under the Angular tab in your browser DevTools.
When you open the extension, you’ll see two additional tabs:
Tabs
Details
Components
Lets you explore the components and directives in your application and preview or edit their state.
Profiler
Lets you profile your application and understand what the performance bottleneck is during change detection execution.
In the top-right corner of Angular DevTools you’ll find which version of Angular is running on the page as well as the latest commit hash for the extension.
Bug reports
Report issues and feature requests on GitHub.
To report an issue with the Profiler, export the Profiler recording by clicking the Save Profile button, and then attaching that export as a file in the issue.
Make sure that the Profiler recording does not contain any confidential information.
Debug your application
The Components tab lets you explore the structure of your application. You can visualize and inspect the component and directive instances and preview or modify their state. In the next couple of sections we’ll look into how to use this tab effectively to debug your application.
Explore the application structure
In the preceding screenshot, you can see the component tree of an application.
The component tree displays a hierarchical relationship of the components and directives within your application. When you select a component or a directive instance, Angular DevTools presents additional information about that instance.
View properties
Click the individual components or directives in the component explorer to select them and preview their properties. Angular DevTools displays their properties and metadata on the right-hand side of the component tree.
Navigate in the component tree using the mouse or the following keyboard shortcuts:
Keyboard shortcut
Details
Up and down arrows
Select the previous and next nodes
Left and right arrows
Collapse and expand a node
To look up a component or directive by name use the search box above the component tree. To navigate to the next search match, press Enter. To navigate to the previous search match, press Shift + Enter.
Navigate to the host node
To go to the host element of a particular component or directive, find it in the component explorer and double-click it. Browsers’ DevTools opens the Elements tab in Chrome or the Inspector one in Firefox, and selects the associated DOM node.
Navigate to source
For components, Angular DevTools also lets you navigate to the component definition in the source tab. After you select a particular component, click the icon at the top-right of the properties view:
View injected services of components
Starting in Angular 17, services that are injected in a component or directive context are viewable in the property viewer. After you select a particular component, if that component has dependencies, you’ll be able to see them listed under the “Injected Services” bar.
By clicking on a service, an expansion panel will appear that visualizes the resolution path that Angular used to resolve that service.
Update property value
Like browsers’ DevTools, the properties view lets you edit the value of an input, output, or another property. Right-click on the property value. If edit functionality is available for this value type, you’ll see a text input. Type the new value and press Enter.
Access selected component or directive in console
As a shortcut in the console, Angular DevTools provides you access to instances of the recently selected components or directives. Type $ng0 to get a reference to the instance of the currently selected component or directive, and type $ng1 for the previously selected instance.
Select a directive or component
Similar to browsers’ DevTools, you can inspect the page to select a particular component or directive. Click the Inspect element icon in the top left corner within Angular DevTools and hover over a DOM element on the page. The extension recognizes the associated directives and/or components and lets you select the corresponding element in the Component tree.
Profile your application
The Profiler tab lets you preview the execution of Angular’s change detection.
The Profiler lets you start profiling or import an existing profile. To start profiling your application, hover over the circle in the top-left corner within the Profiler tab and click Start recording.
During profiling, Angular DevTools captures execution events, such as change detection and lifecycle hook execution. To finish recording, click the circle again to Stop recording.
You can also import an existing recording. Read more about this feature in the Import recording section.
Understand your application’s execution
In the following screenshot, find the default view of the Profiler after you complete recording.
Near the top of the view you can see a sequence of bars, each one of them symbolizing change detection cycles in your app. The taller a bar is, the longer your application has spent in this cycle. When you select a bar, DevTools renders a bar chart with all the components and directives that it captured during this cycle.
Earlier on the change detection timeline, you can find how much time Angular spent in this cycle. Angular DevTools attempts to estimate the frame drop at this point to indicate when the execution of your application might impact the user experience.
Angular DevTools also indicates what triggered the change detection (that is, the change detection’s source).
Understand component execution
When you click on a bar, you’ll find a detailed view about how much time your application spent in the particular directive or component:
Figure shows the total time spent by NgforOf directive and which method was called in it. It also shows the parent hierarchy of the directive selected.
Hierarchical views
You can also preview the change detection execution in a flame graph-like view. Each tile in the graph represents an element on the screen at a specific position in the render tree.
For example, if during one change detection cycle at a specific position in the component tree you had ComponentA, this component was removed and in its place Angular rendered ComponentB, you’ll see both components at the same tile.
Each tile is colored depending on how much time Angular spent there. DevTools determines the intensity of the color by the time spent relative to the tile where we’ve spent the most time in change detection.
When you click on a certain tile, you’ll see details about it in the panel on the right. Double-clicking the tile zooms it in so you can preview the nested children.
Debug OnPush
To preview the components in which Angular did change detection, select the Change detection checkbox at the top, above the flame graph.
This view colors all the tiles in which Angular performed change detection in green, and the rest in gray:
Import recording
Click the Save Profile button at the top-left of a recorded profiling session to export it as a JSON file and save it to the disk. Then, import the file in the initial view of the profiler by clicking the Choose file input:
Inspect your injectors
Note: The Injector Tree is available for Angular Applications built with version 17 or higher.
View the injector hierarchy of your application
The Injector Tree tab lets you explore the structure of the Injectors configured in your application. Here you will see two trees representing the injector hiearchy of your application. One tree is your environment hierarchy, the other is your element hierachy.
Visualize resolution paths
When a specific injector is selected, the path that Angular’s depenedency injection algorithm traverses from that injector to the root is highlighted. For element injectors, this includes highlighting the environment injectors that the dependency injection algorithm jumps to when a dependency cannot be resolved in the element hierarchy. See resolution rules for more details about how Angular resolves resolution paths.
View injector providers
Clicking an injector that has configured providers will display those providers in a list on the right of the injector tree view. Here you can view the provided token and it’s type.
Configuring compiler options for the Angular Language Service
To enable the latest Language Service features, set the strictTemplates option in tsconfig.json by setting strictTemplates to true, as shown in the following example:
For more information, see the Angular compiler options guide.
Features
Your editor autodetects that you are opening an Angular file. It then uses the Angular Language Service to read your tsconfig.json file, find all the templates you have in your application, and then provide language services for any templates that you open.
Language services include:
Completions lists
AOT Diagnostic messages
Quick info
Go to definition
Autocompletion
Autocompletion can speed up your development time by providing you with contextual possibilities and hints as you type. This example shows autocomplete in an interpolation. As you type it out, you can press tab to complete.
There are also completions within elements. Any elements you have as a component selector will show up in the completion list.
Error checking
The Angular Language Service can forewarn you of mistakes in your code. In this example, Angular doesn’t know what orders is or where it comes from.
Quick info and navigation
The quick-info feature lets you hover to see where components, directives, and modules come from. You can then click “Go to definition” or press F12 to go directly to the definition.
Angular Language Service in your editor
Angular Language Service is currently available as an extension for Visual Studio Code, WebStorm, Sublime Text and Eclipse IDE.
Visual Studio Code
In Visual Studio Code, install the extension from the Extensions: Marketplace. Open the marketplace from the editor using the Extensions icon on the left menu pane, or use VS Quick Open (⌘+P on Mac, CTRL+P on Windows) and type “? ext”. In the marketplace, search for Angular Language Service extension, and click the Install button.
The Visual Studio Code integration with the Angular language service is maintained and distributed by the Angular team.
Visual Studio
In Visual Studio, install the extension from the Extensions: Marketplace. Open the marketplace from the editor selecting Extensions on the top menu pane, and then selecting Manage Extensions. In the marketplace, search for Angular Language Service extension, and click the Install button.
The Visual Studio integration with the Angular language service is maintained and distributed by Microsoft with help from the Angular team. Check out the project here.
WebStorm
In WebStorm, enable the plugin Angular and AngularJS.
Since WebStorm 2019.1, the @angular/language-service is not required anymore and should be removed from your package.json.
Sublime Text
In Sublime Text, the Language Service supports only in-line templates when installed as a plug-in. You need a custom Sublime plug-in (or modifications to the current plug-in) for completions in HTML files.
To use the Language Service for in-line templates, you must first add an extension to allow TypeScript, then install the Angular Language Service plug-in. Starting with TypeScript 2.3, TypeScript has a plug-in model that the language service can use.
Install the latest version of TypeScript in a local node_modules directory:content_copynpm install --save-dev typescript
Install the Angular Language Service package in the same location:content_copynpm install --save-dev @angular/language-service
Once the package is installed, add the following to the "compilerOptions" section of your project’s tsconfig.json.tsconfig.jsoncontent_copy"plugins": [ {"name": "@angular/language-service"} ]
In your editor’s user preferences (Cmd+, or Ctrl+,), add the following:Sublime Text user preferencescontent_copy"typescript-tsdk": "<path to your folder>/node_modules/typescript/lib"
This lets the Angular Language Service provide diagnostics and completions in .ts files.
Eclipse IDE
Either directly install the “Eclipse IDE for Web and JavaScript developers” package which comes with the Angular Language Server included, or from other Eclipse IDE packages, use Help > Eclipse Marketplace to find and install Eclipse Wild Web Developer.
When you use an editor with a language service, the editor starts a separate language-service process and communicates with it through an RPC, using the Language Server Protocol. When you type into the editor, the editor sends information to the language-service process to track the state of your project.
When you trigger a completion list within a template, the editor first parses the template into an HTML abstract syntax tree (AST). The Angular compiler interprets that tree to determine the context: which module the template is part of, the current scope, the component selector, and where your cursor is in the template AST. It can then determine the symbols that could potentially be at that position.
It’s a little more involved if you are in an interpolation. If you have an interpolation of {{data.---}} inside a div and need the completion list after data.---, the compiler can’t use the HTML AST to find the answer. The HTML AST can only tell the compiler that there is some text with the characters “{{data.---}}“. That’s when the template parser produces an expression AST, which resides within the template AST. The Angular Language Services then looks at data.--- within its context, asks the TypeScript Language Service what the members of data are, and returns the list of possibilities.
A number of Angular CLI commands run a complex process on your code, such as linting, building, or testing. The commands use an internal tool called Architect to run CLI builders, which apply another tool to accomplish the wanted task.
With Angular version 8, the CLI Builder API is stable and available to developers who want to customize the Angular CLI by adding or modifying commands. For example, you could supply a builder to perform an entirely new task, or to change which third-party tool is used by an existing command.
This document explains how CLI builders integrate with the workspace configuration file, and shows how you can create your own builder.
Find the code from the examples used here in this GitHub repository.
CLI builders
The internal Architect tool delegates work to handler functions called builders. A builder handler function receives two arguments; a set of input options (a JSON object), and a context (a BuilderContext object).
The separation of concerns here is the same as with schematics, which are used for other CLI commands that touch your code (such as ng generate).
The options object is provided by the CLI user, while the context object is provided by the CLI Builder API
In addition to the contextual information, the context object, which is an instance of the BuilderContext, also provides access to a scheduling method, context.scheduleTarget(). The scheduler executes the builder handler function with a given target configuration.
The builder handler function can be synchronous (return a value) or asynchronous (return a Promise), or it can watch and return multiple values (return an Observable). The return value or values must always be of type BuilderOutput. This object contains a Boolean success field and an optional error field that can contain an error message.
Angular provides some builders that are used by the CLI for commands such as ng build and ng test. Default target configurations for these and other built-in CLI builders can be found (and customized) in the “architect” section of the workspace configuration file, angular.json. Also, extend and customize Angular by creating your own builders, which you can run using the ng run CLI command.
Builder project structure
A builder resides in a “project” folder that is similar in structure to an Angular workspace, with global configuration files at the top level, and more specific configuration in a source folder with the code files that define the behavior. For example, your myBuilder folder could contain the following files.
Files
Purpose
src/my-builder.ts
Main source file for the builder definition.
src/my-builder.spec.ts
Source file for tests.
src/schema.json
Definition of builder input options.
builders.json
Builders definition.
package.json
Dependencies. See https://docs.npmjs.com/files/package.json.
tsconfig.json
TypeScript configuration.
Publish the builder to npm (see Publishing your Library). If you publish it as @example/my-builder, install it using the following command.
content_copynpm install @example/my-builder
Creating a builder
As an example, create a builder that copies a file. To create a builder, use the createBuilder() CLI Builder function, and return a Promise<BuilderOutput> object.src/my-builder.ts (builder skeleton)
Now let’s add some logic to it. The following code retrieves the source and destination file paths from user options and copies the file from the source to the destination (using the Promise version of the built-in NodeJScopyFile()function). If the copy operation fails, it returns an error with a message about the underlying problem.src/my-builder.ts (builder)
content_copyimport { BuilderContext, BuilderOutput, createBuilder } from '@angular-devkit/architect';
import { JsonObject } from '@angular-devkit/core';
import { promises as fs } from 'fs';
interface Options extends JsonObject {
source: string;
destination: string;
}
export default createBuilder(copyFileBuilder);
async function copyFileBuilder(
options: Options,
context: BuilderContext,
): Promise<BuilderOutput> {
try {
By default, copyFile() does not print anything to the process standard output or error. If an error occurs, it might be difficult to understand exactly what the builder was trying to do when the problem occurred. Add some additional context by logging additional information using the Logger API. This also lets the builder itself be executed in a separate process, even if the standard output and error are deactivated (as in an Electron app).
You can retrieve a Logger instance from the context.src/my-builder.ts (handling output)
content_copyimport { BuilderContext, BuilderOutput, createBuilder } from '@angular-devkit/architect';
import { JsonObject } from '@angular-devkit/core';
import { promises as fs } from 'fs';
interface Options extends JsonObject {
source: string;
destination: string;
}
export default createBuilder(copyFileBuilder);
async function copyFileBuilder(
options: Options,
context: BuilderContext,
): Promise<BuilderOutput> {
try {
The CLI Builder API includes progress and status reporting tools, which can provide hints for certain functions and interfaces.
To report progress, use the context.reportProgress() method, which takes a current value, (optional) total, and status string as arguments. The total can be any number; for example, if you know how many files you have to process, the total could be the number of files, and current should be the number processed so far. The status string is unmodified unless you pass in a new string value.
You can see an example of how the tslint builder reports progress.
In our example, the copy operation either finishes or is still executing, so there’s no need for a progress report, but you can report status so that a parent builder that called our builder would know what’s going on. Use the context.reportStatus() method to generate a status string of any length.
NOTE: There’s no guarantee that a long string will be shown entirely; it could be cut to fit the UI that displays it.
Pass an empty string to remove the status.src/my-builder.ts (progress reporting)
content_copyimport { BuilderContext, BuilderOutput, createBuilder } from '@angular-devkit/architect';
import { JsonObject } from '@angular-devkit/core';
import { promises as fs } from 'fs';
interface Options extends JsonObject {
source: string;
destination: string;
}
export default createBuilder(copyFileBuilder);
async function copyFileBuilder(
options: Options,
context: BuilderContext,
): Promise<BuilderOutput> {
context.reportStatus(Copying ${options.source} to ${options.destination}.);
try {
You can invoke a builder indirectly through a CLI command, or directly with the Angular CLI ng run command. In either case, you must provide required inputs, but can let other inputs default to values that are pre-configured for a specific target, provide a pre-defined, named override configuration, and provide further override option values on the command line.
Input validation
You define builder inputs in a JSON schema associated with that builder. The Architect tool collects the resolved input values into an options object, and validates their types against the schema before passing them to the builder function. (The Schematics library does the same kind of validation of user input.)
For our example builder, you expect the options value to be a JsonObject with two keys: A source and a destination, each of which are a string.
You can provide the following schema for type validation of these values.src/schema.json
The official name of our builder is now @example/copy-file:copy. The first part of this is the package name (resolved using node resolution), and the second part is the builder name (resolved using the builders.json file).
Using one of our options is very straightforward. You did this in the previous section when you accessed options.source and options.destination.src/my-builder.ts (report status)
content_copycontext.reportStatus(Copying ${options.source} to ${options.destination}.);
try {
await fs.copyFile(options.source, options.destination);
} catch (err) {
context.logger.error('Failed to copy file.');
return {
A builder must have a defined target that associates it with a specific input configuration and project.
Targets are defined in the angular.json CLI configuration file. A target specifies the builder to use, its default options configuration, and named alternative configurations. The Architect tool uses the target definition to resolve input options for a given run.
The angular.json file has a section for each project, and the “architect” section of each project configures targets for builders used by CLI commands such as ‘build’, ‘test’, and ‘lint’. By default, for example, the build command runs the builder @angular-devkit/build-angular:browser to perform the build task, and passes in default option values as specified for the build target in angular.json.angular.json
The command passes the builder the set of default options specified in the "options" section. If you pass the --configuration=production flag, it uses the override values specified in the production alternative configuration. Specify further option overrides individually on the command line. You might also add more alternative configurations to the build target, to define other environments such as stage or qa.
Target strings
The generic ng run CLI command takes as its first argument a target string of the following form.
content_copyproject:target[:configuration]
Details
project
The name of the Angular CLI project that the target is associated with.
target
A named builder configuration from the architect section of the angular.json file.
configuration
(optional) The name of a specific configuration override for the given target, as defined in the angular.json file.
If your builder calls another builder, it might need to read a passed target string. Parse this string into an object by using the targetFromTargetString() utility function from @angular-devkit/architect.
Schedule and run
Architect runs builders asynchronously. To invoke a builder, you schedule a task to be run when all configuration resolution is complete.
The builder function is not executed until the scheduler returns a BuilderRun control object. The CLI typically schedules tasks by calling the context.scheduleTarget() function, and then resolves input options using the target definition in the angular.json file.
Architect resolves input options for a given target by taking the default options object, then overwriting values from the configuration used (if any), then further overwriting values from the overrides object passed to context.scheduleTarget(). For the Angular CLI, the overrides object is built from command line arguments.
Architect validates the resulting options values against the schema of the builder. If inputs are valid, Architect creates the context and executes the builder.
For more information see Workspace Configuration.
You can also invoke a builder directly from another builder or test by calling context.scheduleBuilder(). You pass an options object directly to the method, and those option values are validated against the schema of the builder without further adjustment.
Only the context.scheduleTarget() method resolves the configuration and overrides through the angular.json file.
Default architect configuration
Let's create a simple angular.json file that puts target configurations into context.
You can publish the builder to npm (see Publishing your Library), and install it using the following command:
content_copynpm install @example/copy-file
If you create a new project with ng new builder-test, the generated angular.json file looks something like this, with only default builder configurations.angular.json
Add a new target that will run our builder to copy a file. This target tells the builder to copy the package.json file.
You need to update the angular.json file to add a target for this builder to the "architect" section of our new project.
We'll add a new target section to the "architect" object for our project
The target named "copy-package" uses our builder, which you published to @example/copy-file. (See Publishing your Library.)
The options object provides default values for the two inputs that you defined; source, which is the existing file you are copying, and destination, the path you want to copy to
The configurations key is optional, we'll leave it out for now
To run our builder with the new target's default configuration, use the following CLI command.
content_copyng run builder-test:copy-package
This copies the package.json file to package-copy.json.
Use command-line arguments to override the configured defaults. For example, to run with a different destination value, use the following CLI command.
content_copyng run builder-test:copy-package --destination=package-other.json
This copies the file to package-other.json instead of package-copy.json. Because you did not override the source option, it will copy from the package.json file (the default value provided for the target).
Testing a builder
Use integration testing for your builder, so that you can use the Architect scheduler to create a context, as in this example.
In the builder source directory, you have created a new test file my-builder.spec.ts. The code creates new instances of JsonSchemaRegistry (for schema validation), TestingArchitectHost (an in-memory implementation of ArchitectHost), and Architect.
We've added a builders.json file next to the builder's package.json file, and modified the package file to point to it.
Here's an example of a test that runs the copy file builder. The test uses the builder to copy the package.json file and validates that the copied file's contents are the same as the source.src/my-builder.spec.ts
content_copyimport { Architect } from '@angular-devkit/architect';
import { TestingArchitectHost } from '@angular-devkit/architect/testing';
import { schema } from '@angular-devkit/core';
import { promises as fs } from 'fs';
import { join } from 'path';
describe('Copy File Builder', () => {
let architect: Architect;
let architectHost: TestingArchitectHost;
beforeEach(async () => {
const registry = new schema.CoreSchemaRegistry();
registry.addPostTransform(schema.transforms.addUndefinedDefaults);
// TestingArchitectHost() takes workspace and current directories.
// Since we don't use those, both are the same in this case.
architectHost = new TestingArchitectHost(__dirname, __dirname);
architect = new Architect(architectHost, registry);
// This will either take a Node package name, or a path to the directory
// for the package.json file.
await architectHost.addBuilderFromPackage(join(__dirname, '..'));
});
it('can copy files', async () => {
// A "run" can have multiple outputs, and contains progress information.
const run = await architect.scheduleBuilder('@example/copy-file:copy', {
source: 'package.json',
destination: 'package-copy.json',
});
// The "result" member (of type BuilderOutput) is the next output.
const output = await run.result;
// Stop the builder from running. This stops Architect from keeping
// the builder-associated states in memory, since builders keep waiting
// to be scheduled.
await run.stop();
// Expect that the copied file is the same as its source.
const sourceContent = await fs.readFile('package.json', 'utf8');
const destinationContent = await fs.readFile('package-copy.json', 'utf8');
expect(destinationContent).toBe(sourceContent);
});
});
When running this test in your repo, you need the ts-node package. You can avoid this by renaming my-builder.spec.ts to my-builder.spec.js.
Watch mode
Architect expects builders to run once (by default) and return. This behavior is not entirely compatible with a builder that watches for changes (like Webpack, for example). Architect can support watch mode, but there are some things to look out for.
To be used with watch mode, a builder handler function should return an Observable. Architect subscribes to the Observable until it completes and might reuse it if the builder is scheduled again with the same arguments.
The builder should always emit a BuilderOutput object after each execution. Once it's been executed, it can enter a watch mode, to be triggered by an external event. If an event triggers it to restart, the builder should execute the context.reportRunning() function to tell Architect that it is running again. This prevents Architect from stopping the builder if another run is scheduled.
When your builder calls BuilderRun.stop() to exit watch mode, Architect unsubscribes from the builder's Observable and calls the builder's teardown logic to clean up. (This behavior also allows for long-running builds to be stopped and cleaned up.)
In general, if your builder is watching an external event, you should separate your run into three phases.
Phases
Details
Running
For example, webpack compiles. This ends when webpack finishes and your builder emits a BuilderOutput object.
Watching
Between two runs, watch an external event stream. For example, webpack watches the file system for any changes. This ends when webpack restarts building, and context.reportRunning() is called. This goes back to step 1.
Completion
Either the task is fully completed (for example, webpack was supposed to run a number of times), or the builder run was stopped (using BuilderRun.stop()). Your teardown logic is executed, and Architect unsubscribes from your builder's Observable.
You can define different named build configurations for your project, such as development and staging, with different defaults.
Each named configuration can have defaults for any of the options that apply to the various builder targets, such as build, serve, and test. The Angular CLI build, serve, and test commands can then replace files with appropriate versions for your intended target environment.
Configure environment-specific defaults
Using the Angular CLI, start by running the generate environments command shown here to create the src/environments/ directory and configure the project to use these files.
content_copyng generate environments
The project’s src/environments/ directory contains the base configuration file, environment.ts, which provides configuration for production, the default environment. You can override default values for additional environments, such as development and staging, in target-specific configuration files.
For example:
myProject/src/environments
environment.ts
environment.development.ts
environment.staging.ts
The base file environment.ts, contains the default environment settings. For example:
The build command uses this as the build target when no environment is specified. You can add further variables, either as additional properties on the environment object, or as separate objects. For example, the following adds a default for a variable to the default environment:
You can add target-specific configuration files, such as environment.development.ts. The following content sets default values for the development build target:
The following application structure configures build targets for development and staging environments:
src
app
app.component.html
app.component.ts
environments
environment.ts
environment.development.ts
environment.staging.ts
To use the environment configurations you have defined, your components must import the original environments file:
content_copyimport { environment } from './../environments/environment';
This ensures that the build and serve commands can find the configurations for specific build targets.
The following code in the component file (app.component.ts) uses an environment variable defined in the configuration files.
content_copyimport { Component } from '@angular/core';
import { environment } from './../environments/environment';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
constructor() {
console.log(environment.production); // Logs false for development environment
}
title = 'app works!';
}
Configure target-specific file replacements
The main CLI configuration file, angular.json, contains a fileReplacements section in the configuration for each build target, which lets you replace any file in the TypeScript program with a target-specific version of that file. This is useful for including target-specific code or variables in a build that targets a specific environment, such as production or staging.
By default no files are replaced. You can add file replacements for specific build targets. For example:
This means that when you build your development configuration with ng build --configuration development, the src/environments/environment.ts file is replaced with the target-specific version of the file, src/environments/environment.development.ts.
You can add additional configurations as required. To add a staging environment, create a copy of src/environments/environment.ts called src/environments/environment.staging.ts, then add a staging configuration to angular.json:
You can add more configuration options to this target environment as well. Any option that your build supports can be overridden in a build target configuration.
To build using the staging configuration, run the following command:
content_copyng build --configuration=staging
You can also configure the serve command to use the targeted build configuration if you add it to the "serve:configurations" section of angular.json:
As applications grow in functionality, they also grow in size. The CLI lets you set size thresholds in your configuration to ensure that parts of your application stay within size boundaries that you define.
Define your size boundaries in the CLI configuration file, angular.json, in a budgets section for each configured environment.
content_copy{
…
"configurations": {
"production": {
…
"budgets": []
}
}
}
You can specify size budgets for the entire app, and for particular parts. Each budget entry configures a budget of a given type. Specify size values in the following formats:
Size value
Details
123 or 123b
Size in bytes.
123kb
Size in kilobytes.
123mb
Size in megabytes.
12%
Percentage of size relative to baseline. (Not valid for baseline values.)
When you configure a budget, the build system warns or reports an error when a given part of the application reaches or exceeds a boundary size that you set.
Each budget entry is a JSON object with the following properties:
Property
Value
type
The type of budget. One of:ValueDetailsbundleThe size of a specific bundle.initialThe size of JavaScript needed for bootstrapping the application. Defaults to warning at 500kb and erroring at 1mb.allScriptThe size of all scripts.allThe size of the entire application.anyComponentStyleThis size of any one component stylesheet. Defaults to warning at 2kb and erroring at 4kb.anyScriptThe size of any one script.anyThe size of any file.
name
The name of the bundle (for type=bundle).
baseline
The baseline size for comparison.
maximumWarning
The maximum threshold for warning relative to the baseline.
maximumError
The maximum threshold for error relative to the baseline.
minimumWarning
The minimum threshold for warning relative to the baseline.
minimumError
The minimum threshold for error relative to the baseline.
warning
The threshold for warning relative to the baseline (min & max).
error
The threshold for error relative to the baseline (min & max).
Configuring CommonJS dependencies
It is recommended that you avoid depending on CommonJS modules in your Angular applications. Depending on CommonJS modules can prevent bundlers and minifiers from optimizing your application, which results in larger bundle sizes. Instead, it is recommended that you use ECMAScript modules in your entire application. For more information, see How CommonJS is making your bundles larger.
The Angular CLI outputs warnings if it detects that your browser application depends on CommonJS modules. To disable these warnings, add the CommonJS module name to allowedCommonJsDependencies option in the build options located in angular.json file.
The Angular CLI uses Browserslist to ensure compatibility with different browser versions. Autoprefixer is used for CSS vendor prefixing and @babel/preset-env for JavaScript syntax transformations.
Internally, the Angular CLI uses the below browserslist configuration which matches the browsers that are supported by Angular.
content_copylast 2 Chrome versions
last 1 Firefox version
last 2 Edge major versions
last 2 Safari major versions
last 2 iOS major versions
Firefox ESR
To override the internal configuration, run ng generate config browserslist, which generates a .browserslistrc configuration file in the project directory.
See the browserslist repository for more examples of how to target specific browsers and versions.
Use browsersl.ist to display compatible browsers for a browserslist query.
Proxying to a backend server
Use the proxying support in the webpack development server to divert certain URLs to a backend server, by passing a file to the --proxy-config build option. For example, to divert all calls for http://localhost:4200/api to a server running on http://localhost:3000/api, take the following steps.
Create a file proxy.conf.json in your project's src/ folder.
Add the following content to the new proxy file:content_copy{ "/api": { "target": "http://localhost:3000", "secure": false } }
In the CLI configuration file, angular.json, add the proxyConfig option to the serve target:content_copy… "architect": { "serve": { "builder": "@angular-devkit/build-angular:dev-server", "options": { "browserTarget": "your-application-name:build", "proxyConfig": "src/proxy.conf.json" }, …
To run the development server with this proxy configuration, call ng serve.
Edit the proxy configuration file to add configuration options; following are some examples. For a description of all options, see webpack DevServer documentation.
NOTE: If you edit the proxy configuration file, you must relaunch the ng serve process to make your changes effective.
As of Node version 17, Node will not always resolve http://localhost:<port> to http://127.0.0.1:<port> depending on each machine's configuration.
If you get an ECONNREFUSED error using a proxy targeting a localhost URL, you can fix this issue by updating the target from http://localhost:<port> to http://127.0.0.1:<port>.
See the http proxy middleware documentation for more information.
Rewrite the URL path
The pathRewrite proxy configuration option lets you rewrite the URL path at run time. For example, specify the following pathRewrite value to the proxy configuration to remove "api" from the end of a path.
If you need to optionally bypass the proxy, or dynamically change the request before it's sent, add the bypass option, as shown in this JavaScript example.
content_copyexport default {
'/api/proxy': {
"target": 'http://localhost:3000',
"secure": false,
"bypass": function (req, res, proxyOptions) {
if (req.headers.accept.includes('html')) {
console.log('Skipping proxy for browser request.');
return '/index.html';
}
req.headers['X-Custom-Header'] = 'yes';
}
}
};
Using corporate proxy
If you work behind a corporate proxy, the backend cannot directly proxy calls to any URL outside your local network. In this case, you can configure the backend proxy to redirect calls through your corporate proxy using an agent:
When you define an environment variable http_proxy or HTTP_PROXY, an agent is automatically added to pass calls through your corporate proxy when running npm start.
Use the following content in the JavaScript configuration file.
Just as TypeScript catches type errors in your code, Angular checks the expressions and bindings within the templates of your application and can report any type errors it finds. Angular currently has three modes of doing this, depending on the value of the fullTemplateTypeCheck and strictTemplates flags in the TypeScript configuration file.
Basic mode
In the most basic type-checking mode, with the fullTemplateTypeCheck flag set to false, Angular validates only top-level expressions in a template.
If you write <map [city]="user.address.city">, the compiler verifies the following:
user is a property on the component class
user is an object with an address property
user.address is an object with a city property
The compiler does not verify that the value of user.address.city is assignable to the city input of the <map> component.
The compiler also has some major limitations in this mode:
Importantly, it doesn’t check embedded views, such as *ngIf, *ngFor, other <ng-template> embedded view.
It doesn’t figure out the types of #refs, the results of pipes, or the type of $event in event bindings.
In many cases, these things end up as type any, which can cause subsequent parts of the expression to go unchecked.
Full mode
If the fullTemplateTypeCheck flag is set to true, Angular is more aggressive in its type-checking within templates. In particular:
Embedded views (such as those within an *ngIf or *ngFor) are checked
Pipes have the correct return type
Local references to directives and pipes have the correct type (except for any generic parameters, which will be any)
The following still have type any.
Local references to DOM elements
The $event object
Safe navigation expressions
The fullTemplateTypeCheck flag has been deprecated in Angular 13. The strictTemplates family of compiler options should be used instead.
Strict mode
Angular maintains the behavior of the fullTemplateTypeCheck flag, and introduces a third “strict mode”. Strict mode is a superset of full mode, and is accessed by setting the strictTemplates flag to true. This flag supersedes the fullTemplateTypeCheck flag. In strict mode, Angular uses checks that go beyond the version 8 type-checker.
NOTE: Strict mode is only available if using Ivy.
In addition to the full mode behavior, Angular does the following:
Verifies that component/directive bindings are assignable to their @Input()s
Obeys TypeScript’s strictNullChecks flag when validating the preceding mode
Infers the correct type of components/directives, including generics
Infers template context types where configured (for example, allowing correct type-checking of NgFor)
Infers the correct type of $event in component/directive, DOM, and animation event bindings
Infers the correct type of local references to DOM elements, based on the tag name (for example, the type that document.createElement would return for that tag)
Checking of *ngFor
The three modes of type-checking treat embedded views differently. Consider the following example.User interface
content_copyinterface User {
name: string;
address: {
city: string;
state: string;
}
}
content_copy<div *ngFor="let user of users">
<h2>{{config.title}}</h2>
<span>City: {{user.address.city}}</span>
</div>
The <h2> and the <span> are in the *ngFor embedded view. In basic mode, Angular doesn’t check either of them. However, in full mode, Angular checks that config and user exist and assumes a type of any. In strict mode, Angular knows that the user in the <span> has a type of User, and that address is an object with a city property of type string.
Troubleshooting template errors
With strict mode, you might encounter template errors that didn’t arise in either of the previous modes. These errors often represent genuine type mismatches in the templates that were not caught by the previous tooling. If this is the case, the error message should make it clear where in the template the problem occurs.
There can also be false positives when the typings of an Angular library are either incomplete or incorrect, or when the typings don’t quite line up with expectations as in the following cases.
When a library’s typings are wrong or incomplete (for example, missing null | undefined if the library was not written with strictNullChecks in mind)
When a library’s input types are too narrow and the library hasn’t added appropriate metadata for Angular to figure this out. This usually occurs with disabled or other common Boolean inputs used as attributes, for example, <input disabled>.
When using $event.target for DOM events (because of the possibility of event bubbling, $event.target in the DOM typings doesn’t have the type you might expect)
In case of a false positive like these, there are a few options:
Use the $any() type-cast function in certain contexts to opt out of type-checking for a part of the expression
Disable strict checks entirely by setting strictTemplates: false in the application’s TypeScript configuration file, tsconfig.json
Disable certain type-checking operations individually, while maintaining strictness in other aspects, by setting a strictness flag to false
If you want to use strictTemplates and strictNullChecks together, opt out of strict null type checking specifically for input bindings using strictNullInputTypes
Unless otherwise commented, each following option is set to the value for strictTemplates (true when strictTemplates is true and conversely, the other way around).
Strictness flag
Effect
strictInputTypes
Whether the assignability of a binding expression to the @Input() field is checked. Also affects the inference of directive generic types.
strictInputAccessModifiers
Whether access modifiers such as private/protected/readonly are honored when assigning a binding expression to an @Input(). If disabled, the access modifiers of the @Input are ignored; only the type is checked. This option is false by default, even with strictTemplates set to true.
strictNullInputTypes
Whether strictNullChecks is honored when checking @Input() bindings (per strictInputTypes). Turning this off can be useful when using a library that was not built with strictNullChecks in mind.
strictAttributeTypes
Whether to check @Input() bindings that are made using text attributes. For example,<input matInput disabled="true">(setting the disabled property to the string 'true') vs<input matInput [disabled]="true">(setting the disabled property to the boolean true).
strictSafeNavigationTypes
Whether the return type of safe navigation operations (for example, user?.name will be correctly inferred based on the type of user). If disabled, user?.name will be of type any.
strictDomLocalRefTypes
Whether local references to DOM elements will have the correct type. If disabled ref will be of type any for <input #ref>.
strictOutputEventTypes
Whether $event will have the correct type for event bindings to component/directive an @Output(), or to animation events. If disabled, it will be any.
strictDomEventTypes
Whether $event will have the correct type for event bindings to DOM events. If disabled, it will be any.
strictContextGenerics
Whether the type parameters of generic components will be inferred correctly (including any generic bounds). If disabled, any type parameters will be any.
strictLiteralTypes
Whether object and array literals declared in the template will have their type inferred. If disabled, the type of such literals will be any. This flag is true when eitherfullTemplateTypeCheck or strictTemplates is set to true.
If you still have issues after troubleshooting with these flags, fall back to full mode by disabling strictTemplates.
If that doesn’t work, an option of last resort is to turn off full mode entirely with fullTemplateTypeCheck: false.
A type-checking error that you cannot resolve with any of the recommended methods can be the result of a bug in the template type-checker itself. If you get errors that require falling back to basic mode, it is likely to be such a bug. If this happens, file an issue so the team can address it.
Inputs and type-checking
The template type checker checks whether a binding expression’s type is compatible with that of the corresponding directive input. As an example, consider the following component:
The AppComponent template uses this component as follows:
content_copy@Component({
selector: 'app-root',
template: '<user-detail [user]="selectedUser"></user-detail>',
})
export class AppComponent {
selectedUser: User | null = null;
}
Here, during type checking of the template for AppComponent, the [user]="selectedUser" binding corresponds with the UserDetailComponent.user input. Therefore, Angular assigns the selectedUser property to UserDetailComponent.user, which would result in an error if their types were incompatible. TypeScript checks the assignment according to its type system, obeying flags such as strictNullChecks as they are configured in the application.
Avoid run-time type errors by providing more specific in-template type requirements to the template type checker. Make the input type requirements for your own directives as specific as possible by providing template-guard functions in the directive definition. See Improving template type checking for custom directives in this guide.
Strict null checks
When you enable strictTemplates and the TypeScript flag strictNullChecks, typecheck errors might occur for certain situations that might not easily be avoided. For example:
A nullable value that is bound to a directive from a library which did not have strictNullChecks enabled.For a library compiled without strictNullChecks, its declaration files will not indicate whether a field can be null or not. For situations where the library handles null correctly, this is problematic, as the compiler will check a nullable value against the declaration files which omit the null type. As such, the compiler produces a type-check error because it adheres to strictNullChecks.
Using the async pipe with an Observable which you know will emit synchronously.The async pipe currently assumes that the Observable it subscribes to can be asynchronous, which means that it’s possible that there is no value available yet. In that case, it still has to return something —which is null. In other words, the return type of the async pipe includes null, which might result in errors in situations where the Observable is known to emit a non-nullable value synchronously.
There are two potential workarounds to the preceding issues:
In the template, include the non-null assertion operator ! at the end of a nullable expression, such as<user-detail [user]="user!"></user-detail>In this example, the compiler disregards type incompatibilities in nullability, just as in TypeScript code. In the case of the async pipe, notice that the expression needs to be wrapped in parentheses, as in<user-detail [user]="(user$ | async)!"></user-detail>
Disable strict null checks in Angular templates completely.When strictTemplates is enabled, it is still possible to disable certain aspects of type checking. Setting the option strictNullInputTypes to false disables strict null checks within Angular templates. This flag applies for all components that are part of the application.
Advice for library authors
As a library author, you can take several measures to provide an optimal experience for your users. First, enabling strictNullChecks and including null in an input’s type, as appropriate, communicates to your consumers whether they can provide a nullable value or not. Additionally, it is possible to provide type hints that are specific to the template type checker. See Improving template type checking for custom directives, and Input setter coercion.
Input setter coercion
Occasionally it is desirable for the @Input() of a directive or component to alter the value bound to it, typically using a getter/setter pair for the input. As an example, consider this custom button component:
`,
})
class SubmitButton {
private _disabled: boolean;
get disabled(): boolean {
return this._disabled;
}
@Input()
set disabled(value: boolean) {
this._disabled = value;
}
}
Here, the disabled input of the component is being passed on to the <button> in the template. All of this works as expected, as long as a boolean value is bound to the input. But, suppose a consumer uses this input in the template as an attribute:
At runtime, the input will be set to the empty string, which is not a boolean value. Angular component libraries that deal with this problem often “coerce” the value into the right type in the setter:
It would be ideal to change the type of value here, from boolean to boolean|'', to match the set of values which are actually accepted by the setter. TypeScript prior to version 4.3 requires that both the getter and setter have the same type, so if the getter should return a boolean then the setter is stuck with the narrower type.
If the consumer has Angular’s strictest type checking for templates enabled, this creates a problem: the empty string ('') is not actually assignable to the disabled field, which creates a type error when the attribute form is used.
As a workaround for this problem, Angular supports checking a wider, more permissive type for @Input() than is declared for the input field itself. Enable this by adding a static property with the ngAcceptInputType_ prefix to the component class:
content_copyclass SubmitButton {
private _disabled: boolean;
get disabled(): boolean {
Since TypeScript 4.3, the setter could have been declared to accept boolean|'' as type, making the input setter coercion field obsolete. As such, input setters coercion fields have been deprecated.
This field does not need to have a value. Its existence communicates to the Angular type checker that the disabled input should be considered as accepting bindings that match the type boolean|''. The suffix should be the @Inputfield name.
Care should be taken that if an ngAcceptInputType_ override is present for a given input, then the setter should be able to handle any values of the overridden type.
Disabling type checking using $any()
Disable checking of a binding expression by surrounding the expression in a call to the $any() cast pseudo-function. The compiler treats it as a cast to the any type just like in TypeScript when a <any> or as any cast is used.
In the following example, casting person to the any type suppresses the error Property address does not exist.
The following are metadata errors you may encounter, with explanations and suggested corrections.
Expression form not supported Reference to a local (non-exported) symbol Only initialized variables and constants Reference to a non-exported class Reference to a non-exported function Function calls are not supported Destructured variable or constant not supported Could not resolve type Name expected Unsupported enum member name Tagged template expressions are not supported Symbol reference expected
Expression form not supported
The compiler encountered an expression it didn’t understand while evaluating Angular metadata.
Language features outside of the compiler’s restricted expression syntax can produce this error, as seen in the following example:
content_copy// ERROR
export class Fooish { … }
…
const prop = typeof Fooish; // typeof is not valid in metadata
…
// bracket notation is not valid in metadata
{ provide: 'token', useValue: { [prop]: 'value' } };
…
You can use typeof and bracket notation in normal application code. You just can’t use those features within expressions that define Angular metadata.
Avoid this error by sticking to the compiler’s restricted expression syntax when writing Angular metadata and be wary of new or unusual TypeScript features.
Reference to a local (non-exported) symbol
Reference to a local (non-exported) symbol ‘symbol name’. Consider exporting the symbol.
The compiler encountered a reference to a locally defined symbol that either wasn’t exported or wasn’t initialized.
Here’s a provider example of the problem.
content_copy// ERROR
let foo: number; // neither exported nor initialized
@Component({
selector: 'my-component',
template: … ,
providers: [
{ provide: Foo, useValue: foo }
]
})
export class MyComponent {}
The compiler generates the component factory, which includes the useValue provider code, in a separate module. That factory module can’t reach back to this source module to access the local (non-exported) foo variable.
You could fix the problem by initializing foo.
content_copylet foo = 42; // initialized
The compiler will fold the expression into the provider as if you had written this.
Adding export often works for variables referenced in metadata such as providers and animations because the compiler can generate references to the exported variables in these expressions. It doesn’t need the values of those variables.
Adding export doesn’t work when the compiler needs the actual value in order to generate code. For example, it doesn’t work for the template property.
content_copy// ERROR
export let someTemplate: string; // exported but not initialized
@Component({
selector: 'my-component',
template: someTemplate
})
export class MyComponent {}
The compiler needs the value of the template property right now to generate the component factory. The variable reference alone is insufficient. Prefixing the declaration with export merely produces a new error, “Only initialized variables and constants can be referenced“.
Only initialized variables and constants
Only initialized variables and constants can be referenced because the value of this variable is needed by the template compiler.
The compiler found a reference to an exported variable or static field that wasn’t initialized. It needs the value of that variable to generate code.
The following example tries to set the component’s template property to the value of the exported someTemplate variable which is declared but unassigned.
content_copy// ERROR
export let someTemplate: string;
@Component({
selector: 'my-component',
template: someTemplate
})
export class MyComponent {}
You’d also get this error if you imported someTemplate from some other module and neglected to initialize it there.
content_copy// ERROR - not initialized there either
import { someTemplate } from './config';
@Component({
selector: 'my-component',
template: someTemplate
})
export class MyComponent {}
The compiler cannot wait until runtime to get the template information. It must statically derive the value of the someTemplate variable from the source code so that it can generate the component factory, which includes instructions for building the element based on the template.
To correct this error, provide the initial value of the variable in an initializer clause on the same line.
content_copy// CORRECTED
export let someTemplate = '<h1>Greetings from Angular</h1>';
@Component({
selector: 'my-component',
template: someTemplate
})
export class MyComponent {}
Reference to a non-exported class
Reference to a non-exported class <class name>.Consider exporting the class.
Metadata referenced a class that wasn’t exported.
For example, you may have defined a class and used it as an injection token in a providers array but neglected to export that class.
content_copy// ERROR
abstract class MyStrategy { }
…
providers: [
{ provide: MyStrategy, useValue: … }
]
…
Angular generates a class factory in a separate module and that factory can only access exported classes. To correct this error, export the referenced class.
Metadata referenced a function that wasn’t exported.
For example, you may have set a providers useFactory property to a locally defined function that you neglected to export.
content_copy// ERROR
function myStrategy() { … }
…
providers: [
{ provide: MyStrategy, useFactory: myStrategy }
]
…
Angular generates a class factory in a separate module and that factory can only access exported functions. To correct this error, export the function.
Function calls are not supported. Consider replacing the function or lambda with a reference to an exported function.
The compiler does not currently support function expressions or lambda functions. For example, you cannot set a provider’s useFactory to an anonymous function or arrow function like this.
The Window type in the constructor is no longer a problem for the compiler because it uses the @Inject(WINDOW) to generate the injection code.
Angular does something similar with the DOCUMENT token so you can inject the browser’s document object (or an abstraction of it, depending upon the platform in which the application runs).
content_copyimport { Inject } from '@angular/core';
import { DOCUMENT } from '@angular/common';
@Component({ … })
export class MyComponent {
constructor (@Inject(DOCUMENT) private doc: Document) { … }
}
Name expected
The compiler expected a name in an expression it was evaluating.
This can happen if you use a number as a property name as in the following example.
When you use ahead-of-time compilation (AOT), you can control how your application is compiled by specifying template compiler options in the TypeScript configuration file.
The template options object, angularCompilerOptions, is a sibling to the compilerOptions object that supplies standard options to the TypeScript compiler.tsconfig.json
Like the TypeScript compiler, the Angular AOT compiler also supports extends in the angularCompilerOptions section of the TypeScript configuration file. The extends property is at the top level, parallel to compilerOptions and angularCompilerOptions.
A TypeScript configuration can inherit settings from another file using the extends property. The configuration options from the base file are loaded first, then overridden by those in the inheriting configuration file.
For more information, see the TypeScript Handbook.
Template options
The following options are available for configuring the AOT template compiler.
annotationsAs
Modifies how Angular-specific annotations are emitted to improve tree-shaking. Non-Angular annotations are not affected. One of static fields or decorators. The default value is static fields.
By default, the compiler replaces decorators with a static field in the class, which allows advanced tree-shakers like Closure compiler to remove unused classes
The decorators value leaves the decorators in place, which makes compilation faster. TypeScript emits calls to the __decorate helper. Use --emitDecoratorMetadata for runtime reflection.NOTE: That the resulting code cannot tree-shake properly.
annotateForClosureCompiler
When true, use Tsickle to annotate the emitted JavaScript with JSDoc comments needed by the Closure Compiler. Default is false.
compilationMode
Specifies the compilation mode to use. The following modes are available:
Modes
Details
'full'
Generates fully AOT-compiled code according to the version of Angular that is currently being used.
'partial'
Generates code in a stable, but intermediate form suitable for a published library.
The default value is 'full'.
disableExpressionLowering
When true, the default, transforms code that is or could be used in an annotation, to allow it to be imported from template factory modules. See metadata rewriting for more information.
When false, disables this rewriting, requiring the rewriting to be done manually.
disableTypeScriptVersionCheck
When true, the compiler does not look at the TypeScript version and does not report an error when an unsupported version of TypeScript is used. Not recommended, as unsupported versions of TypeScript might have undefined behavior. Default is false.
enableI18nLegacyMessageIdFormat
Instructs the Angular template compiler to create legacy ids for messages that are tagged in templates by the i18n attribute. See Mark text for translations for more information about marking messages for localization.
Set this option to false unless your project relies upon translations that were created earlier using legacy IDs. Default is true.
The pre-Ivy message extraction tooling created a variety of legacy formats for extracted message IDs. These message formats have some issues, such as whitespace handling and reliance upon information inside the original HTML of a template.
The new message format is more resilient to whitespace changes, is the same across all translation file formats, and can be created directly from calls to $localize. This allows $localize messages in application code to use the same ID as identical i18n messages in component templates.
enableResourceInlining
When true, replaces the templateUrl and styleUrls properties in all @Component decorators with inline content in the template and styles properties.
When enabled, the .js output of ngc does not include any lazy-loaded template or style URLs.
For library projects created with the Angular CLI, the development configuration default is true.
enableLegacyTemplate
When true, enables the deprecated <template> element in place of <ng-template>. Default is false. Might be required by some third-party Angular libraries.
flatModuleId
The module ID to use for importing a flat module (when flatModuleOutFile is true). References created by the template compiler use this module name when importing symbols from the flat module. Ignored if flatModuleOutFile is false.
flatModuleOutFile
When true, generates a flat module index of the given filename and the corresponding flat module metadata. Use to create flat modules that are packaged similarly to @angular/core and @angular/common. When this option is used, the package.json for the library should refer to the created flat module index instead of the library index file.
Produces only one .metadata.json file, which contains all the metadata necessary for symbols exported from the library index. In the created .ngfactory.js files, the flat module index is used to import symbols. Symbols that include both the public API from the library index and shrouded internal symbols.
By default, the .ts file supplied in the files field is assumed to be the library index. If more than one .ts file is specified, libraryIndex is used to select the file to use. If more than one .ts file is supplied without a libraryIndex, an error is produced.
A flat module index .d.ts and .js is created with the given flatModuleOutFile name in the same location as the library index .d.ts file.
For example, if a library uses the public_api.ts file as the library index of the module, the tsconfig.jsonfiles field would be ["public_api.ts"]. The flatModuleOutFile option could then be set, for example, to "index.js", which produces index.d.ts and index.metadata.json files. The module field of the library’s package.json would be "index.js" and the typings field would be "index.d.ts".
fullTemplateTypeCheck
When true, the recommended value, enables the binding expression validation phase of the template compiler. This phase uses TypeScript to verify binding expressions. For more information, see Template type checking.
Default is false, but set to true in the created workspace configuration when creating a project using the Angular CLI.
The fullTemplateTypeCheck option has been deprecated in Angular 13 in favor of the strictTemplates family of compiler options.
generateCodeForLibraries
When true, creates factory files (.ngfactory.js and .ngstyle.js) for .d.ts files with a corresponding .metadata.json file. The default value is true.
When false, factory files are created only for .ts files. Do this when using factory summaries.
preserveWhitespaces
When false, the default, removes blank text nodes from compiled templates, which results in smaller emitted template factory modules. Set to true to preserve blank text nodes.
When using hydration, it is recommended that you use preserveWhitespaces: false, which is the default value. If you choose to enable preserving whitespaces by adding preserveWhitespaces: true to your tsconfig, it is possible you may encounter issues with hydration. This is not yet a fully supported configuration. Ensure this is also consistently set between the server and client tsconfig files. See the hydration guide for more details.
skipMetadataEmit
When true, does not produce .metadata.json files. Default is false.
The .metadata.json files contain information needed by the template compiler from a .ts file that is not included in the .d.ts file produced by the TypeScript compiler. This information includes, for example, the content of annotations, such as a component’s template, which TypeScript emits to the .js file but not to the .d.ts file.
You can set to true when using factory summaries, because the factory summaries include a copy of the information that is in the .metadata.json file.
Set to true if you are using TypeScript’s --outFile option, because the metadata files are not valid for this style of TypeScript output. The Angular community does not recommend using --outFile with Angular. Use a bundler, such as webpack, instead.
skipTemplateCodegen
When true, does not emit .ngfactory.js and .ngstyle.js files. This turns off most of the template compiler and disables the reporting of template diagnostics.
Can be used to instruct the template compiler to produce .metadata.json files for distribution with an npm package. This avoids the production of .ngfactory.js and .ngstyle.js files that cannot be distributed to npm.
For library projects created with the Angular CLI, the development configuration default is true.
strictMetadataEmit
When true, reports an error to the .metadata.json file if "skipMetadataEmit" is false. Default is false. Use only when "skipMetadataEmit" is false and "skipTemplateCodegen" is true.
This option is intended to verify the .metadata.json files emitted for bundling with an npm package. The validation is strict and can emit errors for metadata that would never produce an error when used by the template compiler. You can choose to suppress the error emitted by this option for an exported symbol by including @dynamic in the comment documenting the symbol.
It is valid for .metadata.json files to contain errors. The template compiler reports these errors if the metadata is used to determine the contents of an annotation. The metadata collector cannot predict the symbols that are designed for use in an annotation. It preemptively includes error nodes in the metadata for the exported symbols. The template compiler can then use the error nodes to report an error if these symbols are used.
If the client of a library intends to use a symbol in an annotation, the template compiler does not normally report this. It gets reported after the client actually uses the symbol. This option allows detection of these errors during the build phase of the library and is used, for example, in producing Angular libraries themselves.
For library projects created with the Angular CLI, the development configuration default is true.
strictInjectionParameters
When true, reports an error for a supplied parameter whose injection type cannot be determined. When false, constructor parameters of classes marked with @Injectable whose type cannot be resolved produce a warning. The recommended value is true, but the default value is false.
Set to true in the created workspace configuration when creating a project using the Angular CLI.
strictTemplates
When true, enables strict template type checking.
The strictness flags that this option enables allow you to turn on and off specific types of strict template type checking. See troubleshooting template errors.
Set to true in the created workspace configuration when creating a project using the Angular CLI.
trace
When true, prints extra information while compiling templates. Default is false.
Command line options
Most of the time you interact with the Angular Compiler indirectly using Angular CLI. When debugging certain issues, you might find it useful to invoke the Angular Compiler directly. You can use the ngc command provided by the @angular/compiler-cli npm package to call the compiler from the command line.
The ngc command is just a wrapper around TypeScript’s tsc compiler command and is primarily configured via the tsconfig.json configuration options documented in the previous sections.
Besides the configuration file, you can also use tsccommand line options to configure ngc.
An Angular application consists mainly of components and their HTML templates. Because the components and templates provided by Angular cannot be understood by the browser directly, Angular applications require a compilation process before they can run in a browser.
The Angular ahead-of-time (AOT) compiler converts your Angular HTML and TypeScript code into efficient JavaScript code during the build phase before the browser downloads and runs that code. Compiling your application during the build process provides a faster rendering in the browser.
This guide explains how to specify metadata and apply available compiler options to compile your applications efficiently using the AOT compiler.
Watch Alex Rickabaugh explain the Angular compiler at AngularConnect 2019.
Here are some reasons you might want to use AOT.
Reasons
Details
Faster rendering
With AOT, the browser downloads a pre-compiled version of the application. The browser loads executable code so it can render the application immediately, without waiting to compile the application first.
Fewer asynchronous requests
The compiler inlines external HTML templates and CSS style sheets within the application JavaScript, eliminating separate ajax requests for those source files.
Smaller Angular framework download size
There’s no need to download the Angular compiler if the application is already compiled. The compiler is roughly half of Angular itself, so omitting it dramatically reduces the application payload.
Detect template errors earlier
The AOT compiler detects and reports template binding errors during the build step before users can see them.
Better security
AOT compiles HTML templates and components into JavaScript files long before they are served to the client. With no templates to read and no risky client-side HTML or JavaScript evaluation, there are fewer opportunities for injection attacks.
Choosing a compiler
Angular offers two ways to compile your application:
Angular compile
Details
Just-in-Time (JIT)
Compiles your application in the browser at runtime. This was the default until Angular 8.
Ahead-of-Time (AOT)
Compiles your application and libraries at build time. This is the default starting in Angular 9.
When you run the ng build (build only) or ng serve (build and serve locally) CLI commands, the type of compilation (JIT or AOT) depends on the value of the aot property in your build configuration specified in angular.json. By default, aot is set to true for new CLI applications.
See the CLI command reference and Building and serving Angular apps for more information.
How AOT works
The Angular AOT compiler extracts metadata to interpret the parts of the application that Angular is supposed to manage. You can specify the metadata explicitly in decorators such as @Component() and @Input(), or implicitly in the constructor declarations of the decorated classes. The metadata tells Angular how to construct instances of your application classes and interact with them at runtime.
In the following example, the @Component() metadata object and the class constructor tell Angular how to create and display an instance of TypicalComponent.
The Angular compiler extracts the metadata once and generates a factory for TypicalComponent. When it needs to create a TypicalComponent instance, Angular calls the factory, which produces a new visual element, bound to a new instance of the component class with its injected dependency.
Compilation phases
There are three phases of AOT compilation.
Phase
Details
1
code analysis
In this phase, the TypeScript compiler and AOT collector create a representation of the source. The collector does not attempt to interpret the metadata it collects. It represents the metadata as best it can and records errors when it detects a metadata syntax violation.
2
code generation
In this phase, the compiler’s StaticReflector interprets the metadata collected in phase 1, performs additional validation of the metadata, and throws an error if it detects a metadata restriction violation.
3
template type checking
In this optional phase, the Angular template compiler uses the TypeScript compiler to validate the binding expressions in templates. You can enable this phase explicitly by setting the strictTemplates configuration option; see Angular compiler options.
Metadata restrictions
You write metadata in a subset of TypeScript that must conform to the following general constraints:
Limit expression syntax to the supported subset of JavaScript
Only reference exported symbols after code folding
Only call functions supported by the compiler
Input/Outputs and data-bound class members must be public or protected.
For additional guidelines and instructions on preparing an application for AOT compilation, see Angular: Writing AOT-friendly applications.
Errors in AOT compilation commonly occur because of metadata that does not conform to the compiler’s requirements (as described more fully below). For help in understanding and resolving these problems, see AOT Metadata Errors.
Configuring AOT compilation
You can provide options in the TypeScript configuration file that controls the compilation process. See Angular compiler options for a complete list of available options.
Phase 1: Code analysis
The TypeScript compiler does some of the analytic work of the first phase. It emits the .d.tstype definition files with type information that the AOT compiler needs to generate application code. At the same time, the AOT collector analyzes the metadata recorded in the Angular decorators and outputs metadata information in .metadata.json files, one per .d.ts file.
You can think of .metadata.json as a diagram of the overall structure of a decorator’s metadata, represented as an abstract syntax tree (AST).
Angular’s schema.ts describes the JSON format as a collection of TypeScript interfaces.
Expression syntax limitations
The AOT collector only understands a subset of JavaScript. Define metadata objects with the following limited syntax:
Syntax
Example
Literal object
{cherry: true, apple: true, mincemeat: false}
Literal array
['cherries', 'flour', 'sugar']
Spread in literal array
['apples', 'flour', ...]
Calls
bake(ingredients)
New
new Oven()
Property access
pie.slice
Array index
ingredients[0]
Identity reference
Component
A template string
pie is ${multiplier} times better than cake
Literal string
'pi'
Literal number
3.14153265
Literal boolean
true
Literal null
null
Supported prefix operator
!cake
Supported binary operator
a+b
Conditional operator
a ? b : c
Parentheses
(a+b)
If an expression uses unsupported syntax, the collector writes an error node to the .metadata.json file. The compiler later reports the error if it needs that piece of metadata to generate the application code.
If you want ngc to report syntax errors immediately rather than produce a .metadata.json file with errors, set the strictMetadataEmit option in the TypeScript configuration file.
Angular libraries have this option to ensure that all Angular .metadata.json files are clean and it is a best practice to do the same when building your own libraries.
No arrow functions
The AOT compiler does not support function expressions and arrow functions, also called lambda functions.
The AOT collector does not support the arrow function, () => new Server(), in a metadata expression. It generates an error node in place of the function. When the compiler later interprets this node, it reports an error that invites you to turn the arrow function into an exported function.
You can fix the error by converting to this:
content_copyexport function serverFactory() {
return new Server();
}
@Component({
…
providers: [{provide: server, useFactory: serverFactory}]
})
In version 5 and later, the compiler automatically performs this rewriting while emitting the .js file.
Code folding
The compiler can only resolve references to exported symbols. The collector, however, can evaluate an expression during collection and record the result in the .metadata.json, rather than the original expression. This allows you to make limited use of non-exported symbols within expressions.
For example, the collector can evaluate the expression 1 + 2 + 3 + 4 and replace it with the result, 10. This process is called folding. An expression that can be reduced in this manner is foldable.
The collector can evaluate references to module-local const declarations and initialized var and let declarations, effectively removing them from the .metadata.json file.
The compiler could not refer to the template constant because it isn’t exported. The collector, however, can fold the template constant into the metadata definition by in-lining its contents. The effect is the same as if you had written:
There is no longer a reference to template and, therefore, nothing to trouble the compiler when it later interprets the collector’s output in .metadata.json.
You can take this example a step further by including the template constant in another expression:
The following table describes which expressions the collector can and cannot fold:
Syntax
Foldable
Literal object
yes
Literal array
yes
Spread in literal array
no
Calls
no
New
no
Property access
yes, if target is foldable
Array index
yes, if target and index are foldable
Identity reference
yes, if it is a reference to a local
A template with no substitutions
yes
A template with substitutions
yes, if the substitutions are foldable
Literal string
yes
Literal number
yes
Literal boolean
yes
Literal null
yes
Supported prefix operator
yes, if operand is foldable
Supported binary operator
yes, if both left and right are foldable
Conditional operator
yes, if condition is foldable
Parentheses
yes, if the expression is foldable
If an expression is not foldable, the collector writes it to .metadata.json as an AST for the compiler to resolve.
Phase 2: code generation
The collector makes no attempt to understand the metadata that it collects and outputs to .metadata.json. It represents the metadata as best it can and records errors when it detects a metadata syntax violation. It’s the compiler’s job to interpret the .metadata.json in the code generation phase.
The compiler understands all syntax forms that the collector supports, but it may reject syntactically correct metadata if the semantics violate compiler rules.
Public or protected symbols
The compiler can only reference exported symbols.
Decorated component class members must be public or protected. You cannot make an @Input() property private.
Data bound properties must also be public or protected
Supported classes and functions
The collector can represent a function call or object creation with new as long as the syntax is valid. The compiler, however, can later refuse to generate a call to a particular function or creation of a particular object.
The compiler can only create instances of certain classes, supports only core decorators, and only supports calls to macros (functions or static methods) that return expressions.
Compiler action
Details
New instances
The compiler only allows metadata that create instances of the class InjectionToken from @angular/core.
Supported decorators
The compiler only supports metadata for the Angular decorators in the @angular/core module.
Function calls
Factory functions must be exported, named functions. The AOT compiler does not support lambda expressions (“arrow functions”) for factory functions.
Functions and static method calls
The collector accepts any function or static method that contains a single return statement. The compiler, however, only supports macros in the form of functions or static methods that return an expression.
For example, consider the following function:
content_copyexport function wrapInArray<T>(value: T): T[] {
return [value];
}
You can call the wrapInArray in a metadata definition because it returns the value of an expression that conforms to the compiler’s restrictive JavaScript subset.
You might use wrapInArray() like this:
content_copy@NgModule({
declarations: wrapInArray(TypicalComponent)
})
export class TypicalModule {}
The compiler treats this usage as if you had written:
content_copy@NgModule({
declarations: [TypicalComponent]
})
export class TypicalModule {}
The Angular RouterModule exports two macro static methods, forRoot and forChild, to help declare root and child routes. Review the source code for these methods to see how macros can simplify configuration of complex NgModules.
Metadata rewriting
The compiler treats object literals containing the fields useClass, useValue, useFactory, and data specially, converting the expression initializing one of these fields into an exported variable that replaces the expression. This process of rewriting these expressions removes all the restrictions on what can be in them because the compiler doesn’t need to know the expression’s value —it just needs to be able to generate a reference to the value.
Without rewriting, this would be invalid because lambdas are not supported and TypicalServer is not exported. To allow this, the compiler automatically rewrites this to something like:
This allows the compiler to generate a reference to θ0 in the factory without having to know what the value of θ0 contains.
The compiler does the rewriting during the emit of the .js file. It does not, however, rewrite the .d.ts file, so TypeScript doesn’t recognize it as being an export. And it does not interfere with the ES module’s exported API.
Phase 3: Template type checking
One of the Angular compiler’s most helpful features is the ability to type-check expressions within templates, and catch any errors before they cause crashes at runtime. In the template type-checking phase, the Angular template compiler uses the TypeScript compiler to validate the binding expressions in templates.
Enable this phase explicitly by adding the compiler option "fullTemplateTypeCheck" in the "angularCompilerOptions" of the project’s TypeScript configuration file (see Angular Compiler Options).
Template validation produces error messages when a type error is detected in a template binding expression, similar to how type errors are reported by the TypeScript compiler against code in a .ts file.
my.component.ts.MyComponent.html(1,1): : Property 'addresss' does not exist on type 'Person'. Did you mean 'address'?
The file name reported in the error message, my.component.ts.MyComponent.html, is a synthetic file generated by the template compiler that holds contents of the MyComponent class template. The compiler never writes this file to disk. The line and column numbers are relative to the template string in the @Component annotation of the class, MyComponent in this case. If a component uses templateUrl instead of template, the errors are reported in the HTML file referenced by the templateUrl instead of a synthetic file.
The error location is the beginning of the text node that contains the interpolation expression with the error. If the error is in an attribute binding such as [value]="person.address.street", the error location is the location of the attribute that contains the error.
The validation uses the TypeScript type checker and the options supplied to the TypeScript compiler to control how detailed the type validation is. For example, if the strictTypeChecks is specified, the error
my.component.ts.MyComponent.html(1,1): : Object is possibly 'undefined'
is reported as well as the above error message.
Type narrowing
The expression used in an ngIf directive is used to narrow type unions in the Angular template compiler, the same way the if expression does in TypeScript. For example, to avoid Object is possibly 'undefined' error in the template above, modify it to only emit the interpolation if the value of person is initialized as shown below:
Using *ngIf allows the TypeScript compiler to infer that the person used in the binding expression will never be undefined.
For more information about input type narrowing, see Improving template type checking for custom directives.
Non-null type assertion operator
Use the non-null type assertion operator to suppress the Object is possibly 'undefined' error when it is inconvenient to use *ngIf or when some constraint in the component ensures that the expression is always non-null when the binding expression is interpolated.
In the following example, the person and address properties are always set together, implying that address is always non-null if person is non-null. There is no convenient way to describe this constraint to TypeScript and the template compiler, but the error is suppressed in the example by using address!.street.
Before fully deploying your application, you can test the process, build configuration, and deployed behavior by using one of these interim techniques.
Building and serving from disk
During development, you typically use the ng serve command to build, watch, and serve the application from local memory, using webpack-dev-server. When you are ready to deploy, however, you must use the ng build command to build the application and deploy the build artifacts elsewhere.
Both ng build and ng serve clear the output folder before they build the project, but only the ng build command writes the generated build artifacts to the output folder.
The output folder is dist/project-name/ by default. To output to a different folder, change the outputPath in angular.json.
As you near the end of the development process, serving the contents of your output folder from a local web server can give you a better idea of how your application will behave when it is deployed to a remote server. You will need two terminals to get the live-reload experience.
On the first terminal, run the ng build command in watch mode to compile the application to the dist folder.content_copyng build --watchLike the ng serve command, this regenerates output files when source files change.
On the second terminal, install a web server (such as lite-server), and run it against the output folder. For example:content_copylite-server --baseDir="dist/project-name"The server will automatically reload your browser when new files are output.
This method is for development and testing only, and is not a supported or secure way of deploying an application.
Automatic deployment with the CLI
The Angular CLI command ng deploy (introduced in version 8.3.0) executes the deploy CLI builder associated with your project. A number of third-party builders implement deployment capabilities to different platforms. You can add any of them to your project by running ng add [package name].
When you add a package with deployment capability, it’ll automatically update your workspace configuration (angular.json file) with a deploy section for the selected project. You can then use the ng deploy command to deploy that project.
For example, the following command automatically deploys a project to Firebase.
content_copyng add @angular/fire
ng deploy
The command is interactive. In this case, you must have or create a Firebase account, and authenticate using that account. The command prompts you to select a Firebase project for deployment
The command builds your application and uploads the production assets to Firebase.
In the table below, you can find a list of packages which implement deployment functionality to different platforms. The deploy command for each package may require different command line options. You can read more by following the links associated with the package names below:
Deployment to
Package
Firebase hosting
@angular/fire
Vercel
vercel init angular
Netlify
@netlify-builder/deploy
GitHub pages
angular-cli-ghpages
Amazon Cloud S3
@jefiozie/ngx-aws-deploy
If you’re deploying to a self-managed server or there’s no builder for your favorite cloud platform, you can either create a builder that allows you to use the ng deploy command, or read through this guide to learn how to manually deploy your application.
Basic deployment to a remote server
For the simplest deployment, create a production build and copy the output directory to a web server.
Start with the production build:content_copyng build
Copy everything within the output folder (dist/project-name/ by default) to a folder on the server.
Configure the server to redirect requests for missing files to index.html. Learn more about server-side redirects below.
This is the simplest production-ready deployment of your application.
Deploy to GitHub Pages
To deploy your Angular application to GitHub Pages, complete the following steps:
Create a GitHub repository for your project.
Configure git in your local project by adding a remote that specifies the GitHub repository you created in previous step. GitHub provides these commands when you create the repository so that you can copy and paste them at your command prompt. The commands should be similar to the following, though GitHub fills in your project-specific settings for you:content_copygit remote add origin https://github.com/your-username/your-project-name.git git branch -M main git push -u origin mainWhen you paste these commands from GitHub, they run automatically.
Create and check out a git branch named gh-pages.content_copygit checkout -b gh-pages
Build your project using the GitHub project name, with the Angular CLI command ng build and the following options, where your_project_name is the name of the project that you gave the GitHub repository in step 1.Be sure to include the slashes on either side of your project name as in /your_project_name/.content_copyng build --output-path docs --base-href /your_project_name/
When the build is complete, make a copy of docs/index.html and name it docs/404.html.
Commit your changes and push.
On the GitHub project page, go to Settings and select the Pages option from the left sidebar to configure the site to publish from the docs folder.
Click Save.
Click on the GitHub Pages link at the top of the GitHub Pages section to see your deployed application. The format of the link is https://<user_name>.github.io/<project_name>.
Check out angular-cli-ghpages, a full-featured package that does all this for you and has extra functionality.
Server configuration
This section covers changes you may have to make to the server or to files deployed on the server.
Routed apps must fall back 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 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.
Servers
Details
Apache
Add a rewrite rule to the .htaccess file as shown (ngmilk.rocks/2015/03/09/angularjs-html5-mode-or-pretty-urls-on-apache-using-htaccess):content_copyRewriteEngine 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
Use try_files, as described in Front Controller Pattern Web Apps, modified to serve index.html:content_copytry_files $uri $uri/ /index.html;
Ruby
Create a Ruby server using (sinatra) with a basic Ruby file that configures the server server.rb:content_copyrequire '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
Add a rewrite rule to web.config, similar to the one shown here:content_copy<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
You can’t directly configure 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 fromdocson main and to create a.nojekyllfile
Configuring correct MIME-type for JavaScript assets
All of your application JavaScript files must be served by the server with the Content-Typeheader set to text/javascript or another JavaScript-compatible MIME-type.
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.
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.
Production optimizations
The production configuration engages the following build optimization features.
Features
Details
Ahead-of-Time (AOT) Compilation
Pre-compiles Angular component templates.
Production mode
Optimizes the application for the best runtime performance
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 for more about CLI build options and what they do.
Production mode at runtime
When you run an application locally using ng serve, Angular uses the development mode configuration at runtime. The development mode at runtime enables extra safety checks, more detailed error messages and debugging utilities, such as the expression-changed-after-checked detection. Angular outputs a message in the browser console to indicate that the development mode is enabled.
Those extra checks are helpful during the development, but they require an extra code in a bundle, which is undesirable in production. To ensure that there are no implications on the bundle size, the build optimizer removes the development-only code from the bundle when building in production mode.
Building your application with the production configuration automatically enables Angular’s runtime production mode.
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 or by 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 which automatically recognizes lazy-loaded NgModules and creates separate bundles for them.
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 tool is another good choice that can also help verify that your deployment was successful.
Inspect the bundles
The source-map-explorer tool is a great way to inspect the generated JavaScript bundles after a production build.
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.
The base tag
The HTML <base href="..." /> specifies a base path for resolving relative URLs to assets such as images, scripts, and style sheets. For example, given the <base href="/my/app/">, 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 alternative.
In development, you typically start the server in the folder that holds index.html. That’s the root folder and you’d add <base href="/"> 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 <base href="/my/app/"> 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.
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). Users with more complicated setups may need to manually configure the APP_BASE_HREF token within the application (for example, 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.