Personalize Your Angular Build With Webpack
Join the DZone community and get the full member experience.
Join For FreeIf you’re a front-end developer, then there are good chances that you’ve heard or even used webpack. The Angular build process uses webpack to tackle many tasks such as transforming Sass files to CSS, and transpiling TypeScript to JavaScript.
JavaScript modules have very restricted support within web browsers. In theory, any JavaScript application should be confined within a single source file before loading it into a browser. It’s also a best practice to distinguish out code into modules contained in separate files, which is why when deploying a JavaScript application, modules are built into a single source file. Webpack’s superpower is bundling multiple modules into a single file, making it a very important build tool.
Webpack is not limited to simply bundling source files. Because it can support a multitude of plugins, it can perform many additional tasks. Webpack module loaders are able to parse different file types. This allows, for example, Angular TypeScript files to use the import
statement to import stylesheet files. Usually, webpack is hidden behind the Angular command-line tool. But in some cases, it may be necessary to tweak the configuration of webpack when building an Angular application.
In earlier versions of Angular, it was possible to eject the webpack configuration and modify it directly. With Angular 8, access to the base configuration has been disabled. But it is still possible to extend the webpack configuration and add additional loaders or configuration options. In this tutorial, I will be showing you how to create an Angular 8 application and tweak the webpack configuration.
Prerequisites: Node.js v12+.
Set Up Angular With Webpack
I will assume that you have a general knowledge of JavaScript and Angular and that you have installed node
and the npm
package manager on your system. To start you will need to globally install the Angular command-line tool. Open a terminal and install Angular with the following command.
npm install -g @angular/cli@8.3.20
Depending on your system you may have to run this command with administrator permissions using sudo
. Now navigate into a directory of your choice and create a new Angular application by running the command below.
xxxxxxxxxx
ng new angular-webpack-demo --routing --style css
To allow customization of the webpack configuration, you will need to install the custom webpack Angular builder. Navigate into the newly created directory angular-webpack-demo
and run the following command.
xxxxxxxxxx
npm install -D -E @angular-builders/custom-webpack@8.4.1
You will be using the webpack-define
plugin to inject global value definitions into your code. As an example, this could be used to feature flag parts of your applications.
To enable custom webpack configurations, open the angular.json
configuration file. Locate the line "builder": "@angular-devkit/build-angular:browser"
inside the architect.build
section. Replace it with the following lines.
xxxxxxxxxx
"builder": "@angular-builders/custom-webpack:browser",
Now, inside architect.build.options
add the following property.
xxxxxxxxxx
"customWebpackConfig": {
"path": "./custom-webpack.config.js"
},
This adds the custom-webpack.config.js
to the default webpack configuration for the ng build
command. To also enable the configuration for the ng serve
command, locate the line "builder": "@angular-devkit/build-angular:dev-server",
and replace it with the code below.
xxxxxxxxxx
"builder": "@angular-builders/custom-webpack:dev-server",
Now create the file custom-webpack.config.js
and paste the following content into it.
xxxxxxxxxx
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.DefinePlugin({
'STABLE_FEATURE': JSON.stringify(true),
'EXPERIMENTAL_FEATURE': JSON.stringify(false)
})
]
};
This creates two global constants, STABLE_FEATURE
and EXPERIMENTAL_FEATURE
, and makes them available in your application. To read more about the usage of the DefinePlugin
, please see the DefinePlugin’s documentation.
Implement the Angular Application
To make it easier to create a clean responsive layout, install Bootstrap and its Angular components. In your terminal run the command below.
xxxxxxxxxx
ng add ngx-bootstrap@5.2.0
Now start your favorite IDE and open the file src/styles.css.html
. Add the following line to include the stylesheet for the bootstrap library.
xxxxxxxxxx
@import "~bootstrap/dist/css/bootstrap.css";
Open src/app/app.component.html
and replace the default content with the following.
xxxxxxxxxx
<nav class="navbar navbar-expand navbar-light bg-light">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" [routerLink]="['']">
Home
</a>
</li>
<li class="nav-item">
<a class="nav-link" [routerLink]="['demo']">
Demo
</a>
</li>
</ul>
</nav>
<router-outlet></router-outlet>
The router-outlet
element serves as the container for the router. This means that different components can be loaded into this placeholder by changing the URL in the browser’s navigation bar. Create two components to be placed into the router-outlet
and call them Home
and Demo
. Open the terminal again and run the following commands.
xxxxxxxxxx
ng generate component home
ng generate component demo
Now open src/app/app-routing.module.ts
and add routes for these components.
xxxxxxxxxx
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { DemoComponent } from './demo/demo.component';
const routes: Routes = [
{
path: '',
component: HomeComponent
},
{
path: 'demo',
component: DemoComponent,
},];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
Next, place some content into the home page. Open src/app/home/home.component.html
and replace the default content with the following code.
xxxxxxxxxx
<div class="container">
<div class="row mt-5">
<div class="col-sm">
<h1>Angular Webpack Demo</h1>
</div>
</div>
</div>
The DemoComponent
will display content depending on the feature flags that you defined in the webpack configuration. Open src/app/demo/demo.component.ts
and paste the following code into it.
xxxxxxxxxx
import { Component, OnInit } from '@angular/core';
declare const STABLE_FEATURE: boolean;
declare const EXPERIMENTAL_FEATURE: boolean;
@Component({
selector: 'app-demo',
templateUrl: './demo.component.html',
styleUrls: ['./demo.component.css']
})
export class DemoComponent implements OnInit {
stableFeature: string;
experimentalFeature: string;
constructor() { }
ngOnInit() {
this.stableFeature = STABLE_FEATURE ? 'Stable feature enabled' : 'Stable feature disabled';
this.experimentalFeature = EXPERIMENTAL_FEATURE ? 'Experimental feature enabled' : 'Experimental feature disabled';
}
}
Note the declarations of STABLE_FEATURE
and EXPERIMENTAL_FEATURE
at the top of the file. These are needed for TypeScript to know that the two constants exist. But also notice that no values are assigned here.
Next, open src/app/demo/demo.component.html
and replace the contents with the following lines.
xxxxxxxxxx
<div class="container">
<div class="row mt-5">
<div class="col-sm col-md-8 offset-md-2">
<h2>Demo Features</h2>
<p>
{{stableFeature}}
</p>
<p>
{{experimentalFeature}}
</p>
</div>
</div>
</div>
Add Angular Authentication
Almost every web application will need some sort of user authentication. Using the Okta Angular SDK it is really easy to add state of the art single sign-on authentication to any Angular app.
To get started, sign up for an Okta developer account, if you don’t already have one. Open your browser and navigate to https://developer.okta.com. Follow the Sign-Up link and fill in the registration form. When you have completed the registration you will be taken to your Okta dashboard.
To register a new application with Okta, select the Applications tab at the top and then click on the Add Application button. You will be taken to a configuration screen where you can modify the settings for your application.
To make Okta work with the development server of your Angular application, you have to make two modifications in these settings. First, change the base URI to http://localhost:4200/
. Then set the Login Redirect URI to http://localhost:4200/implicit/callback
. Select Authorization Code as a grant type and click the Done button. You will see the settings overview together with a generated client ID.
Open the terminal in your application directory and add the Okta package to your Angular application by running the command below.
xxxxxxxxxx
npm install -E @okta/okta-angular@1.2.2
Now open src/app/app.module.ts
and add the import of the Okta authentication module to the top of the file.
xxxxxxxxxx
import { OktaAuthModule } from '@okta/okta-angular';
Further down in the same file, add the authentication module to the imports
array.
xxxxxxxxxx
OktaAuthModule.initAuth({
issuer: 'https://{yourOktaDomain}/oauth2/default',
redirectUri: 'http://localhost:4200/implicit/callback',
clientId: '{yourClientId}',
pkce: true
})
In this piece of code, {yourOktaDomain}
is your Okta domain. This can be found on the top right of your Okta dashboard with the label Org URL. The value of {yourClientId}
can be copied from the settings page of the application as described above.
Next, open src/app/app.component.ts
and replace the contents with the following code.
xxxxxxxxxx
import { Component } from '@angular/core';
import { OktaAuthService } from '@okta/okta-angular';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'angular-webpack-demo';
isAuthenticated: boolean;
constructor(public oktaAuth: OktaAuthService) {
this.oktaAuth.$authenticationState.subscribe(
(isAuthenticated: boolean) => this.isAuthenticated = isAuthenticated
);
}
ngOnInit() {
this.oktaAuth.isAuthenticated().then((auth) => {this.isAuthenticated = auth});
}
login() {
this.oktaAuth.loginRedirect();
}
logout() {
this.oktaAuth.logout('/');
}
}
This adds a flag isAuthenticated
to the application component that tracks the authentication status of the user. The component also contains two callbacks for logging the user in and out. Now open src/app/app.component.html
and add the login and logout buttons by pasting the code below at the end inside the <nav>
element.
xxxxxxxxxx
<span>
<button class="btn btn-primary" *ngIf="!isAuthenticated" (click)="login()"> Login </button>
<button class="btn btn-primary" *ngIf="isAuthenticated" (click)="logout()"> Logout </button>
</span>
Open src/app/app-routing.module.ts
again and add the import of the Okta callback component and the auth guard to the top of the file.
xxxxxxxxxx
import { OktaCallbackComponent, OktaAuthGuard } from '@okta/okta-angular';
Next, register the callback component to the implicit/callback
route by adding the following entry to the routes
array.
xxxxxxxxxx
{
path: 'implicit/callback',
component: OktaCallbackComponent
}
Finally, add the route guard to route entry for the demo component.
xxxxxxxxxx
{
path: 'demo',
component: DemoComponent,
canActivate: [OktaAuthGuard]
}
Well done! You have completed the implementation of an Angular application with a custom webpack configuration. You can try out the application by opening the terminal again and running the following command.
xxxxxxxxxx
ng serve
Open your browser and navigate to http://localhost:4200/
and you will see your application. If you click on the Demo link at the top, you should be prompted to log in. After successfully signing on with the Okta service, you should see something like this.
Learn More about Angular and Webpack
In this tutorial, I have shown you how to create a simple Angular web application with a custom webpack configuration. Starting with Angular 8, access to the internal webpack configuration has been restricted. It is still possible, however, to extend the configuration object with a custom configuration. This allows you to register custom loaders or additional webpack plugins. In the example presented here, I demonstrated how to use the DefinePlugin
to define global constants through the configuration. This might be useful for feature flagging parts of your application.
As always, you can find the source code for this tutorial on GitHub in the oktadeveloper/okta-angular-webpack-example.
If you want to learn more about Webpack, Angular, and authentication, check out the links below.
- Build a Basic CRUD App with Angular and Node
- Use Angular Schematics to Simplify Your Life
- Build Secure Login for Your Angular App
- Angular 8 + Spring Boot 2.2: Build a CRUD App Today!
- Build a Desktop Application with Angular and Electron
If you have any questions about this post, please add a comment below. For more high-tech content, follow @oktadev on Twitter, or subscribe to our YouTube channel!
How to Customize Your Angular Build With Webpack was originally published on the Okta Developer Blog on December 9, 2019.
Published at DZone with permission of Holger Schmitz, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments