Skip to content
This repository has been archived by the owner on Mar 20, 2024. It is now read-only.

Upgrading Angular Bazel build to Angular 6.2.1

Greg Magolan edited this page Aug 10, 2018 · 6 revisions

Building Angular with Bazel was broken at version 6.0.5 due to a change in the @angular/router package (https://github.com/angular/angular/issues/24521). As of Angular 6.2.1, Angular can be built with Bazel again. This guide is meant to help you update your Bazel build configuration to work with Angular 6.2.1.

Building Angular from source

The build configuration for building and Angular project with Bazel has changed as of 6.2.1. Angular is now built from source with Bazel. This is a temporary solution that is required with the current generation Angular compiler and in the future it should be possible to use the Angular npm distribution with Bazel once Ivy is released.

Upgrading

Upgrading your Angular Bazel build to Angular 6.2.1+ requires a few changes to your WORKSPACE and Bazel BUILD files. https://github.com/alexeagle/angular-bazel-example/pull/160 shows these changes as applied to the canonical angular-bazel-example.

Update to rules_nodejs 0.11.3 or newer

Make sure that your build_bazel_rules_nodejs version in your WORKSPACE file is 0.11.3 or newer:

http_archive(
    name = "build_bazel_rules_nodejs",
    urls = ["https://github.com/bazelbuild/rules_nodejs/archive/0.11.3.zip"],
    strip_prefix = "rules_nodejs-0.11.3",
    sha256 = "e8842fa5f5e38f2c826167ff94323d4b5aabd13217cee867d971d6f860cfd730"
)

Update to rules_typescript 0.16.0 or newer

The recommended way to fetch build_bazel_rules_typescript is from the npm distribution. Add "@bazel/typescript": "0.16.0" to your devDependencies in your package.json or run yarn add @bazel/typescript --dev. This approach will ensure that npm dependencies of @bazel/typescript are installed in your node_modules. Alternately, you can fetch build_bazel_rules_typescript using http_archive in your WORKSPACE file and add its dependencies to your package.json manually.

If you fetch the @bazel/typescript npm package, you will also need to add the following to your WORKSPACE file:

local_repository(
    name = "build_bazel_rules_typescript",
    path = "node_modules/@bazel/typescript",
)

This lets Bazel know where to find the build_bazel_rules_typescript repository in your node_modules.

You should also add "@build_bazel_rules_typescript//:node_modules" to the srcs array of the //:node_modules filegroup definition in your root BUILD.bazel file:

filegroup(
    name = "node_modules",
    srcs = glob([ ... ]) + ["@build_bazel_rules_typescript//:node_modules"],
    # "@build_bazel_rules_typescript//:node_modules" is incluced
    # in `//:node_modules` so that npm dependencies that are hoisted to
    # node_modules/@bazel/typescript/node_modules because of conflicting
    # versions can be resolved correctly
)

This will ensure that if your project has conflicting npm dependencies with @bazel/typescript such as the protobufjs dependency, Bazel will be able to resolve the @bazel/typescript dependencies correctly.

build_bazel_rules_typescript 0.16.0 now sets a default value for the tsconfig attribute of ts_library and ng_module. The default value is //:tsconfig.json. If your tsconfig.json file is in your root folder then you don't need to change anything except ensure that you add it to export_files in your root BUILD.bazel file (e.g. exports_files([tsconfig.json])). If the tsconfig.json file is in another folder you can add an alias to your root BUILD.bazel file as is done in angular-bazel-example:

# ts_library and ng_module use the `//:tsconfig.json` target
# by default. This alias allows omitting explicit tsconfig
# attribute.
alias(
    name = "tsconfig.json",
    actual = "//src:tsconfig.json",
)

Fetch bazel_gazelle and io_bazel_skydoc in your WORKSPACE file

Make sure you fetch bazel_gazelle and io_bazel_skydoc in your WORKSPACE file. These are new transitive dependencies of build_bazel_rules_typescript that must be included since Bazel does not automatically fetch transitive dependencies for you.

http_archive(
    name = "bazel_gazelle",
    urls = ["https://github.com/bazelbuild/bazel-gazelle/releases/download/0.13.0/bazel-gazelle-0.13.0.tar.gz"],
    sha256 = "bc653d3e058964a5a26dcad02b6c72d7d63e6bb88d94704990b908a1445b8758",
)

http_archive(
    name = "io_bazel_skydoc",
    urls = ["https://github.com/bazelbuild/skydoc/archive/0ef7695c9d70084946a3e99b89ad5a99ede79580.zip"],
    strip_prefix = "skydoc-0ef7695c9d70084946a3e99b89ad5a99ede79580",
    sha256 = "491f9e142b870b18a0ec8eb3d66636eeceabe5f0c73025706c86f91a1a2acb4d",
)

Fetch Angular in your WORKSPACE file

Angular is now pulled down as an external Bazel repository named @angular in your WORKSPACE file so that it can be built from source:

http_archive(
    name = "angular",
    url = "https://github.com/angular/angular/archive/6.1.2.zip",
    strip_prefix = "angular-6.1.2",
    sha256 = "e7553542cebd1113069a92d97a464a2d2aa412242926686653b8cf0101935617",
)

If the version is newer than 6.1.2 than you'll have to either update the sha256 or you can remove that attribute as it is optional.

Don't forget to call ng_setup_workspace() in your WORKSPACE file as well:

load("@angular//:index.bzl", "ng_setup_workspace")

ng_setup_workspace()

Remove @angular from your package.json

Remove all @angular/* packages from your package.json. The exception to this is if you need ngc to run an npm postinstall step to create generated files such as node_modules/@ngrx/store/store.ngsummary.json for 3rd party libraries.

If your npm postinstall step was only being run on node_modules/@angular/**/* then you can remove that step as it is no longer necessary. If you need to run postinstall on 3rd party libraries such as @ngrx as is done in angular-bazel-example, then you'll still need to keep the following three @angular packages as devDependencies in your package.json:

"@angular/compiler": "6.1.2",
"@angular/compiler-cli": "6.1.2",
"@angular/core": "6.1.2",

and run ngc on 3rd party libraries in your npm postinstall step. See postinstall.tsconfig.json in angular-bazel-example for how this is done for @ngrx.

Add tslib to package.json and to the main entry point

You'll need to add "tslib": "1.9.3" as a dependency to your project. Previously, tslib was automatically included in the angular npm distribution bundles. When building Angular from source we need to include it manually.

For the time being, you'll also need to explicitly import tslib at the main entry point of your application. In angular-bazel-example, this is done in main.ts:

// `tslib` must be imported explicitly into the application
// when building angular from source using bazel
// TODO(gmagolan): Remove this import once it is no longer needed.
// See https://github.com/bazelbuild/rules_typescript/issues/252
import 'tslib';

import {platformBrowser} from '@angular/platform-browser';
import {AppModuleNgFactory} from './app.module.ngfactory';

platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);

