-
Notifications
You must be signed in to change notification settings - Fork 84
Upgrading Angular Bazel build to Angular 6.2.1
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.
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 (https://github.com/angular/angular/issues/21706).
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.
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"
)
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",
)
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",
)
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 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
.
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);
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",
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",
],
)
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"],
)
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",
],
)
This guide covers the key upgrading step. If you run into issues that this guide or https://github.com/alexeagle/angular-bazel-example/pull/160 don't cover, please file issues to https://github.com/alexeagle/angular-bazel-example.