Skip to content

Commit

Permalink
Adds Declarative Shadow DOM example.
Browse files Browse the repository at this point in the history
Refs #38.

This renders an example component using Declarative Shadow DOM and a simple style limited to the shadow root.
  • Loading branch information
dgp1130 committed Sep 7, 2021
1 parent 9d3944a commit 63aa3f7
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 0 deletions.
47 changes: 47 additions & 0 deletions examples/declarative_shadow_dom/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
load("@npm//@bazel/typescript:index.bzl", "ts_library")
load(
"//:index.bzl",
"prerender_component",
"prerender_pages",
"web_resources_devserver",
)
load("//tools:jasmine.bzl", "jasmine_node_test")

prerender_pages(
name = "site",
src = "site.ts",
lib_deps = ["//packages/rules_prerender"],
deps = [":component"],
)

prerender_component(
name = "component",
srcs = ["component.ts"],
styles = ["component.css"],
lib_deps = ["//packages/rules_prerender"],
deps = ["//:declarative_shadow_dom"],
)

web_resources_devserver(
name = "devserver",
resources = ":site",
)

ts_library(
name = "test_lib",
srcs = ["test.ts"],
data = [":devserver"],
testonly = True,
deps = [
"//common/testing:devserver",
"//common/testing:puppeteer",
"@npm//@bazel/runfiles",
"@npm//@types/jasmine",
"@npm//@types/node",
],
)

jasmine_node_test(
name = "test",
deps = [":test_lib"],
)
9 changes: 9 additions & 0 deletions examples/declarative_shadow_dom/component.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* Because this sheet is included in a shadow root, we can use very broad
* selectors like `div` and trust that they will be scoped only to the
* component DOM
*/

div {
color: red;
}
30 changes: 30 additions & 0 deletions examples/declarative_shadow_dom/component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { inlineStyle } from 'rules_prerender';
import { polyfillDeclarativeShadowDom } from 'rules_prerender/declarative_shadow_dom';

/** Renders an example component using Declarative Shadow DOM. */
export async function renderComponent(lightDom: string): Promise<string> {
return `
<!-- Host element. -->
<div id="component">
<!-- Shadow root. -->
<template shadowroot="open">
<!-- Polyfill declarative shadow DOM for browsers that don't
support it yet. -->
${polyfillDeclarativeShadowDom()}
<!-- Inline styles to apply them within this shadow root. -->
${await inlineStyle('rules_prerender/examples/declarative_shadow_dom/component.css')}
<!-- Shadow DOM content, styled with the associated style
sheet. -->
<div>Shadow content</div>
<!-- Slot to insert the associated light DOM. -->
<slot></slot>
</template>
<!-- Light DOM content, not affected by above style sheet. -->
${lightDom}
</div>
`;
}
18 changes: 18 additions & 0 deletions examples/declarative_shadow_dom/site.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { PrerenderResource } from 'rules_prerender';
import { renderComponent } from 'rules_prerender/examples/declarative_shadow_dom/component';

export default async function*(): AsyncGenerator<PrerenderResource, void, void> {
yield PrerenderResource.of('/index.html', `
<!DOCTYPE html>
<html>
<head>
<title>Declarative Shadow DOM</title>
</head>
<body>
${await renderComponent(`
<div>Light content</div>
`)}
</body>
</html>
`);
}
49 changes: 49 additions & 0 deletions examples/declarative_shadow_dom/test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import 'jasmine';

import { runfiles } from '@bazel/runfiles';
import { useDevserver } from 'rules_prerender/common/testing/devserver';
import { puppeteerTestTimeout, useBrowser, usePage } from 'rules_prerender/common/testing/puppeteer';

const devserverBinary = runfiles.resolvePackageRelative('devserver');

describe('Declarative Shadow DOM', () => {
const server = useDevserver(devserverBinary);
const browser = useBrowser();
const page = usePage(browser);

it('attaches the declarative shadow root to its host', async () => {
await page.get().goto(
`http://${server.get().host}:${server.get().port}/`,
{ waitUntil: 'load' },
);

const title = await page.get().title();
expect(title).toBe('Declarative Shadow DOM');

const shadowRoot = await page.get().evaluateHandle(
'document.querySelector("#component").shadowRoot');
expect(shadowRoot).toBeTruthy();
});

it('scopes CSS to the shadow root', async () => {
await page.get().goto(
`http://${server.get().host}:${server.get().port}/`,
{ waitUntil: 'load' },
);

const shadowDiv = await page.get().evaluateHandle(
'document.querySelector("#component").shadowRoot.querySelector("div")');
expect(await shadowDiv.evaluate((el) => el.textContent))
.toBe('Shadow content');
const shadowDivColor =
await shadowDiv.evaluate((el) => getComputedStyle(el).color);
expect(shadowDivColor).toBe('rgb(255, 0, 0)'); // Red.

const lightDivText = await page.get().$eval(
'#component div', (el) => el.textContent);
expect(lightDivText).toBe('Light content');
const lightDivColor = await page.get().$eval(
'#component div', (el) => getComputedStyle(el).color);
expect(lightDivColor).toBe('rgb(0, 0, 0)'); // Black (default).
}, puppeteerTestTimeout);
});

0 comments on commit 63aa3f7

Please sign in to comment.