Skip to content

Commit

Permalink
feat(example): add full pwa support
Browse files Browse the repository at this point in the history
  • Loading branch information
flolu authored and alexeagle committed Oct 17, 2020
1 parent e3698d2 commit 4d5b9c7
Show file tree
Hide file tree
Showing 23 changed files with 212 additions and 62 deletions.
2 changes: 2 additions & 0 deletions examples/angular/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ load("@k8s_deploy//:defaults.bzl", "k8s_deploy")

package(default_visibility = ["//:__subpackages__"])

exports_files(["favicon.ico"])

# ts_library uses the `//:tsconfig.json` target
# by default. This alias allows omitting explicit tsconfig
# attribute.
Expand Down
1 change: 1 addition & 0 deletions examples/angular/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ This example is a monorepo, meant to show many different features and integratio
- **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.
- **Docker**: see below where we package up the production app for deployment on Kubernetes.
- **Server Side Rendering**: with the help of Angular Universal you can render your application on the server
- **Progressive Web App**: support for service worker and the app can be installed on phones and desktops (also has 90+ Lighthouse score)

This example is deployed at https://bazel.angular.io/example

Expand Down
Binary file added examples/angular/favicon.ico
Binary file not shown.
2 changes: 2 additions & 0 deletions examples/angular/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@
"@angular/platform-browser-dynamic": "10.0.2",
"@angular/platform-server": "10.0.2",
"@angular/router": "10.0.2",
"@angular/service-worker": "10.0.2",
"@ngrx/store": "9.2.0",
"@nguniversal/express-engine": "^9.0.0",
"compression": "^1.7.4",
"date-fns": "1.30.1",
"rxjs": "6.5.3",
"systemjs": "6.1.2",
Expand Down
34 changes: 20 additions & 14 deletions examples/angular/src/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ load("@npm//history-server:index.bzl", "history_server")
load("@npm//html-insert-assets:index.bzl", "html_insert_assets")
load("//tools:angular_prerender.bzl", "ng_prerender", "ng_prerender_test")
load("//tools:angular_ts_library.bzl", "ng_ts_library")
load("//tools:ngsw_config.bzl", "ngsw_config")

package(default_visibility = ["//:__subpackages__"])

