blob: 721215bf93fedc58bf4f69c7bb4e50b822e2405f [file] [log] [blame]
load("@build_bazel_rules_nodejs//:index.bzl", "pkg_web")
load("@infra-sk_npm//@bazel/typescript:index.bzl", "ts_library")
load("@infra-sk_npm//@bazel/rollup:index.bzl", "rollup_bundle")
load("@infra-sk_npm//@bazel/terser:index.bzl", "terser_minified")
load("@infra-sk_npm//html-insert-assets:index.bzl", "html_insert_assets")
load("@io_bazel_rules_sass//:defs.bzl", "sass_library", "sass_binary")
load("//infra-sk/html_insert_nonce_attribute:index.bzl", "html_insert_nonce_attribute")
# Utility macro to copy a single file to a destination path, making parent directories as needed.
def copy_file(name, src, dst):
native.genrule(
name = name,
srcs = [src],
outs = [dst],
cmd = "mkdir -p $$(dirname $@) && cp $< $@"
)
# This macro takes a page name, e.g. "mypage", assumes the existence of files mypage.html, mypage.ts
# and mypage.scss, and defines the necessary build targets to generate development and production
# bundles for said page.
#
# Input files:
# <name>.html
# <name>.ts
# <name>.scss
#
# Generated files:
# development/<name>.html
# development/<name>.ts
# development/<name>.scss
# production/<name>.html
# production/<name>.ts
# production/<name>.scss
#
# For convenience, a target with the same name as the "name" argument is defined, which generates
# all of the above files (e.g. bazel build //path/to:mypage).
#
# Tags <script> and <link> will be inserted into the output HTML pointing to the generated bundles.
# The serving path for said bundles defaults to "/" and can be overriden via the
# assets_serving_path argument.
#
# A timestamp will be appended to the URLs for any referenced assets for cache busting purposes,
# e.g. <script src="/index.js?v=27396986"></script>.
#
# If the nonce argument is provided, a nonce attribute will be inserted to all <link> and <script>
# tags. For example, if the nonce argument is set to "{% .Nonce %}", then the generated HTML will
# contain tags such as <script nonce="{% .Nonce %}" src="/index.js?v=27396986"></script>.
#
# This macro is designed to work side by side with the existing Webpack build without requiring any
# major changes to the pages in question.
def sk_page(name, deps, sass_deps, assets_serving_path="/", nonce=None):
# Output directories.
DEV_OUT_DIR = "development"
PROD_OUT_DIR = "production"
#######################
# JavaScript bundles. #
#######################
ts_library(
name = "%s_ts_lib" % name,
srcs = ["%s.ts" % name],
deps = deps,
)
# Generates file <name>_js_bundle.js. Intermediate result; do not use.
rollup_bundle(
name = "%s_js_bundle" % name,
deps = [
":%s_ts_lib" % name,
"@infra-sk_npm//@rollup/plugin-node-resolve",
"@infra-sk_npm//@rollup/plugin-commonjs",
"@infra-sk_npm//rollup-plugin-sourcemaps",
],
entry_point = "%s.ts" % name,
format = "umd",
config_file = "//infra-sk:rollup.config.js",
)
# Generates file <name>_js_bundle_minified.js. Intermediate result; do not use.
terser_minified(
name = "%s_js_bundle_minified" % name,
src = "%s_js_bundle.js" % name,
sourcemap = False,
)
# Generates file development/<name>.js.
copy_file(
name = "%s_js_dev" % name,
src = "%s_js_bundle.js" % name,
dst = "%s/%s.js" % (DEV_OUT_DIR, name),
)
# Generates file production/<name>.js.
copy_file(
name = "%s_js_prod" % name,
# For some reason the output of the terser_minified rule above is not directly visible as a
# source file, so we use the rule name instead (i.e. we drop the ".js" extension).
src = "%s_js_bundle_minified" % name,
dst = "%s/%s.js" % (PROD_OUT_DIR, name),
)
################
# CSS Bundles. #
################
# Notes:
# - The source maps generated by the sass_binary rule are currently broken.
# - Sass compilation errors are not visible unless "bazel build" is invoked with flag
# "--strategy=SassCompiler=sandboxed". This is due to a known issue with sass_binary. For
# more details please see https://github.com/bazelbuild/rules_sass/issues/96.
# Generates file development/<name>.css.
sass_binary(
name = "%s_css_dev" % name,
src = "%s.scss" % name,
output_name = "%s/%s.css" % (DEV_OUT_DIR, name),
deps = sass_deps,
include_paths = ["//infra-sk/node_modules"],
output_style = "expanded",
sourcemap = True,
)
# Generates file production/<name>.css.
sass_binary(
name = "%s_css_prod" % name,
src = "%s.scss" % name,
output_name = "%s/%s.css" % (PROD_OUT_DIR, name),
deps = sass_deps,
include_paths = ["//infra-sk/node_modules"],
output_style = "compressed",
sourcemap = False,
)
###############
# HTML files. #
###############
# Generates file <name>.with_assets.html. Intermediate result; do not use.
#
# See https://www.npmjs.com/package/html-insert-assets.
html_insert_assets(
name = "%s_html" % name,
outs = ["%s.with_assets.html" % name],
args = [
"--html=$(location %s.html)" % name,
"--out=$@",
"--roots=$(RULEDIR)",
"--assets",
# This is OK because html-insert-assets normalizes paths with successive slashes.
"%s/%s.js" % (assets_serving_path, name),
"%s/%s.css" % (assets_serving_path, name),
],
data = ["%s.html" % name],
)
if nonce:
# Generates file <name>.with_assets_and_nonce.html. Intermediate result; do not use.
html_insert_nonce_attribute(
name = "%s_html_nonce" % name,
src = "%s.with_assets.html" % name,
out = "%s.with_assets_and_nonce.html" % name,
nonce = nonce,
)
instrumented_html = ("%s.with_assets_and_nonce.html" if nonce else "%s.with_assets.html") % name
# Generates file development/<name>.html.
copy_file(
name = "%s_html_dev",
src = instrumented_html,
dst = "%s/%s.html" % (DEV_OUT_DIR, name),
)
# Generates file production/<name>.html.
copy_file(
name = "%s_html_prod",
src = instrumented_html,
dst = "%s/%s.html" % (PROD_OUT_DIR, name),
)
###########################
# Convenience filegroups. #
###########################
# Generates all output files (that is, the development and production bundles).
native.filegroup(
name = name,
srcs = [
":%s_dev" % name,
":%s_prod" % name,
],
)
# Generates the development bundle.
native.filegroup(
name = "%s_dev" % name,
srcs = [
"development/%s.html" % name,
"development/%s.js" % name,
"development/%s.css" % name,
]
)
# Generates the production bundle.
native.filegroup(
name = "%s_prod" % name,
srcs = [
"production/%s.html" % name,
"production/%s.js" % name,
"production/%s.css" % name,
]
)