| """Helper macros for rendering parts of an Angular application at build time""" |
| |
| load("@build_bazel_rules_nodejs//:index.bzl", _nodejs_binary = "nodejs_binary", _nodejs_test = "nodejs_test") |
| load("@npm//@bazel/typescript:index.bzl", _ts_library = "ts_library") |
| |
| def _get_output_path(route, root_at): |
| return root_at + "/" + route + "/index.html" |
| |
| def ng_prerender(name, index, prerender_roots = [], **kwargs): |
| """ |
| Helper macro for prerendering Angular routes to index files as part of the build |
| |
| The outputs of this macro are: |
| %name% - all the rendered roots, plus the root route / |
| %name%.root - an alias referencing just the root index file |
| %name%.%route% - an alias referencing each rendered route, with / replaced by underscores |
| |
| Args: |
| name: Rule name for the main output genrule |
| index: Label for the production index.html file with which to render into |
| prerender_roots: A list of roots that will be prerendered as part of this macro, the root route / is always rendered |
| """ |
| |
| renderer_lib = "%s_renderer_lib" % name |
| _ts_library( |
| name = renderer_lib, |
| srcs = ["//src:prerender.ts"], |
| deps = [ |
| "//src/app:app_server", |
| "@npm//@angular/platform-server", |
| "@npm//zone.js", |
| "@npm//domino", |
| "@npm//reflect-metadata", |
| "@npm//@types/node", |
| ], |
| ) |
| |
| bin = "%s_bin" % renderer_lib |
| _nodejs_binary( |
| name = bin, |
| data = [ |
| ":%s" % renderer_lib, |
| "@npm//@angular/platform-server", |
| "@npm//zone.js", |
| "@npm//domino", |
| "@npm//reflect-metadata", |
| ], |
| entry_point = "//src:prerender.ts", |
| templated_args = ["--nobazel_run_linker"], |
| ) |
| |
| root_at = "_prerender/" + native.package_name() |
| |
| # we can't output "foo/index.html" since that collides with source files and will likely cross a package boundary |
| # so we output "_prerender/pkg_name/route/index.html" |
| prerender_root_outs = [_get_output_path(route, root_at) for route in prerender_roots] |
| root_index = "%s/index.html" % root_at |
| |
| visibility = kwargs.pop("visibility", []) |
| |
| native.genrule( |
| name = name, |
| srcs = [index], |
| outs = [root_index] + prerender_root_outs, |
| cmd = "$(location :%s) --index $(location %s) --outs $(OUTS) --routes / %s" % (bin, index, " ".join(prerender_roots)), |
| tools = [":%s" % bin], |
| message = "Prerendering Angular", |
| visibility = visibility, |
| tags = kwargs.pop("tags", []), |
| ) |
| |
| # convenience "output groups" from macro |
| native.alias( |
| name = "%s.root" % name, |
| actual = root_index, |
| visibility = visibility, |
| ) |
| |
| [ |
| native.alias( |
| name = "%s.%s" % (name, route.replace("/", "_")), |
| actual = _get_output_path(route, root_at), |
| visibility = visibility, |
| ) |
| for route in prerender_roots |
| ] |
| |
| def ng_prerender_test(name, index, route, expected_elements = [], **kwargs): |
| """ |
| Simple smoke test for a prerendered index file, as generated by ng_prerender |
| |
| Args: |
| name: Rule name for the test |
| index: Label of the index file under test |
| route: The route that this index file belongs to |
| expected_elements: An optional array of expected elements that should appear in the index file |
| """ |
| |
| _ts_library( |
| name = "%s_render_spec" % name, |
| srcs = ["//src:prerender-spec.ts"], |
| deps = [ |
| "@npm//@types/node", |
| ], |
| testonly = 1, |
| ) |
| |
| _nodejs_test( |
| name = name, |
| data = [ |
| ":%s_render_spec" % name, |
| index, |
| ], |
| templated_args = ["--index $(location %s)" % index, "--route %s" % route, "--expected %s" % (" ".join(expected_elements))], |
| entry_point = "//src:prerender-spec.ts", |
| tags = kwargs.pop("tags", []), |
| ) |