Day12 Challenge: Optimize Angular Builds Using the Angular Build Optimizer
Objective:
Your goal is to optimize an Angular project for production using the Angular Build Optimizer. This includes setting up proper configurations, understanding the impact of tree-shaking, analyzing the build output, and improving loading performance.
Step 1: Set Up Your Angular Project
Create a new Angular project (skip if you already have an Angular project):
ng new angular-build-optimizer-challenge --routing --style=scss cd angular-build-optimizer-challenge
Install any necessary dependencies: Although the Build Optimizer is integrated into Angular by default, you may need some extra tools to analyze and optimize the build.
npm install --save-dev source-map-explorer
source-map-explorer
helps you visualize your final build, and it's useful for understanding how much code is included in your application after optimization.
Step 2: Configure Angular for Production Optimizations
Enable Angular Build Optimizer: Angular uses the Build Optimizer for production builds by default, but it's good to verify that it's enabled and functioning.
- Open
angular.json
and ensure that the production configuration has theoptimization
flag enabled under the build options:
- Open
{
"projects": {
"angular-build-optimizer-challenge": {
"architect": {
"build": {
"configurations": {
"production": {
"optimization": true, // Enable build optimizer
"sourceMap": true,
"extractCss": true,
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"budget": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
}
]
}
}
}
}
}
}
}
- The
"optimization": true
flag ensures that tree-shaking and minification are performed.
Step 3: Understand Tree-Shaking and Minification
Tree-Shaking: Tree-shaking is the process of removing unused code from your final bundle. It is a feature built into Angular’s production builds by default. Angular’s compiler and Webpack eliminate unused code from libraries, components, and services.
To demonstrate this, create a component with unused imports or services.
In
src/app/unused/unused.component.ts
:import { Component } from '@angular/core'; import { SomeUnusedService } from '../services/unused.service'; // This service is not used @Component({ selector: 'app-unused', template: `<p>Unused Component!</p>`, }) export class UnusedComponent { // Some logic that does not use the `SomeUnusedService` }
Minification: Minification is another key feature of Angular's build optimizer. When running the production build, Angular minifies the JavaScript code, removing whitespace, comments, and shortening variable names, which reduces the file size.
- To enable minification, make sure that
optimization
is set totrue
in the production build configuration, which is enabled by default.
- To enable minification, make sure that
Step 4: Build the Application for Production
Run the production build:
ng build --prod
This command builds the application for production. Angular will perform several optimizations:
Minification: Reduces the size of the JavaScript files.
Tree-shaking: Removes unused code.
AOT Compilation: Compiles Angular templates and components ahead of time, reducing the time it takes for the browser to parse the code.
Step 5: Analyze the Build Output
Use
source-map-explorer
to analyze the build output:source-map-explorer dist/angular-build-optimizer-challenge/main.*.js
This will generate a visual representation of your build, showing how much code each module takes in the final output. You should see a significant reduction in unused code if tree-shaking is working as expected.
If your bundle includes unused code (e.g., from the
UnusedComponent
or any unused imports), check whether these components or modules are correctly marked for removal by tree-shaking.If you notice that some code is still included, inspect your application for any incorrectly imported code or modules that are not tree-shakeable (e.g., dynamic imports that Angular cannot analyze statically).
Step 6: Further Optimization
Lazy Loading: One of the most effective ways to optimize large Angular apps is using lazy loading. This allows you to load feature modules on demand, rather than loading everything upfront.
Modify your
app-routing.module.ts
to use lazy loading:const routes: Routes = [ { path: '', component: HomeComponent }, { path: 'lazy', loadChildren: () => import('./lazy/lazy.module').then(m => m.LazyModule) } ];
Create a
LazyModule
and add it to the routing configuration.
Remove Unnecessary Polyfills: In production builds, Angular includes polyfills that may not be needed in all environments. Check the
src/polyfills.ts
file and comment out any unnecessary polyfills based on the browser support you need. For example:// import 'zone.js'; // Needed for Angular's change detection // import 'core-js'; // May not be needed in modern browsers
This can reduce the size of your bundle in production.
Step 7: Verify Performance Gains
Measure performance improvements: Once you’ve completed the above steps, measure the difference in file size between the development build and the production build. You can use browser developer tools or a tool like
source-map-explorer
to visualize this.Development build (
ng serve
) should have a larger file size due to unoptimized code.Production build (
ng build --prod
) should be significantly smaller due to optimizations like tree-shaking, minification, and AOT compilation.
Test performance: Use browser performance tools like Lighthouse to analyze the performance of the production build. This will help you see if the optimizations have reduced loading time and improved your app’s performance.
Run Lighthouse in Chrome DevTools:
Open Chrome DevTools (F12) → Go to the Lighthouse tab → Click Generate Report for a production build.
Look for improvements in metrics such as First Contentful Paint (FCP), Time to Interactive (TTI), and Total Blocking Time (TBT).
Bonus Challenge: Analyze Bundle Sizes
Use Webpack Bundle Analyzer: To analyze which modules contribute the most to the bundle size, you can use the
webpack-bundle-analyzer
. This tool can give you a detailed report on the size of each package and help you optimize further.Install the tool:
npm install --save-dev webpack-bundle-analyzer
Configure Webpack to run the analyzer by adding the following to
angular.json
under thebuild
options:"buildOptimizer": true, "statsJson": true
Once the build completes, use the generated
stats.json
file to generate a visualization of your app's size.
Expected Outcome:
Optimized Production Build: You’ll have successfully built an Angular app with optimizations enabled, including tree-shaking, minification, and AOT compilation.
Improved Performance: The production build should be smaller, faster to load, and more performant compared to the development build.
Lazy Loading: By lazy loading feature modules, you will improve the loading time and reduce the initial load time of your app.
Bonus (Advanced):
- Explore Differential Loading to serve different bundles to different browsers (modern vs legacy browsers) and improve load times for modern browsers.