Day11 Challenge: Set Up and Optimize an Angular Project Using Bazel

·

4 min read

Objective:

Your goal is to set up a new Angular project using Bazel as the build tool and optimize its build performance for large-scale applications. You’ll configure Bazel, structure the project correctly, and demonstrate performance improvements by running builds in development and production modes.


Step 1: Set Up Bazel in an Angular Project

  1. Create a new Angular project:
    Start by creating a new Angular project using Angular CLI if you don’t have one already. If you already have an Angular project, skip to Step 2.

     ng new bazel-angular-challenge --routing --style=scss
     cd bazel-angular-challenge
    
  2. Install Bazel:
    Install the required Bazel dependencies and tools to integrate Bazel into your Angular project.

    • Add Bazel to your Angular project:

        ng add @angular/bazel
      
    • Install necessary Bazel dependencies:

        yarn add @bazel/bazel @angular/bazel
      
    • This will generate Bazel build files and configurations like BUILD.bazel, .bazelrc, and angular.json.


Step 2: Create and Configure Bazel Files

  1. Configure BUILD.bazel files:
    In Bazel, you use BUILD.bazel files to define build targets. Here, you’ll configure Bazel to build Angular applications.

    • In your project root, open or create a BUILD.bazel file.

    • Add configurations for building Angular apps:

        load("@npm//@angular/bazel", "ng_module", "ng_package")
      
        ng_module(
            name = "app",
            srcs = glob(["src/**/*.ts"]),
            deps = [
                "@npm//@angular/core",
                "@npm//@angular/common",
                "@npm//@angular/router",
            ],
        )
      
        ng_package(
            name = "app_package",
            srcs = glob(["src/**/*"]),
            deps = [":app"],
        )
      
    • This configuration ensures that Bazel can build the Angular application (ng_module) and package it (ng_package).

  2. Bazel Build Configurations:
    You’ll also need to modify or add to your .bazelrc file to customize build parameters for Bazel’s build strategy.

    Example .bazelrc configurations:

     build --experimental_action_listener=@bazel_tools//tools/jdk:default_java_toolchain
     build --output_groups=debug
     build --experimental_convenience_symlinks=ignore
    

Step 3: Integrating Angular’s Development Server

  1. Set up an Angular development server using Bazel:
    In a typical Angular project, you might use ng serve. With Bazel, the process is slightly different.

    • Install the Angular development server dependency for Bazel:

        yarn add @angular/bazel-build-angular
      
    • Update your angular.json to add a build target for Bazel.

      Example configuration:

        "projects": {
          "bazel-angular-challenge": {
            "architect": {
              "build": {
                "builder": "@angular/bazel:browser",
                "options": {
                  "outputPath": "dist/",
                  "sourceMap": true
                }
              },
              "serve": {
                "builder": "@angular/bazel:devserver",
                "options": {
                  "browserTarget": "bazel-angular-challenge:build"
                }
              }
            }
          }
        }
      
  2. Run the Angular project:
    Now you should be able to build and serve the application using Bazel.

    • To build the application:

        bazel build //src:app
      
    • To serve the application:

        bazel run //src:devserver
      

This command starts a development server for the Angular app using Bazel.


Step 4: Optimize Angular Build Performance with Bazel

  1. Optimize Build with Incremental Builds:
    Bazel’s main selling point is its caching and incremental builds. To fully take advantage of this, start building parts of your app incrementally:

    • Bazel builds only what has changed since the last build, which can speed up the process, especially with large applications.

    • Test incremental builds by changing files and running the build command multiple times. You should see faster builds for unchanged parts of the application.

  2. Using --experimental_aggregate_files:
    Bazel offers flags to optimize file aggregations during builds. By enabling --experimental_aggregate_files, you can speed up file processing in larger Angular applications.

    Example:

     bazel build --experimental_aggregate_files //src:app
    
  3. Parallel Builds and Caching:

    • Use the --jobs flag to run Bazel with parallel jobs for faster builds:

        bazel build --jobs=4 //src:app
      
    • You can also enable remote caching for Bazel to cache builds across different machines, speeding up builds for large teams or CI/CD pipelines.


Step 5: Bonus - Using Bazel with Angular Libraries

  1. Set up Angular Libraries with Bazel:
    You can also use Bazel to build Angular libraries for a modular and scalable architecture.

    • Create a BUILD.bazel file for the library:

        load("@npm//@angular/bazel", "ng_module")
      
        ng_module(
            name = "shared-lib",
            srcs = glob(["src/lib/**/*.ts"]),
            deps = [
                "@npm//@angular/core",
                "@npm//@angular/common",
            ],
        )
      
    • Import the library into your main Angular app using Bazel’s module system, ensuring that it is properly built and optimized.


Step 6: Deploying the Angular App with Bazel

  1. Configure Deployment for Production:
    Use Bazel’s ng_build target for production optimization. You can set up a production build by tweaking the angular.json and .bazelrc to enable optimizations such as minification and tree shaking.

    Example:

    bazel build --config=production //src:app
    

    This builds a production-ready application using the best optimizations available in Bazel and Angular.


Challenge Results & Expected Outcomes:

  • Bazel Integration: You’ve successfully set up an Angular project using Bazel and configured it for building and serving Angular applications.

  • Performance Gains: You’ve optimized the Angular build using Bazel’s caching, parallel execution, and incremental build features, leading to faster build times.

  • Modularization: You’ve created Angular libraries with Bazel, enabling more maintainable and scalable applications.

  • Production Optimization: You’ve configured production builds with Bazel for optimized and efficient output.


Bonus Challenge: CI/CD Integration with Bazel

  • Integrate Bazel with your continuous integration pipeline (e.g., GitHub Actions, Jenkins, or CircleCI). Use Bazel’s incremental builds and caching features in your CI/CD setup to speed up build and test times for large Angular projects.

This challenge gives you a comprehensive understanding of Bazel’s integration with Angular and how you can leverage it to optimize your development workflow, build performance, and project scalability.