diff --git a/.vscode/settings.json b/.vscode/settings.json index 3dce572b..0e9adc01 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -20,6 +20,7 @@ "readonly", "runfile", "semver", + "shadowroot", "testonly", "transpiled", "tsjs", diff --git a/packages/rules_prerender/BUILD.bazel b/packages/rules_prerender/BUILD.bazel index 95baa5f5..6e0d9f1a 100644 --- a/packages/rules_prerender/BUILD.bazel +++ b/packages/rules_prerender/BUILD.bazel @@ -1,5 +1,6 @@ load("@bazel_skylib//:bzl_library.bzl", "bzl_library") load("@npm//@bazel/typescript:index.bzl", "ts_library") +load("//:index.bzl", "prerender_component") load("//tools:jasmine.bzl", "jasmine_node_test") load("//tools:publish.bzl", "publish_files") @@ -147,6 +148,7 @@ bzl_library( ts_library( name = "scripts", srcs = ["scripts.ts"], + visibility = ["//packages/rules_prerender/declarative_shadow_dom:__pkg__"], deps = ["//common/models:prerender_annotation"], ) diff --git a/packages/rules_prerender/BUILD.publish b/packages/rules_prerender/BUILD.publish index 276aec82..b6b505f4 100644 --- a/packages/rules_prerender/BUILD.publish +++ b/packages/rules_prerender/BUILD.publish @@ -1,4 +1,22 @@ +load(":prerender_component.bzl", "prerender_component") +load("@npm//@bazel/typescript:index.bzl", "ts_library") + exports_files( ["rollup-default.config.js"], visibility = ["//visibility:public"], ) + +# TESTME +# TODO(#39): Don't ship TypeScript code to NPM and compile it on the user's cpu. +prerender_component( + name = "declarative_shadow_dom", + srcs = ["declarative_shadow_dom.ts"], + scripts = [":declarative_shadow_dom_polyfill"], + lib_deps = ["@npm//rules_prerender"], + visibility = ["//visibility:public"], +) + +ts_library( + name = "declarative_shadow_dom_polyfill", + srcs = ["declarative_shadow_dom_polyfill.ts"], +) diff --git a/packages/rules_prerender/declarative_shadow_dom/BUILD.bazel b/packages/rules_prerender/declarative_shadow_dom/BUILD.bazel new file mode 100644 index 00000000..52877ebe --- /dev/null +++ b/packages/rules_prerender/declarative_shadow_dom/BUILD.bazel @@ -0,0 +1,34 @@ +load("@npm//@bazel/typescript:index.bzl", "ts_library") +load( + "//packages/rules_prerender:prerender_component.bzl", + "prerender_component", +) +load("//tools:jasmine.bzl", "jasmine_node_test") + +prerender_component( + name = "declarative_shadow_dom", + srcs = ["declarative_shadow_dom.ts"], + scripts = [":declarative_shadow_dom_polyfill"], + lib_deps = ["//packages/rules_prerender:scripts"], + visibility = ["//visibility:public"], +) + +ts_library( + name = "declarative_shadow_dom_test_lib", + srcs = ["declarative_shadow_dom_test.ts"], + testonly = True, + deps = [ + ":declarative_shadow_dom_prerender_for_test", + "@npm//@types/jasmine", + ], +) + +jasmine_node_test( + name = "declarative_shadow_dom_test", + deps = [":declarative_shadow_dom_test_lib"], +) + +ts_library( + name = "declarative_shadow_dom_polyfill", + srcs = ["declarative_shadow_dom_polyfill.ts"], +) diff --git a/packages/rules_prerender/declarative_shadow_dom/declarative_shadow_dom.ts b/packages/rules_prerender/declarative_shadow_dom/declarative_shadow_dom.ts new file mode 100644 index 00000000..4a0005a0 --- /dev/null +++ b/packages/rules_prerender/declarative_shadow_dom/declarative_shadow_dom.ts @@ -0,0 +1,10 @@ +import { includeScript } from 'rules_prerender/packages/rules_prerender/scripts'; + +/** + * Returns a prerender annotation used by the bundler to inject the declarative + * shadow DOM polyfill into the document. + */ +export function polyfillDeclarativeShadowDom(): string { + return includeScript( + 'rules_prerender/packages/rules_prerender/declarative_shadow_dom/declarative_shadow_dom_polyfill'); +} diff --git a/packages/rules_prerender/declarative_shadow_dom/declarative_shadow_dom_polyfill.ts b/packages/rules_prerender/declarative_shadow_dom/declarative_shadow_dom_polyfill.ts new file mode 100644 index 00000000..72ff7ad9 --- /dev/null +++ b/packages/rules_prerender/declarative_shadow_dom/declarative_shadow_dom_polyfill.ts @@ -0,0 +1,23 @@ +/** + * @fileoverview Polyfills declarative shadow DOM by searching for templates + * which match its attributes and attaching them as real shadow roots. + * + * Shamelessly stolen from: https://web.dev/declarative-shadow-dom/#polyfill and + * adapted for TypeScript. + */ + +const templates = document.querySelectorAll('template[shadowroot]') as + NodeListOf; +for (const template of Array.from(templates)) { + const mode = template.getAttribute('shadowroot'); + if (mode !== 'open' && mode !== 'closed') { + console.error( + `Found declarative shadow root with invalid mode: ${mode}.`); + continue; + } + + const parent = template.parentNode as Element; + const shadowRoot = parent.attachShadow({ mode }); + shadowRoot.appendChild(template.content); + template.remove(); +} diff --git a/packages/rules_prerender/declarative_shadow_dom/declarative_shadow_dom_test.ts b/packages/rules_prerender/declarative_shadow_dom/declarative_shadow_dom_test.ts new file mode 100644 index 00000000..c60c7036 --- /dev/null +++ b/packages/rules_prerender/declarative_shadow_dom/declarative_shadow_dom_test.ts @@ -0,0 +1,11 @@ +import 'jasmine'; +import { polyfillDeclarativeShadowDom } from 'rules_prerender/packages/rules_prerender/declarative_shadow_dom/declarative_shadow_dom'; + +describe('declarative_shadow_dom', () => { + describe('polyfillDeclarativeShadowDom()', () => { + it('returns an annotation to include the declarative shadow DOM polyfill', () => { + expect(polyfillDeclarativeShadowDom()) + .toBe(''); + }); + }); +});