Skip to content

Commit 9072ddb

Browse files
committed
feat(examples): the Angular example now lives in rules_nodejs
angular-bazel-example repo is now archived This will help our team triage issues and keep things up-to-date as we won't need to remember about another repository
1 parent c376355 commit 9072ddb

5 files changed

Lines changed: 283 additions & 0 deletions

File tree

commitlint.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ module.exports = {
1010
'buildozer',
1111
'builtin',
1212
'create',
13+
'examples',
1314
'hide-bazel-files',
1415
'jasmine',
1516
'karma',

examples/angular/.firebaserc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"projects": {
3+
"default": "bazel-angular-io"
4+
}
5+
}

examples/angular/README.md

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
[![CircleCI](https://circleci.com/gh/angular/angular-bazel-example.svg?style=svg)](https://circleci.com/gh/angular/angular-bazel-example)
2+
3+
# Example Angular monorepo using Bazel
4+
5+
**This is experimental, as part of Angular Labs! There may be breaking changes.**
6+
7+
This is part of the ABC project. The overall goal is to make it possible to
8+
develop Angular applications the same way we do at Google.
9+
10+
Learn more about Bazel and Angular at https://bazel.angular.io
11+
12+
This example is deployed at https://bazel.angular.io/example
13+
14+
## Guide to the example
15+
16+
This example is a monorepo, meant to show many different features and integrations that we expect are generally useful for enterprise use cases.
17+
18+
- **Angular CLI**: you can use the `ng` command to run build, serve, test, and e2e
19+
- **Angular Libraries**: to maximize build incrementality, each Angular module is compiled as a separate step. This lets us re-use Angular libraries without having to publish them as npm packages. See `src/todos` for a typical `NgModule` compiled as a library for use in the application, using the `ng_module` rule in the `BUILD.bazel` file.
20+
- **TypeScript Libraries**: see `src/lib` for a trivial example of a pure-TS library that's consumed in the application, using the `ts_library` rule in the `BUILD.bazel` file.
21+
- **Sass**: we use Sass for all styling. Angular components import Sass files, and these are built by Bazel as independent processes calling the modern Sass compiler (written in Dart).
22+
- **Material design**: see `src/material` where we collect the material modules we use.
23+
- **Redux-style state management**: see `src/reducers` where we use the [NgRx Store](https://ngrx.io/guide/store).
24+
- **Lazy loading**: in production mode, the application is served in chunks. Run `ng serve --prod`
25+
- **Differential loading**: in production mode, we load a pair of `<script>` tags. Modern browsers will load code in the ES2015 syntax, which is smaller and requires fewer polyfills. Older browsers will load ES5 syntax.
26+
- **Docker**: see below where we package up the production app for deployment on Kubernetes.
27+
28+
## Installation
29+
30+
You only need to install one build tool, and which one you choose typically depends on what kind of development you do most often.
31+
32+
If you're a frontend developer, you should install NodeJS and yarn.
33+
The `package.json` file has an `engines` section which indicates the range of NodeJS and yarn versions that you could use.
34+
You simply run `yarn` commands shown below, and don't need to install Bazel or any other dependencies.
35+
36+
If you're a full-stack developer, you might be using Bazel for your backend already.
37+
In this case, you should install Bazel following instructions at http://bazel.build.
38+
Also install `ibazel`, which is a watch mode for Bazel not included in the standard distribution. See https://github.com/bazelbuild/bazel-watcher#installation.
39+
The `WORKSPACE` file has a `check_bazel_version` call which will print an error if your Bazel version is not in the supported range.
40+
You simply run `bazel` commands shown below, and don't need to install NodeJS, yarn, or any other dependencies.
41+
42+
## Development
43+
44+
First we'll run the development server:
45+
46+
```bash
47+
$ ng serve
48+
# or
49+
$ ibazel run //src:devserver
50+
```
51+
52+
This runs in "watch mode", which means it will watch any files that are inputs to the devserver, and when they change it will ask Bazel to re-build them.
53+
When the re-build is finished, it will trigger a LiveReload in the browser.
54+
55+
This command prints a URL on the terminal. Open that page to see the demo app
56+
running. Now you can edit one of the source files (`src/lib/file.ts` is an easy
57+
one to understand and see the effect). As soon as you save a change, the app
58+
should refresh in the browser with the new content. Our intent is that this time
59+
is less than two seconds, even for a large application.
60+
61+
Control-C twice to kill the devserver.
62+
63+
## Testing
64+
65+
We can also run all the unit tests:
66+
67+
```bash
68+
$ ng test
69+
# or
70+
$ bazel test //src/...
71+
```
72+
73+
Or run the end-to-end tests:
74+
75+
```bash
76+
$ ng e2e
77+
# or
78+
$ bazel test //e2e/...
79+
```
80+
81+
In this example, there is a unit test for the `hello-world` component which uses
82+
the `ts_web_test_suite` rule. There are also protractor e2e tests for both the
83+
`prodserver` and `devserver` which use the `protractor_web_test_suite` rule.
84+
85+
Note that Bazel will only re-run the tests whose inputs changed since the last run.
86+
87+
## Production
88+
89+
We can run the application in production mode, where the code has been bundled
90+
and optimized. This can be slower than the development mode, because any change
91+
requires re-optimizing the app. This example uses Rollup and Uglify, but other
92+
bundlers can be integrated with Bazel.
93+
94+
```bash
95+
$ ng serve --prod
96+
# or
97+
$ bazel run //src:prodserver
98+
```
99+
100+
### Code splitting
101+
102+
The production bundle is code split and routes such as `/` and `/todos`
103+
are lazy loaded. Code splitting is handled by the rollup_bundle rule
104+
which now supports the new code splitting feature in rollup.
105+
106+
Note: code splitting is _not_ supported in development mode yet so the
107+
`//src:devserver` target does not serve a code split bundle. The dynamic
108+
`import()` statements will resolve to modules that are served in the initial
109+
JS payload.
110+
111+
## Npm dependencies
112+
113+
Having a local `node_modules` folder setup by `yarn` or `npm` is not
114+
necessary when building this example with Bazel. This example makes use
115+
of Bazel managed npm dependencies (https://github.com/bazelbuild/rules_nodejs#using-bazel-managed-dependencies)
116+
which means Bazel will setup the npm dependencies in your `package.json` for you
117+
outside of your local workspace for use in the build.
118+
119+
However, you may still want to run `yarn` or `npm` to manually
120+
setup a local `node_modules` folder for editor and tooling support.
121+
122+
## Deployment
123+
124+
### Firebase
125+
126+
We use the standard firebase deploy command.
127+
128+
Run `yarn deploy` to release changes to bazel.angular.io.
129+
130+
### Kubernetes Engine
131+
We use Bazel's docker support to package up our production server for deployment.
132+
Each time the app changes, we'll get a slim new docker layer with just the modified files, keeping the round-trip for deployment incremental and fast.
133+
This example is configured to run on Google Kubernetes Engine, so we can have an elastic pool of backend machines behind a load balancer.
134+
This setup is more expensive to operate than something like Firebase Functions where the backend code is spun up on-demand, but is also more adaptable to scenarios like backend servers that need to run other binaries on the machine.
135+
136+
The application is currently live at http://35.197.115.230/
137+
138+
To run it under docker:
139+
140+
```
141+
$ bazel run src:nodejs_image -- --norun
142+
$ docker run --rm -p 8080:8080 bazel/src:nodejs_image
143+
```
144+
145+
Deploy to production:
146+
147+
1. Install gcloud and kubectl
148+
1. Authenticate to the Google Container Registry
149+
`gcloud auth configure-docker`
150+
1. Authenticate to Kubernetes Engine
151+
`gcloud container clusters get-credentials angular-bazel-example --zone=us-west1-a`
152+
1. For the first deployment: `bazel run :deploy.create`
153+
1. To update: `bazel run :deploy.replace`
154+
155+
Tips:
156+
157+
```
158+
# Run the binary without docker
159+
$ bazel run src:nodejs_image.binary
160+
# What's in the image?
161+
$ bazel build src:nodejs_image && file-roller dist/bin/src/nodejs_image-layer.tar
162+
# Tear down all running docker containers
163+
$ docker rm -f $(docker ps -aq)
164+
# Hop into the running image on kubernetes
165+
$ kubectl exec angular-bazel-example-prod-3285254973-ncv3g -it -- /bin/bash
166+
```

examples/angular/angular.json

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
{
2+
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3+
"version": 1,
4+
"newProjectRoot": "projects",
5+
"projects": {
6+
"angular-bazel-example": {
7+
"root": "",
8+
"sourceRoot": "src",
9+
"projectType": "application",
10+
"prefix": "app",
11+
"schematics": {
12+
"@schematics/angular:component": {
13+
"style": "scss"
14+
}
15+
},
16+
"architect": {
17+
"build": {
18+
"builder": "@angular/bazel:build",
19+
"options": {
20+
"targetLabel": "//src:prodapp",
21+
"bazelCommand": "build"
22+
}
23+
},
24+
"serve": {
25+
"builder": "@angular/bazel:build",
26+
"options": {
27+
"targetLabel": "//src:devserver",
28+
"bazelCommand": "run",
29+
"watch": true
30+
},
31+
"configurations": {
32+
"production": {
33+
"targetLabel": "//src:prodserver"
34+
}
35+
}
36+
},
37+
"extract-i18n": {
38+
"builder": "@angular-devkit/build-angular:extract-i18n",
39+
"options": {
40+
"browserTarget": "ngbazel:build"
41+
}
42+
},
43+
"test": {
44+
"builder": "@angular/bazel:build",
45+
"options": {
46+
"bazelCommand": "test",
47+
"targetLabel": "//src/app/..."
48+
}
49+
},
50+
"lint": {
51+
"builder": "@angular-devkit/build-angular:tslint",
52+
"options": {
53+
"tsConfig": [
54+
"src/tsconfig.app.json",
55+
"src/tsconfig.spec.json"
56+
],
57+
"exclude": [
58+
"**/node_modules/**"
59+
]
60+
}
61+
}
62+
}
63+
},
64+
"ngbazel-e2e": {
65+
"root": "e2e/",
66+
"projectType": "application",
67+
"prefix": "",
68+
"architect": {
69+
"e2e": {
70+
"builder": "@angular/bazel:build",
71+
"options": {
72+
"bazelCommand": "test",
73+
"targetLabel": "//e2e:devserver_test"
74+
},
75+
"configurations": {
76+
"production": {
77+
"targetLabel": "//e2e:prodserver_test"
78+
}
79+
}
80+
},
81+
"lint": {
82+
"builder": "@angular-devkit/build-angular:tslint",
83+
"options": {
84+
"tsConfig": "e2e/tsconfig.e2e.json",
85+
"exclude": [
86+
"**/node_modules/**"
87+
]
88+
}
89+
}
90+
}
91+
}
92+
},
93+
"defaultProject": "ngbazel"
94+
95+
}

examples/angular/firebase.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"hosting": {
3+
"public": "dist/bin/src/prodapp",
4+
"ignore": [
5+
"firebase.json",
6+
"**/.*",
7+
"**/node_modules/**"
8+
],
9+
"rewrites": [
10+
{
11+
"source": "/example/**",
12+
"destination": "/example/index.html"
13+
}
14+
]
15+
}
16+
}

0 commit comments

Comments
 (0)