Angular 9 - Basic HTTP Authentication Tutorial & Example
Tutorial built with Angular 9.1.3
Other versions available:
- Angular: Angular 14, 10, 8, 6
- React: React 16, React 17 + Recoil
- Vue: Vue 3 + Pinia, Vue 2
- Next.js: Next.js 11
- AngularJS: AngularJS
- Blazor: Blazor WebAssembly
This is an example of how to setup a simple login page using Angular 9 and Basic HTTP authentication.
Angular CLI was used to generate the base project structure with the ng new <project name>
command, the CLI is also used to build and serve the application. For more info about the Angular CLI see https://angular.io/cli.
Styling of the example app is all done with Bootstrap 4.4 css, for more info about Bootstrap see https://getbootstrap.com/docs/4.4/getting-started/introduction/.
The tutorial app code is available on GitHub at https://github.com/cornflourblue/angular-9-basic-authentication-example.
Here it is in action: (See on StackBlitz at https://stackblitz.com/edit/angular-9-basic-authentication-example)
Running the Angular 9 Basic Auth Example Locally
- Install Node and NPM from https://nodejs.org.
- Download or clone the tutorial project source code from https://github.com/cornflourblue/angular-9-basic-authentication-example
- Install all required npm packages by running
npm install
ornpm i
from the command line in the project root folder (where the package.json is located). - Start the application by running
npm start
from the command line in the project root folder, this will build the application and automatically launch it in the browser on the URLhttp://localhost:4200
.
NOTE: You can also start the app with the Angular CLI command ng serve --open
. To do this first install the Angular CLI globally on your system with the command npm install -g @angular/cli
.
For more info on setting up an Angular development environment see Angular - Setup Development Environment.
Running the Example with a Real Backend API
The Angular 9 basic authentication example app uses a fake backend by default so it can run in the browser without a real api, to switch to a real backend api you just have to remove or comment out the line below the comment // provider used to create fake backend
located in the /src/app/app.module.ts
file.
You can build your own backend api or start with one of the below options:
- To run the Angular 9 basic auth example with a real backend API built with ASP.NET Core 3.1 follow the instructions at ASP.NET Core 3.1 - Basic Authentication Tutorial with Example API
- For a real backend API built with Node.js follow the instructions at NodeJS - Basic Authentication Tutorial with Example API
Angular 9 Project Structure
The app and code structure of the tutorial mostly follows the best practice recommendations in the official Angular Style Guide, with a few of my own tweaks here and there.
Each feature has it's own folder (home & login), other shared/common code such as services, models, helpers etc are placed in folders prefixed with an underscore _
to easily differentiate them and group them together at the top of the folder structure.
The index.ts
files in each folder are barrel files that group the exported modules from a folder together so they can be imported using the folder path instead of the full module path and to enable importing multiple modules in a single import (e.g. import { AuthenticationService, UserService } from '../_services'
).
Path aliases @app
and @environments
have been configured in tsconfig.json that map to the /src/app
and /src/environments
directories. This allows imports to be relative to the app and environments folders by prefixing import paths with aliases instead of having to use long relative paths (e.g. import MyComponent from '../../../MyComponent'
).
Here are the main project files that contain the application logic, I left out some files that were generated by Angular CLI ng new
command that I didn't change.
- src
- app
- _helpers
- _models
- user.ts
- index.ts
- _services
- authentication.service.ts
- user.service.ts
- index.ts
- home
- home.component.html
- home.component.ts
- index.ts
- login
- login.component.html
- login.component.ts
- index.ts
- app-routing.module.ts
- app.component.html
- app.component.ts
- app.module.ts
- environments
- index.html
- main.ts
- polyfills.ts
- styles.less
- app
- package.json
- tsconfig.json
Auth Guard
The auth guard is an angular route guard that's used to prevent unauthenticated users from accessing restricted routes, it does this by implementing the CanActivate
interface which allows the guard to decide if a route can be activated with the canActivate()
method. If the method returns true
the route is activated (allowed to proceed), otherwise if the method returns false
the route is blocked.
The auth guard uses the authentication service to check if the user is logged in, if they are logged in it returns true
from the canActivate()
method, otherwise it returns false
and redirects the user to the login page.
Angular route guards are attached to routes in the router config, this auth guard is used in app-routing.module.ts to protect the home page route.
import { Injectable } from '@angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { AuthenticationService } from '@app/_services';
@Injectable({ providedIn: 'root' })
export class AuthGuard implements CanActivate {
constructor(
private router: Router,
private authenticationService: AuthenticationService
) { }
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
const user = this.authenticationService.userValue;
if (user) {
// logged in so return true
return true;
}
// not logged in so redirect to login page with the return url
this.router.navigate(['/login'], { queryParams: { returnUrl: state.url } });
return false;
}
}
Basic Authentication Interceptor
The Basic Authentication Interceptor intercepts http requests from the application to add basic authentication credentials to the Authorization header if the user is logged in and the request is to the application api url (environment.apiUrl
).
It's implemented using the HttpInterceptor
interface included in the HttpClientModule
, by implementing the HttpInterceptor interface you can create a custom interceptor to modify http requests before they get sent to the server.
Http interceptors are added to the request pipeline in the providers section of the app.module.ts file.
import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { Observable } from 'rxjs';
import { environment } from '@environments/environment';
import { AuthenticationService } from '@app/_services';
@Injectable()
export class BasicAuthInterceptor implements HttpInterceptor {
constructor(private authenticationService: AuthenticationService) { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// add header with basic auth credentials if user is logged in and request is to the api url
const user = this.authenticationService.userValue;
const isLoggedIn = user && user.authdata;
const isApiUrl = request.url.startsWith(environment.apiUrl);
if (isLoggedIn && isApiUrl) {
request = request.clone({
setHeaders: {
Authorization: `Basic ${user.authdata}`
}
});
}
return next.handle(request);
}
}
Http Error Interceptor
The Error Interceptor intercepts http responses from the api to check if there were any errors. If there is a 401 Unauthorized response the user is automatically logged out of the application, all other errors are re-thrown up to the calling service so an alert with the error can be displayed on the screen.
It's implemented using the HttpInterceptor
interface included in the HttpClientModule
, by implementing the HttpInterceptor interface you can create a custom interceptor to modify http requests before they get sent to the server.
Http interceptors are added to the request pipeline in the providers section of the app.module.ts file.
import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { AuthenticationService } from '@app/_services';
@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
constructor(private authenticationService: AuthenticationService) { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request).pipe(catchError(err => {
if (err.status === 401) {
// auto logout if 401 response returned from api
this.authenticationService.logout();
}
const error = err.error.message || err.statusText;
return throwError(error);
}))
}
}
Fake Backend Provider
In order to run and test the Angular application without a real backend API, the example uses a fake backend that intercepts the HTTP requests from the Angular app and send back "fake" responses. This is done by a class that implements the Angular HttpInterceptor
interface, for more information on Angular HTTP Interceptors see https://angular.io/api/common/http/HttpInterceptor or this article.
The fake backend contains a handleRoute
function that checks if the request matches one of the faked routes in the switch statement, at the moment this includes POST
requests to the /users/authenticate
route for handling authentication, and GET
requests to the /users
route for getting all users.
Requests to the authenticate route are handled by the authenticate()
function which checks the username and password against an array of hardcoded users
. If the username and password are correct then an ok
response is returned with the user details, otherwise an error
response is returned.
Requests to the get users route are handled by the getUsers()
function which checks if the user is logged in by calling the new isLoggedIn()
helper function. If the user is logged in an ok()
response with the whole users
array is returned, otherwise a 401 Unauthorized
response is returned by calling the new unauthorized()
helper function.
If the request doesn't match any of the faked routes it is passed through as a real HTTP request to the backend API.
import { Injectable } from '@angular/core';
import { HttpRequest, HttpResponse, HttpHandler, HttpEvent, HttpInterceptor, HTTP_INTERCEPTORS } from '@angular/common/http';
import { Observable, of, throwError } from 'rxjs';
import { delay, mergeMap, materialize, dematerialize } from 'rxjs/operators';
import { User } from '@app/_models';
const users: User[] = [{ id: 1, username: 'test', password: 'test', firstName: 'Test', lastName: 'User' }];
@Injectable()
export class FakeBackendInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const { url, method, headers, body } = request;
// wrap in delayed observable to simulate server api call
return of(null)
.pipe(mergeMap(handleRoute))
.pipe(materialize()) // call materialize and dematerialize to ensure delay even if an error is thrown (https://github.com/Reactive-Extensions/RxJS/issues/648)
.pipe(delay(500))
.pipe(dematerialize());
function handleRoute() {
switch (true) {
case url.endsWith('/users/authenticate') && method === 'POST':
return authenticate();
case url.endsWith('/users') && method === 'GET':
return getUsers();
default:
// pass through any requests not handled above
return next.handle(request);
}
}
// route functions
function authenticate() {
const { username, password } = body;
const user = users.find(x => x.username === username && x.password === password);
if (!user) return error('Username or password is incorrect');
return ok({
id: user.id,
username: user.username,
firstName: user.firstName,
lastName: user.lastName
})
}
function getUsers() {
if (!isLoggedIn()) return unauthorized();
return ok(users);
}
// helper functions
function ok(body?) {
return of(new HttpResponse({ status: 200, body }))
}
function error(message) {
return throwError({ error: { message } });
}
function unauthorized() {
return throwError({ status: 401, error: { message: 'Unauthorised' } });
}
function isLoggedIn() {
return headers.get('Authorization') === `Basic ${window.btoa('test:test')}`;
}
}
}
export let fakeBackendProvider = {
// use fake backend in place of Http service for backend-less development
provide: HTTP_INTERCEPTORS,
useClass: FakeBackendInterceptor,
multi: true
};
User Model
The user model is a small class that defines the properties of a user.
export class User {
id: number;
username: string;
password: string;
firstName: string;
lastName: string;
authdata?: string;
}
Authentication Service
The authentication service is used to login & logout of the Angular app, it notifies other components when the user logs in & out, and allows access the currently logged in user.
RxJS Subjects and Observables are used to store the current user object and notify other components when the user logs in and out of the app. Angular components can subscribe()
to the public user: Observable
property to be notified of changes, and notifications are sent when the this.userSubject.next()
method is called in the login()
and logout()
methods, passing the argument to each subscriber. The RxJS BehaviorSubject
is a special type of Subject that keeps hold of the current value and emits it to any new subscribers as soon as they subscribe, while regular Subjects don't store the current value and only emit values that are published after a subscription is created. For more info on communicating between components with RxJS Observables see this post.
The login()
method sends the user credentials to the API via an HTTP POST request for authentication. If successful the user's basic authentication data (base64 encoded username and password) is added to the user object and stored in localStorage to keep the user logged in between page refreshes. The user object is then published to all subscribers with the call to this.userSubject.next(user);
.
The basic auth data is used by the basic authentication interceptor above to set the authorization header of http requests made to secure api endpoints.
The constructor()
of the service initialises the userSubject
with the user object from localStorage which enables the user to stay logged in between page refreshes or after the browser is closed. The public user
property is then set to this.userSubject.asObservable();
which allows other components to subscribe to the user
Observable but doesn't allow them to publish to the userSubject
, this is so logging in and out of the app can only be done via the authentication service.
The userValue
getter allows other components an easy way to get the value of the currently logged in user without having to subscribe to the user
Observable.
The logout()
method removes the current user object from local storage, publishes null
to the userSubject
to notify all subscribers that the user has logged out and navigates to the /login
page.
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { environment } from '@environments/environment';
import { User } from '@app/_models';
@Injectable({ providedIn: 'root' })
export class AuthenticationService {
private userSubject: BehaviorSubject<User>;
public user: Observable<User>;
constructor(
private router: Router,
private http: HttpClient
) {
this.userSubject = new BehaviorSubject<User>(JSON.parse(localStorage.getItem('user')));
this.user = this.userSubject.asObservable();
}
public get userValue(): User {
return this.userSubject.value;
}
login(username: string, password: string) {
return this.http.post<any>(`${environment.apiUrl}/users/authenticate`, { username, password })
.pipe(map(user => {
// store user details and basic auth credentials in local storage to keep user logged in between page refreshes
user.authdata = window.btoa(username + ':' + password);
localStorage.setItem('user', JSON.stringify(user));
this.userSubject.next(user);
return user;
}));
}
logout() {
// remove user from local storage to log user out
localStorage.removeItem('user');
this.userSubject.next(null);
this.router.navigate(['/login']);
}
}
User Service
The user service contains a method for getting all users from the api, I included it to demonstrate accessing a secure api endpoint with the http authorization header set after logging in to the application, the auth header is automatically set with basic authentication credentials by the basic authentication interceptor. The secure endpoint in the example is a fake one implemented in the fake backend provider.
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { environment } from '@environments/environment';
import { User } from '@app/_models';
@Injectable({ providedIn: 'root' })
export class UserService {
constructor(private http: HttpClient) { }
getAll() {
return this.http.get<User[]>(`${environment.apiUrl}/users`);
}
}
Home Component Template
The home component template contains html and angular 9 template syntax for displaying a simple welcome message and a list of users from a secure api endpoint.
<div class="card mt-4">
<h4 class="card-header">You're logged in with Angular 9 & Basic HTTP Authentication!!</h4>
<div class="card-body">
<h6>Users from secure api end point</h6>
<div *ngIf="loading" class="spinner-border spinner-border-sm"></div>
<ul *ngIf="users">
<li *ngFor="let user of users">{{user.firstName}} {{user.lastName}}</li>
</ul>
</div>
</div>
Home Component
The home component defines an angular 9 component that gets all users from the user service and makes them available to the template via a users
array property.
import { Component } from '@angular/core';
import { first } from 'rxjs/operators';
import { User } from '@app/_models';
import { UserService } from '@app/_services';
@Component({ templateUrl: 'home.component.html' })
export class HomeComponent {
loading = false;
users: User[];
constructor(private userService: UserService) { }
ngOnInit() {
this.loading = true;
this.userService.getAll().pipe(first()).subscribe(users => {
this.loading = false;
this.users = users;
});
}
}
Login Component Template
The login component template contains a login form with username and password fields. It displays validation messages for invalid fields when the submit button is clicked. The form submit event is bound to the onSubmit()
method of the login component.
The component uses reactive form validation to validate the input fields, for more information about angular reactive form validation see Angular 9 - Reactive Forms Validation Example.
<div class="col-md-6 offset-md-3 mt-5">
<div class="alert alert-info">
Username: test<br />
Password: test
</div>
<div class="card">
<h4 class="card-header">Angular 9 Basic Authentication Example</h4>
<div class="card-body">
<form [formGroup]="loginForm" (ngSubmit)="onSubmit()">
<div class="form-group">
<label for="username">Username</label>
<input type="text" formControlName="username" class="form-control" [ngClass]="{ 'is-invalid': submitted && f.username.errors }" />
<div *ngIf="submitted && f.username.errors" class="invalid-feedback">
<div *ngIf="f.username.errors.required">Username is required</div>
</div>
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" formControlName="password" class="form-control" [ngClass]="{ 'is-invalid': submitted && f.password.errors }" />
<div *ngIf="submitted && f.password.errors" class="invalid-feedback">
<div *ngIf="f.password.errors.required">Password is required</div>
</div>
</div>
<button [disabled]="loading" class="btn btn-primary">
<span *ngIf="loading" class="spinner-border spinner-border-sm mr-1"></span>
Login
</button>
<div *ngIf="error" class="alert alert-danger mt-3 mb-0">{{error}}</div>
</form>
</div>
</div>
</div>
Login Component
The login component uses the authentication service to login to the application. If the user is already logged in they are automatically redirected to the home page.
The loginForm: FormGroup
object defines the form controls and validators, and is used to access data entered into the form. The FormGroup is part of the Angular Reactive Forms module and is bound to the login template above with the [formGroup]="loginForm"
directive.
import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { first } from 'rxjs/operators';
import { AuthenticationService } from '@app/_services';
@Component({ templateUrl: 'login.component.html' })
export class LoginComponent implements OnInit {
loginForm: FormGroup;
loading = false;
submitted = false;
returnUrl: string;
error = '';
constructor(
private formBuilder: FormBuilder,
private route: ActivatedRoute,
private router: Router,
private authenticationService: AuthenticationService
) {
// redirect to home if already logged in
if (this.authenticationService.userValue) {
this.router.navigate(['/']);
}
}
ngOnInit() {
this.loginForm = this.formBuilder.group({
username: ['', Validators.required],
password: ['', Validators.required]
});
// get return url from route parameters or default to '/'
this.returnUrl = this.route.snapshot.queryParams['returnUrl'] || '/';
}
// convenience getter for easy access to form fields
get f() { return this.loginForm.controls; }
onSubmit() {
this.submitted = true;
// stop here if form is invalid
if (this.loginForm.invalid) {
return;
}
this.loading = true;
this.authenticationService.login(this.f.username.value, this.f.password.value)
.pipe(first())
.subscribe(
data => {
this.router.navigate([this.returnUrl]);
},
error => {
this.error = error;
this.loading = false;
});
}
}
App Routing Module
Routing for the Angular app is configured as an array of Routes
, each component is mapped to a path so the Angular Router knows which component to display based on the URL in the browser address bar. The home route is secured by passing the AuthGuard to the canActivate
property of the route.
The routes
array is passed to the RouterModule.forRoot()
method which creates a routing module with all of the app routes configured, and also includes all of the Angular Router providers and directives such as the <router-outlet></router-outlet>
directive. For more information on Angular Routing and Navigation see https://angular.io/guide/router.
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { HomeComponent } from './home';
import { LoginComponent } from './login';
import { AuthGuard } from './_helpers';
const routes: Routes = [
{ path: '', component: HomeComponent, canActivate: [AuthGuard] },
{ path: 'login', component: LoginComponent },
// otherwise redirect to home
{ path: '**', redirectTo: '' }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
App Component Template
The app component template is the root component template of the application, it contains the main nav bar which is only displayed for authenticated users, and a router-outlet
component for displaying the contents of each view based on the current route / path.
<!-- nav -->
<nav class="navbar navbar-expand navbar-dark bg-dark" *ngIf="user">
<div class="navbar-nav">
<a class="nav-item nav-link" routerLink="/">Home</a>
<a class="nav-item nav-link" (click)="logout()">Logout</a>
</div>
</nav>
<!-- main app container -->
<div class="container">
<router-outlet></router-outlet>
</div>
App Component
The app component is the root component of the application, it defines the root tag of the app as <app></app>
with the selector property of the @Component()
decorator.
It subscribes to the user
observable in the authentication service so it can reactively show/hide the main navigation bar when the user logs in/out of the application. I didn't worry about unsubscribing from the observable here because it's the root component of the application, the only time the component will be destroyed is when the application is closed which would destroy any subscriptions as well.
The app component contains a logout()
method which is called from the logout link in the main nav bar above to log the user out and redirect them to the login page.
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { AuthenticationService } from './_services';
import { User } from './_models';
@Component({ selector: 'app', templateUrl: 'app.component.html' })
export class AppComponent {
user: User;
constructor(
private router: Router,
private authenticationService: AuthenticationService
) {
this.authenticationService.user.subscribe(x => this.user = x);
}
logout() {
this.authenticationService.logout();
}
}
App Module
The app module defines the root module of the application along with metadata about the module. For more info about angular 9 modules check out this page on the official docs site.
This is where the fake backend provider is added to the application, to switch to a real backend simply remove the providers located below the comment // provider used to create fake backend
.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
// used to create fake backend
import { fakeBackendProvider } from './_helpers';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
import { BasicAuthInterceptor, ErrorInterceptor } from './_helpers';
import { HomeComponent } from './home';
import { LoginComponent } from './login';
@NgModule({
imports: [
BrowserModule,
ReactiveFormsModule,
HttpClientModule,
AppRoutingModule
],
declarations: [
AppComponent,
HomeComponent,
LoginComponent
],
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: BasicAuthInterceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true },
// provider used to create fake backend
fakeBackendProvider
],
bootstrap: [AppComponent]
})
export class AppModule { }
Production Environment Config
The production environment config contains variables required to run the application in production. This enables you to build the application with a different configuration for each different environment (e.g. production & development) without updating the app code.
When you build the application for production with the command ng build --prod
, the output environment.ts
is replaced with environment.prod.ts
.
export const environment = {
production: true,
apiUrl: 'http://localhost:4000'
};
Development Environment Config
The development environment config contains variables required to run the application in development.
Environment config is accessed by importing the environment object into any Angular service of component with the line import { environment } from '@environments/environment'
and accessing properties on the environment
object, see the user service for an example.
export const environment = {
production: false,
apiUrl: 'http://localhost:4000'
};
Main Index Html File
The main index.html file is the initial page loaded by the browser that kicks everything off. The Angular CLI (with Webpack under the hood) bundles all of the compiled javascript files together and injects them into the body of the index.html page so the scripts can be loaded and executed by the browser.
<!DOCTYPE html>
<html>
<head>
<base href="/" />
<title>Angular 9 - Basic HTTP Authentication Tutorial & Example</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- bootstrap css -->
<link href="//netdna.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<app>Loading...</app>
</body>
</html>
Main (Bootstrap) File
The main file is the entry point used by angular to launch and bootstrap the application.
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
Polyfills
Some features used by Angular 9 are not yet supported natively by all major browsers, polyfills are used to add support for features where necessary so your Angular 9 application works across all major browsers.
This file is generated by the Angular CLI when creating a new project with the ng new
command, I've excluded the comments in the file for brevity.
import 'zone.js/dist/zone';
Global LESS/CSS Styles
The global styles file contains LESS/CSS styles that are applied globally throughout the application.
/* You can add global styles to this file, and also import other style files */
a { cursor: pointer }
npm package.json
The package.json file contains project configuration information including package dependencies that get installed when you run npm install
and scripts that get executed when you run npm start
or npm run build
etc. Full documentation is available on the https://docs.npmjs.com/files/package.json.
{
"name": "angular-9-basic-authentication-example",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve --open",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"private": true,
"dependencies": {
"@angular/animations": "~9.1.1",
"@angular/common": "~9.1.1",
"@angular/compiler": "~9.1.1",
"@angular/core": "~9.1.1",
"@angular/forms": "~9.1.1",
"@angular/platform-browser": "~9.1.1",
"@angular/platform-browser-dynamic": "~9.1.1",
"@angular/router": "~9.1.1",
"rxjs": "~6.5.4",
"tslib": "^1.10.0",
"zone.js": "~0.10.2"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.901.1",
"@angular/cli": "~9.1.1",
"@angular/compiler-cli": "~9.1.1",
"@angular/language-service": "~9.1.1",
"@types/node": "^12.11.1",
"@types/jasmine": "~3.5.0",
"@types/jasminewd2": "~2.0.3",
"codelyzer": "^5.1.2",
"jasmine-core": "~3.5.0",
"jasmine-spec-reporter": "~4.2.1",
"karma": "~4.4.1",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage-istanbul-reporter": "~2.1.0",
"karma-jasmine": "~3.0.1",
"karma-jasmine-html-reporter": "^1.4.2",
"protractor": "~5.4.3",
"ts-node": "~8.3.0",
"tslint": "~6.1.0",
"typescript": "~3.8.3"
}
}
TypeScript tsconfig.json
The tsconfig.json file configures how the TypeScript compiler will convert TypeScript into JavaScript that is understood by the browser. For more info see https://www.typescriptlang.org/docs/handbook/tsconfig-json.html.
Most of the file is unchanged from when it was generated by the Angular CLI, only the paths
property has been added to map @app
and @environments
to the /src/app
and /src/environments
directories. This allows imports to be relative to the app and environments folders by prefixing import paths with aliases instead of having to use long relative paths (e.g. import MyComponent from '../../../MyComponent'
).
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"downlevelIteration": true,
"experimentalDecorators": true,
"module": "esnext",
"moduleResolution": "node",
"importHelpers": true,
"target": "es2015",
"lib": [
"es2018",
"dom"
],
"paths": {
"@app/*": ["src/app/*"],
"@environments/*": ["src/environments/*"]
}
},
"angularCompilerOptions": {
"fullTemplateTypeCheck": true,
"strictInjectionParameters": true
}
}
Need Some Angular 9 Help?
Search fiverr for freelance Angular 9 developers.
Follow me for updates
When I'm not coding...
Me and Tina are on a motorcycle adventure around Australia.
Come along for the ride!