Update to typescript 2.9.1 and tsickle 0.32.1

You'll need to update your typescript version to a minimum of 2.9.1 and also add tsickle 0.32.1 as a devDependency:

"tsickle": "0.32.1",
"typescript": "2.9.1",

Add @angular targets to the deps of ng_module targets

With Angular built from source with Bazel, you'll need to add the Angular packages used in each of your ng_module targets to their deps. For example, the //src/hello-world:hello-world ng_module target in angular-bazel-example depends on @angular//packages/core and @angular//packages/forms:

ng_module(
    name = "hello-world",
    srcs = [
        "hello-world.component.ts",
        "hello-world.module.ts",
    ],
    assets = [
        ":hello-world.component.html",
        ":hello-world-styles",
    ],
    deps = [
        "//src/lib",
        "@angular//packages/core",
        "@angular//packages/forms",
        "@rxjs",
    ],
)

Update your ts_devserver target

If you're not using the ts_devserver rule you can ignore this step.

Remove the "//:angular_bundles" filegroup from your ts_devserver rule since Angular is now built from source. You'll need to add tslib to your ts_devserver by adding "angular_bazel_example/node_modules/tslib" to additional_root_paths and "//:node_modules/tslib/tslib.js" to static_files.

As an example, the //src:devserver target in angular-bazel-example now looks like this:

ts_devserver(
    name = "devserver",
    additional_root_paths = [
        "angular_bazel_example/node_modules/zone.js/dist",
        "angular_bazel_example/node_modules/tslib",
        "angular_bazel_example/node_modules/@ngrx/store/bundles",
    ],
    entry_module = "angular_bazel_example/src/main",
    scripts = [
        ":require.config.js",
    ],
    serving_path = "/bundle.min.js",
    static_files = [
        "//:node_modules/zone.js/dist/zone.min.js",
        "//:node_modules/tslib/tslib.js",
        "//:node_modules/@ngrx/store/bundles/store.umd.min.js",
        "index.html",
    ],
    deps = ["//src"],
)

Update your ts_web_test_suite targets

If you're not using the ts_web_test_suite rule you can ignore this step.

Remove the "//:angular_bundles" and "//:angular_test_bundles" filegroups from your ts_web_test_suite rules. You'll need to add "//:node_modules/tslib/tslib.js" to srcs and "//:node_modules/reflect-metadata/Reflect.js" to bootstrap.

As an example, the //src/hello-world:test target in angular-bazel-example now looks like this:

ts_web_test_suite(
    name = "test",
    srcs = ["//:node_modules/tslib/tslib.js"],
    # do not sort
    bootstrap = [
        "//:node_modules/zone.js/dist/zone-testing-bundle.js",
        "//:node_modules/reflect-metadata/Reflect.js",
    ],
    browsers = [
        "@io_bazel_rules_webtesting//browsers:chromium-local",
        "@io_bazel_rules_webtesting//browsers:firefox-local",
    ],
    deps = [
        ":test_lib",
    ],
)

Other issues

The above covers the key upgrading steps above. If you run into issues that this guide or https://github.com/alexeagle/angular-bazel-example/pull/160 don't cover, please file an issue to https://github.com/alexeagle/angular-bazel-example.

Clone this wiki locally