Expand Down Expand Up @@ -73,6 +74,8 @@ filegroup(
_ASSETS = [
# This label references an output of the "styles" sass_binary above.
":styles.css",
":manifest.webmanifest",
"//:favicon.ico",

# Directly reference a file that came from @angular/material npm package
"@npm//:node_modules/@angular/material/prebuilt-themes/deeppurple-amber.css",
Expand Down Expand Up @@ -244,30 +247,34 @@ pkg_web(
":inject_scripts_for_prod_hello_route_index",
":inject_scripts_for_prod_todos_route_index",
"//src/assets",
":robots.txt",
# Service worker
"@npm//:node_modules/@angular/service-worker/ngsw-worker.js",
# Include polyfills that will be requested by old browsers
"@npm//:node_modules/systemjs/dist/system.js",
"@npm//:node_modules/core-js/client/core.min.js",
"index.html",
# NOW needed ?"index.html",
],
# In production mode we serve some polyfills with script tags that have hard-coded paths in the index.html
# so we must serve them at that path, by stripping a prefix
additional_root_paths = [
"npm/node_modules/core-js/client",
"npm/node_modules/systemjs/dist",
"npm/node_modules/@angular/service-worker",
],
)

ngsw_config(
name = "pwa",
src = ":prodapp",
config = "//src:ngsw-config.json",
index_html = ":inject_scripts_for_prod",
)

history_server(
name = "prodserver",
data = [":prodapp"],
# '-a src/prodapp' will ask history-server to scan for all apps under the
# given folder this will result in the following auto-configuration:
# /example => src/prodapp/example
# / => src/prodapp
templated_args = [
"-a",
"$$(rlocation $(rootpath :prodapp))",
],
data = [":pwa"],
templated_args = ["-a $$(rlocation $(rootpath :pwa))"],
)

nodejs_image(
Expand All @@ -288,21 +295,20 @@ container_image(

ts_library(
name = "universal_server_lib",
srcs = [
"server.ts",
],
srcs = ["server.ts"],
deps = [
"//src/app:app_server",
"@npm//@nguniversal/express-engine",
"@npm//@types/node",
"@npm//compression",
"@npm//express",
],
)

nodejs_binary(
name = "universal_server",
data = [
":prodapp",
":pwa",
":universal_server_lib",
],
entry_point = ":server.ts",
Expand Down
1 change: 1 addition & 0 deletions examples/angular/src/app/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ ng_ts_library(
"@npm//@angular/core",
"@npm//@angular/platform-browser",
"@npm//@angular/router",
"@npm//@angular/service-worker",
"@npm//@ngrx/store",
],
)
Expand Down
4 changes: 3 additions & 1 deletion examples/angular/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {StoreModule} from '@ngrx/store';
import { ServiceWorkerModule } from '@angular/service-worker';

import {MaterialModule} from '../shared/material/material.module';

Expand All @@ -16,7 +17,8 @@ import {todoReducer} from './todos/reducers/reducers';
imports: [
AppRoutingModule, BrowserModule, BrowserAnimationsModule, MaterialModule, HomeModule,
StoreModule.forRoot({todoReducer}),
BrowserModule.withServerTransition({ appId: 'angular-bazel-example' })
BrowserModule.withServerTransition({ appId: 'angular-bazel-example' }),
ServiceWorkerModule.register('ngsw-worker.js')
],
exports: [AppComponent],
bootstrap: [AppComponent],
Expand Down
2 changes: 1 addition & 1 deletion examples/angular/src/assets/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ filegroup(
name = "assets",
srcs = glob([
"*.svg",
"*.png",
"**/*.png",
"*.css",
]),
)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/angular/src/assets/icons/icon-72x72.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/angular/src/assets/icons/icon-96x96.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 16 additions & 7 deletions examples/angular/src/example/index.prod.html
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
<!doctype html>

<html>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Angular Bazel Example</title>
<base href="/example">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<base href="/example" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link
rel="stylesheet"
href="https://fonts.googleapis.com/icon?family=Material+Icons"
/>
<meta
name="description"
content="This is an example of building an Angular app at scale. It uses BUILD.bazel files to customize the configuration of Bazel. This means the application is compiled in many small libraries, giving us incremental builds"
/>
<meta name="theme-color" content="#43a047" />
<link rel="manifest" href="/manifest.webmanifest" />
<link rel="dns-prefetch" href="https://bazel.build/" />
</head>
<body>
<!-- The Angular application will be bootstrapped into this element. -->
Expand All @@ -18,6 +27,6 @@
<!-- TODO: figure out how diff. loading interacts with
https://www.npmjs.com/package/rollup-plugin-bundle-html -->
<script type="module" src="/bundle-es2015.min/index.js"></script>
<script nomodule="" src="/bundle-es5.min/index.js"></script>
<script nomodule="" src="/bundle-es5.min/index.js"></script>
</body>
</html>
59 changes: 59 additions & 0 deletions examples/angular/src/manifest.webmanifest
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{
"name": "Angular Bazel Example",
"short_name": "Angular Bazel",
"theme_color": "#43a047",
"background_color": "#fff",
"display": "standalone",
"scope": "./",
"start_url": "./",
"icons": [
{
"src": "assets/icons/icon-72x72.png",
"sizes": "72x72",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/icon-96x96.png",
"sizes": "96x96",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/icon-128x128.png",
"sizes": "128x128",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/icon-144x144.png",
"sizes": "144x144",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/icon-152x152.png",
"sizes": "152x152",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/icon-384x384.png",
"sizes": "384x384",
"type": "image/png",
"purpose": "maskable any"
},
{
"src": "assets/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable any"
}
]
}
35 changes: 35 additions & 0 deletions examples/angular/src/ngsw-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"$schema": "../node_modules/@angular/service-worker/config/schema.json",
"index": "/index.html",
"assetGroups": [
{
"name": "app",
"installMode": "prefetch",
"updateMode": "prefetch",
"resources": {
"files": [
"favicon.ico",
"index.html",
"manifest.webmanifest",
"/**/*.css",
"/**/*.js"
],
"urls": [
"https://fonts.googleapis.com/**",
"https://fonts.gstatic.com/s/**"
]
}
},
{
"name": "assets",
"installMode": "lazy",
"updateMode": "prefetch",
"resources": {
"files": [
"/assets/**",
"/*.(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)"
]
}
}
]
}
2 changes: 2 additions & 0 deletions examples/angular/src/robots.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
User-agent: *
Allow: /
63 changes: 25 additions & 38 deletions examples/angular/src/server.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,28 @@
///<reference types="node"/>
import "zone.js/dist/zone-node";
///<reference types='node'/>
import 'zone.js/dist/zone-node';

import { ngExpressEngine } from "@nguniversal/express-engine";
import * as express from "express";
import { join } from "path";
import { ngExpressEngine } from '@nguniversal/express-engine';
import * as express from 'express';
import { join } from 'path';
import * as compression from 'compression';

const app = express();

const PORT = process.env.PORT || 4000;
const DIST_FOLDER = join(process.cwd(), "src/prodapp");

import { AppServerModule } from "./app/app.server.module";

app.engine(
"html",
ngExpressEngine({
bootstrap: AppServerModule,
providers: [
// TODO add support for lazy loading with server side rendering
// provideModuleMap(LAZY_MODULE_MAP)
]
}) as any
);

app.set("view engine", "html");
app.set("views", DIST_FOLDER);
import { AppServerModule } from './app/app.server.module';

app.get("*.*", express.static(DIST_FOLDER, { maxAge: "1y" }));

// catch /favicon.ico route to prevent the following server error:
// Error: Cannot match any routes. URL Segment: 'favicon.ico'
app.get("/favicon.ico", (req, res) => res.send(""));

app.get("*", (req, res) => {
res.render("example/index", { req });
});

app.listen(PORT, () => {
console.log(`Node Express server listening on http://localhost:${PORT}`);
});
const app = express();
const port = process.env.PORT || 4000;
const DIST_FOLDER = join(process.cwd(), 'src/pwa');

/**
* text compression for smaller download sizes and thus faster load times
* without compression: 1.4 MB
* with compresion: 321 kB
*/
app.use(compression());

app.engine('html', ngExpressEngine({ bootstrap: AppServerModule }) as any);
app.set('view engine', 'html');
app.set('views', DIST_FOLDER);

app.get('*.*', express.static(DIST_FOLDER, { maxAge: '1y' }));
app.get('*', (req, res) => res.render('example/index', { req }));
app.listen(port, () => console.log(`Server listening http://localhost:${port}`));
37 changes: 37 additions & 0 deletions examples/angular/tools/ngsw_config.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"Angular service worker support (credits: https://github.com/marcus-sa)"

load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary")

def ngsw_config(name, config, index_html, src, out = None, **kwargs):
if not out:
out = name

ngsw_config_name = "%s_bin" % name

nodejs_binary(
name = ngsw_config_name,
data = ["@npm//@angular/service-worker", index_html, config, src],
visibility = ["//visibility:private"],
entry_point = "@npm//:node_modules/@angular/service-worker/ngsw-config.js",
)

cmd = """
mkdir -p $@
cp -R $(locations {TMPL_src})/. $@/
cp $(location {TMPL_index}) $@/index.html
$(location :{TMPL_bin}) $@ $(location {TMPL_conf})
""".format(
TMPL_src = src,
TMPL_bin = ngsw_config_name,
TMPL_index = index_html,
TMPL_conf = config,
)

native.genrule(
name = name,
outs = [out],
srcs = [src, config, index_html],
tools = [":" + ngsw_config_name],
cmd = cmd,
**kwargs
)
Loading

0 comments on commit 4d5b9c7

Please sign in to comment.