| """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", []), | |
| ) |