blob: dd7e21a33239c99baf324604a3b092df9efbf1cf [file] [log] [blame]
load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary", "pkg_web")
load("@io_bazel_rules_docker//container:container.bzl", "container_image")
load("@io_bazel_rules_docker//nodejs:image.bzl", "nodejs_image")
load("@io_bazel_rules_sass//:defs.bzl", "sass_binary")
load("@npm//@babel/cli:index.bzl", "babel")
load("@npm//@bazel/concatjs:index.bzl", "concatjs_devserver")
load("@npm//@bazel/rollup:index.bzl", "rollup_bundle")
load("@npm//@bazel/terser:index.bzl", "terser_minified")
load("@npm//@bazel/typescript:index.bzl", "ts_config", "ts_library")
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__"])
ts_config(
name = "tsconfig-test",
src = "tsconfig-test.json",
deps = [":tsconfig.json"],
)
ts_config(
name = "tsconfig-server",
src = "tsconfig.server.json",
deps = [":tsconfig.json"],
)
# Run the sass compiler to output "styles.css"
# TODO(alexeagle): demonstrate the sass_library rule too
sass_binary(
name = "styles",
src = "styles.scss",
)
ts_library(
name = "initialize_testbed",
testonly = 1,
srcs = [
"initialize_testbed.ts",
],
deps = [
"@npm//@angular/core",
"@npm//@angular/platform-browser-dynamic",
"@npm//@types",
],
)
ng_ts_library(
name = "src",
srcs = [
"main.dev.ts",
"main.prod.ts",
],
tsconfig = ":tsconfig.json",
deps = [
"//src/app",
"@npm//@angular/core",
"@npm//@angular/platform-browser",
"@npm//@angular/router",
"@npm//@ngrx/store",
],
)
filegroup(
name = "rxjs_umd_modules",
srcs = [
":rxjs_shims.js",
"@npm//:node_modules/rxjs/bundles/rxjs.umd.js",
],
)
# Files that we serve in both development and production
_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",
# We load zone.js outside the bundle. That's because it's a "pollyfill"
# which speculates that such features might be available in a browser.
# Also it's tricky to configure dead code elimination to understand that
# zone.js is used, given that we don't have any import statement that
# imports from it.
"@npm//:node_modules/zone.js/dist/zone.min.js",
]
html_insert_assets(
name = "inject_scripts_for_dev",
outs = ["index.html"],
args = [
"--html=$(execpath //src:example/index.html)",
"--out=$@",
"--roots=. $(RULEDIR)",
"--assets",
] + ["$(execpath %s)" % s for s in _ASSETS] + [
# This file doesn't exist during the build, but will be served by concatjs_devserver
"./_/ts_scripts.js",
],
data = ["//src:example/index.html"] + _ASSETS,
)
# This devserver is written in Go and is super-fast.
# It doesn't run any bundler or code splitter. Instead, it concatenates
# named UMD and named AMD JavaScript code on-the-fly in-memory.
# This scales really well for massive codebases.
concatjs_devserver(
name = "devserver",
# Serve src/example/index.html at /index.html
additional_root_paths = ["src/example"],
# Run the program from the development version of the main
entry_module = "examples_angular/src/main.dev",
# These scripts will be included in the JS bundle after require.js
# They should have only named UMD modules, or require.js will throw.
scripts = [
"@npm//:node_modules/tslib/tslib.js",
":rxjs_umd_modules",
# We are manaully adding the bazel generated named-UMD date-fns bundle here as
# named-UMD bundles for non-APF npm packages are not yet automatically added.
# This file is generated by the npm_umd_bundle @npm//date-fns:date-fns__umd
# rule that is setup by yarn_install.
"@npm//date-fns:date-fns.umd.js",
],
# Serve these files in addition to the JavaScript bundle
static_files = _ASSETS + [
":inject_scripts_for_dev",
"//src/assets",
],
# Tell Bazel to build the sources first
deps = ["//src"],
)
rollup_bundle(
name = "bundle-es2015",
config_file = "rollup.config.js",
entry_points = {
":main.prod.ts": "index",
},
output_dir = True,
deps = [
"//src",
"@npm//@rollup/plugin-commonjs",
"@npm//@rollup/plugin-node-resolve",
],
)
babel(
name = "bundle-es5",
args = [
"$(execpath :bundle-es2015)",
"--no-babelrc",
"--source-maps",
"--presets=@babel/preset-env",
"--plugins=@babel/plugin-transform-modules-systemjs",
"--out-dir",
"$(@D)",
],
data = [
":bundle-es2015",
"@npm//@babel/preset-env",
],
output_dir = True,
)
terser_minified(
name = "bundle-es2015.min",
src = ":bundle-es2015",
)
terser_minified(
name = "bundle-es5.min",
src = ":bundle-es5",
)
# take the skeleton index.html and use it to render the root, /hello and /todos routes
# this generates multiple index.html files, one for each requested route
ng_prerender(
name = "prerender",
index = "//src:example/index.prod.html",
# routes added here are rendered out to index files
# the root route / is always rendered
prerender_roots = [
"hello",
"todos",
],
)
# smoke test testing the generated root index for key elements
ng_prerender_test(
name = "prerender_test",
expected_elements = ["app-component"],
index = ":prerender.root",
route = "/",
)
html_insert_assets(
name = "inject_scripts_for_prod",
# we can't output "src/example/index.html" since that collides with the devmode file.
# pkg_web rule will re-root paths that start with _{name} by default
# so we output "_prodapp/src/example/index.html" so that it is mapped to
# `example/index.html` in the web package.
outs = ["_prodapp/src/example/index.html"],
args = [
"--html=$(execpath //src:prerender.root)",
"--out=$@",
"--roots=. $(RULEDIR)",
"--assets",
] + ["$(execpath %s)" % s for s in _ASSETS],
data = ["//src:prerender.root"] + _ASSETS,
)
# as there is a index for the /hello and /todos routes, each index needs the scripts and
# assets injected in
html_insert_assets(
name = "inject_scripts_for_prod_hello_route_index",
outs = ["_prodapp/src/example/hello/index.html"],
args = [
"--html=$(execpath //src:prerender.hello)",
"--out=$@",
"--roots=. $(RULEDIR)",
"--assets",
] + ["$(execpath %s)" % s for s in _ASSETS],
data = ["//src:prerender.hello"] + _ASSETS,
)
html_insert_assets(
name = "inject_scripts_for_prod_todos_route_index",
outs = ["_prodapp/src/example/todos/index.html"],
args = [
"--html=$(execpath //src:prerender.todos)",
"--out=$@",
"--roots=. $(RULEDIR)",
"--assets",
] + ["$(execpath %s)" % s for s in _ASSETS],
data = ["//src:prerender.todos"] + _ASSETS,
)
pkg_web(
name = "prodapp",
srcs = _ASSETS + [
":bundle-es2015.min",
":bundle-es5.min",
# each injected index file should be listed here
":inject_scripts_for_prod",
":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",
],
# 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 = [":pwa"],
templated_args = ["-a $$(rlocation $(rootpath :pwa))"],
)
nodejs_image(
name = "nodejs_image",
binary = ":prodserver",
# Actions created by this rule are I/O-bound,
# so there is no benefit to running them remotely
tags = ["local"],
)
container_image(
name = "image",
base = ":nodejs_image",
# Actions created by this rule are I/O-bound,
# so there is no benefit to running them remotely
tags = ["local"],
)
ts_library(
name = "universal_server_lib",
srcs = ["server.ts"],
deps = [
"//src/app:app_server",
"@npm//@nguniversal/express-engine",
"@npm//@types/node",
"@npm//express",
],
)
nodejs_binary(
name = "universal_server",
data = [
":pwa",
":universal_server_lib",
],
entry_point = ":server.ts",
templated_args = ["--bazel_patch_module_resolver"],
)