{{announcement.body}}
{{announcement.title}}

Personalize Your Angular Build With Webpack

DZone 's Guide to

Personalize Your Angular Build With Webpack

In this article, we discuss how to personalize your Angular build with Webpack to better manage node modules.

· Web Dev Zone ·
Free Resource

If 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.

Shell




x


 
1
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.

Shell




xxxxxxxxxx
1


 
1
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.

Shell




xxxxxxxxxx
1


 
1
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.

JSON




xxxxxxxxxx
1


 
1
"builder": "@angular-builders/custom-webpack:browser",



Now, inside architect.build.options add the following property.

JSON




xxxxxxxxxx
1


 
1
"customWebpackConfig": {
2
  "path": "./custom-webpack.config.js"
3
},



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.

JSON




xxxxxxxxxx
1


 
1
"builder": "@angular-builders/custom-webpack:dev-server",



Now create the file custom-webpack.config.js and paste the following content into it.

JavaScript




xxxxxxxxxx
1
10


 
1
const webpack = require('webpack');
2
 
          
3
module.exports = {
4
  plugins: [
5
    new webpack.DefinePlugin({
6
      'STABLE_FEATURE': JSON.stringify(true),
7
      'EXPERIMENTAL_FEATURE': JSON.stringify(false)
8
    })
9
  ]
10
};



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.

Shell




xxxxxxxxxx
1


 
1
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.

CSS




xxxxxxxxxx
1


 
1
@import "~bootstrap/dist/css/bootstrap.css";



Open src/app/app.component.html and replace the default content with the following.

HTML




xxxxxxxxxx
1
15


 
1
<nav class="navbar navbar-expand navbar-light bg-light">
2
  <ul class="navbar-nav mr-auto">
3
    <li class="nav-item">
4
      <a class="nav-link" [routerLink]="['']">
5
        Home
6
      </a>
7
    </li>
8
    <li class="nav-item">
9
      <a class="nav-link" [routerLink]="['demo']">
10
        Demo
11
      </a>
12
    </li>
13
  </ul>
14
</nav>
15
<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.

Shell




xxxxxxxxxx
1


 
1
ng generate component home
2
ng generate component demo



Now open src/app/app-routing.module.ts and add routes for these components.

TypeScript




xxxxxxxxxx
1
20


 
1
import { NgModule } from '@angular/core';
2
import { Routes, RouterModule } from '@angular/router';
3
import { HomeComponent } from './home/home.component';
4
import { DemoComponent } from './demo/demo.component';
5
 
          
6
const routes: Routes = [
7
  {
8
    path: '',
9
    component: HomeComponent
10
  },
11
  {
12
    path: 'demo',
13
    component: DemoComponent,
14
  },];
15
 
          
16
@NgModule({
17
  imports: [RouterModule.forRoot(routes)],
18
  exports: [RouterModule]
19
})
20
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.

HTML




xxxxxxxxxx
1


 
1
<div class="container">
2
  <div class="row mt-5">
3
    <div class="col-sm">
4
      <h1>Angular Webpack Demo</h1>
5
    </div>
6
  </div>
7
</div>
8
 
          



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.

TypeScript




xxxxxxxxxx
1
21


 
1
import { Component, OnInit } from '@angular/core';
2
 
          
3
declare const STABLE_FEATURE: boolean;
4
declare const EXPERIMENTAL_FEATURE: boolean;
5
 
          
6
@Component({
7
  selector: 'app-demo',
8
  templateUrl: './demo.component.html',
9
  styleUrls: ['./demo.component.css']
10
})
11
export class DemoComponent implements OnInit {
12
  stableFeature: string;
13
  experimentalFeature: string;
14
 
          
15
  constructor() { }
16
 
          
17
  ngOnInit() {
18
    this.stableFeature = STABLE_FEATURE ? 'Stable feature enabled' : 'Stable feature disabled';
19
    this.experimentalFeature = EXPERIMENTAL_FEATURE ? 'Experimental feature enabled' : 'Experimental feature disabled';
20
  }
21
}



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.

HTML




xxxxxxxxxx
1
13


 
1
<div class="container">
2
  <div class="row mt-5">
3
    <div class="col-sm col-md-8 offset-md-2">
4
      <h2>Demo Features</h2>
5
      <p>
6
        {{stableFeature}}
7
      </p>
8
      <p>
9
        {{experimentalFeature}}
10
      </p>
11
    </div>
12
  </div>
13
</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.

Spreadsheet




xxxxxxxxxx
1


 
1
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.

TypeScript




xxxxxxxxxx
1


 
1
import { OktaAuthModule } from '@okta/okta-angular';



Further down in the same file, add the authentication module to the imports array.

TypeScript




xxxxxxxxxx
1


 
1
OktaAuthModule.initAuth({
2
  issuer: 'https://{yourOktaDomain}/oauth2/default',
3
  redirectUri: 'http://localhost:4200/implicit/callback',
4
  clientId: '{yourClientId}',
5
  pkce: true
6
})



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.

TypeScript




xxxxxxxxxx
1
30


 
1
import { Component } from '@angular/core';
2
import { OktaAuthService } from '@okta/okta-angular';
3
 
          
4
@Component({
5
  selector: 'app-root',
6
  templateUrl: './app.component.html',
7
  styleUrls: ['./app.component.css']
8
})
9
export class AppComponent {
10
  title = 'angular-webpack-demo';
11
  isAuthenticated: boolean;
12
 
          
13
  constructor(public oktaAuth: OktaAuthService) {
14
    this.oktaAuth.$authenticationState.subscribe(
15
      (isAuthenticated: boolean)  => this.isAuthenticated = isAuthenticated
16
    );
17
  }
18
 
          
19
  ngOnInit() {
20
    this.oktaAuth.isAuthenticated().then((auth) => {this.isAuthenticated = auth});
21
  }
22
 
          
23
  login() {
24
    this.oktaAuth.loginRedirect();
25
  }
26
 
          
27
  logout() {
28
    this.oktaAuth.logout('/');
29
  }
30
}



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.

HTML




xxxxxxxxxx
1


 
1
<span>
2
  <button class="btn btn-primary" *ngIf="!isAuthenticated" (click)="login()"> Login </button>
3
  <button class="btn btn-primary" *ngIf="isAuthenticated" (click)="logout()"> Logout </button>
4
</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.

TypeScript




xxxxxxxxxx
1


 
1
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.

TypeScript




xxxxxxxxxx
1


 
1
{
2
  path: 'implicit/callback',
3
  component: OktaCallbackComponent
4
}



Finally, add the route guard to route entry for the demo component.

TypeScript




xxxxxxxxxx
1


 
1
{
2
  path: 'demo',
3
  component: DemoComponent,
4
  canActivate: [OktaAuthGuard]
5
}



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.

Shell




xxxxxxxxxx
1


 
1
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.

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. 


Topics:
angular ,webpack ,typescript ,javascript ,tutorial ,authentication

Published at DZone with permission of Holger Schmitz . See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}