Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Integrate an Angular Application into a Monorepo with Bazel?

I've spent the last weeks building a Typescript monorepo, which can be built and deployed to Kubernetes using Bazel. But the final piece of the puzzle is integrating an Angular application in to the whole workflow, which I'm really struggling with.

The Project

 ├── WORKSPACE
 ├── BUILD.bazel
 ├── package.json
 ├── packages
 │   ├── package1
 │   ├── package2
 │   └── package3
 └── services
     ├── service1
     ├── service2
     ├── service3
+    └── angular-app
  • WORKSPACE file in the root
  • BUILD.bazel file in the root
  • only one package.json in the root
  • all packages/services are Typescript libraries
  • services depend on packages
  • every package/service has its own BUILD.bazel file

Source code

Goal

In the end I want to be able to add a k8s_object for the Angular app to the root BUILD.bazel file like this:

 load("@io_bazel_rules_k8s//k8s:objects.bzl", "k8s_objects")
 k8s_objects(
     name = "kubernetes_deployment",
     objects = [
         "//services/service1",
         "//services/service2",
         "//services/service3",
+        "//services/angular-app"
     ]
)

and it should deploy the Angular app to Kubernetes when I run bazel run :kubernets_deployment.apply. Just like the other services which already work perfectly. The deployment process involves:

  • creating source code bundles
  • creating a Docker image
  • pushing the Docker image a registry
  • applying changes to Kubernetes cluster

Challenges

  1. Add Angular Bazel dependencies to my existing WORKSPACE file
  2. Make it possible to import my local packages into my Angular source code via import { something } from '@project/package1';
  3. All NPM dependencies should be added to the root package.json instead of the one in the Angular project
  4. Integrating NgRx (my Angular app uses NgRx for state management)
  5. Integrate Angular Universal (for server-side-rendering)
  6. Integrate Angular PWA (progressive web app)
  7. Setup a local development server

What I've Tried

rules_nodejs Angular Example

I was surprised to find a working example of something that is akin to my project: https://github.com/bazelbuild/rules_nodejs/tree/master/examples/angular. But as it turned out the structure of their monorepo is somewhat different. They also use scss, which I am not and there are not integrations for NgRx or Angular Universal. So I've tried to use it a template by I just couldn't make it work.

Bazel with Angular CLI

Of course I've also tried the documented way of adding Bazel to Angular: https://angular.io/guide/bazel, which seems to work for a clean project. With ng build --leaveBazelFilesOnDisk it is event possbile to access the Bazel files. But I got errors telling me that NgRx and my local packages could not be found.


Update

I've gone through the first steps of setting everything up on a clean angular project: https://github.com/flolu/cents-ideas/tree/4d444240cbbe2f8b015c4b7c85746c473bc6842b/services/client But I get an error I am not able to resolve:

ERROR: /home/flolu/Desktop/cents-ideas/services/client/src/app/BUILD.bazel:5:1: Compiling Angular templates (Ivy - prodmode) //src/app:app failed (Exit 1)
external/npm/node_modules/@angular/router/router.d.ts:2421:22 - error NG6002: Appears in the NgModule.imports of AppRoutingModule, but could not be resolved to an NgModule class.

This likely means that the library (@angular/router) which declares RouterModule has not been processed correctly by ngcc, or is not compatible with Angular Ivy. Check if a newer version of the library is available, and update if so. Also consider checking with the library's authors to see if the library is expected to be compatible with Ivy.

2421 export declare class RouterModule {
                          ~~~~~~~~~~~~
external/npm/node_modules/@angular/router/router.d.ts:2421:22 - error NG6003: Appears in the NgModule.exports of AppRoutingModule, but could not be resolved to an NgModule, Component, Directive, or Pipe class.

This likely means that the library (@angular/router) which declares RouterModule has not been processed correctly by ngcc, or is not compatible with Angular Ivy. Check if a newer version of the library is available, and update if so. Also consider checking with the library's authors to see if the library is expected to be compatible with Ivy.

2421 export declare class RouterModule {
                          ~~~~~~~~~~~~
external/npm/node_modules/@angular/platform-browser/platform-browser.d.ts:44:22 - error NG6002: Appears in the NgModule.imports of AppModule, but could not be resolved to an NgModule class.

This likely means that the library (@angular/platform-browser) which declares BrowserModule has not been processed correctly by ngcc, or is not compatible with Angular Ivy. Check if a newer version of the library is available, and update if so. Also consider checking with the library's authors to see if the library is expected to be compatible with Ivy.

44 export declare class BrowserModule {
                        ~~~~~~~~~~~~~
src/app/app-routing.module.ts:11:14 - error NG6002: Appears in the NgModule.imports of AppModule, but itself has errors

11 export class AppRoutingModule { }
like image 342
Flo Avatar asked Feb 19 '20 20:02

Flo


1 Answers

Florian, great progress so far :)

I suggest just looking closely onto bazel-related files in that angular example and copying all needed rules / functions to your project. The files are .bazelrc, WORKSPACE, BUILD.bazel (in every subfolder), rules_docker.patch (it's applied on http_archive in WORKSPACE).

Also, several very important files in /src folder (they are used in the BUILD file): rollup.config.js, rxjs_shims.js, main.dev.ts, main.prod.ts. And there are two index.html files in the example folder: one for prod and one for dev.

Btw, this example already contains ngrx, so it may be a good fit for you, just look closely at ng_module rules in BUILD files and their deps. Just add your deps there (smth like @npm//@ngrx/store, etc).

As for Angular Universal, looks like it's not well supported by Bazel now. Here is the issue to track: https://github.com/bazelbuild/rules_nodejs/issues/1126

And as for scss, that's cool if you use simple css, then you can just insert it into assets field of ng_module and you don't need to add additional compilation steps from rules_sass (sass_binary, sass_library). Just ignore them when copying rules from the example.

On the project structure, here is my example of migration from Nx to Bazel: https://github.com/scalio/nx-bazel-starter. It's a bit outdated, so better to orient on the official one. But you may find some useful features there, i.e. how folders are structured in the Nx. Actually the idea is very similar to yours: they just call services as apps, packages as libs and share common package.json.

like image 168
Ray Avatar answered Oct 08 '22 20:10

Ray