Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: ssr for uxdot-pattern #1971

Merged
merged 25 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
a0e7554
docs: reduce number of file watchers
bennypowers Oct 8, 2024
d722a04
docs: reimplement lit-ssr plugin
bennypowers Oct 8, 2024
a19e2a4
docs: implement ssr-able uxdot-pattern
bennypowers Oct 8, 2024
8356643
docs: migrate uxdot-pattern usage to ssr
bennypowers Oct 8, 2024
dedd294
docs: fix pattern styles
bennypowers Oct 8, 2024
120bd88
docs: headings slotted into pattern
bennypowers Oct 8, 2024
6c85b1b
docs: watch for pattern files
bennypowers Oct 8, 2024
21cb2ae
docs: resizable demo container
bennypowers Oct 8, 2024
57a854e
chore: core patch
bennypowers Oct 8, 2024
8a985db
chore: remove extra file
bennypowers Oct 8, 2024
5b2b314
Merge branch 'main' into docs/pattern-code-tabs
bennypowers Oct 8, 2024
ebfb27e
docs: uxdot-pattern review comments
bennypowers Oct 9, 2024
e8fd4a8
Merge branch 'main' into docs/pattern-code-tabs
bennypowers Oct 9, 2024
003e07f
docs(tabs): patterns
bennypowers Oct 9, 2024
99fa5fb
docs: uxdot-pattern is not a provider
bennypowers Oct 9, 2024
286de1e
docs: uxdot-pattern hydrate ssr state on client
bennypowers Oct 9, 2024
6a6eabc
docs: uxdot pattern responsive padding
bennypowers Oct 9, 2024
a616858
docs: uxdot-pattern attrs
bennypowers Oct 9, 2024
07ec41e
docs: pattern usage
bennypowers Oct 9, 2024
e43e747
Merge branch 'main' into docs/pattern-code-tabs
bennypowers Oct 9, 2024
e524cbe
feat: make generic ssr controller
bennypowers Oct 9, 2024
8763939
chore: update pfe-core patch
bennypowers Oct 9, 2024
21f70d5
chore: update deps
bennypowers Oct 9, 2024
b66ffcf
style: whitespace
bennypowers Oct 9, 2024
de70ac5
chore: update deps
bennypowers Oct 9, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions declaration.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,12 @@ declare module 'prism-esm/plugins/line-numbers/prism-line-numbers.js' {
import type { Prism } from "prism-esm";
export function Plugin(prism: Prism): void
}

declare module '@11ty/eleventy-plugin-syntaxhighlight/src/HighlightPairedShortcode.js' {
export default function HighlightPairedShortcode(content: string, language: string, highlightLines: string, options: object): any
}

declare module '@11ty/eleventy-plugin-syntaxhighlight/src/getAttributes.js' {
export default function getAttributes(...args: any[]): string
}

110 changes: 110 additions & 0 deletions docs/_plugins/lit-ssr/lit.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/**
* @license based on code from eleventy-plugin-lit
* Copyright 2021 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/

const path = require('node:path');
const { pathToFileURL } = require('node:url');
// eslint-disable-next-line no-redeclare
const { Worker } = require('node:worker_threads');

// Lit SSR includes comment markers to track the outer template from
// the template we've generated here, but it's not possible for this
// outer template to be hydrated, so they serve no purpose.
function trimOuterMarkers(renderedContent) {
return renderedContent
.replace(/^((<!--[^<>]*-->)|(<\?>)|\s)+/, '')
.replace(/((<!--[^<>]*-->)|(<\?>)|\s)+$/, '');
}

/**
* @param {import('@11ty/eleventy').UserConfig} eleventyConfig
* @param {{componentModules: string[]}} resolvedComponentModules
*/
module.exports = function(eleventyConfig, { componentModules } = {}) {
if (componentModules === undefined || componentModules.length === 0) {
// If there are no component modules, we could never have anything to
// render.
return;
}

const resolvedComponentModules = componentModules.map(module =>
pathToFileURL(path.resolve(process.cwd(), module)).href);

let worker;

const requestIdResolveMap = new Map();
let requestId = 0;

eleventyConfig.on('eleventy.before', async function() {
worker = new Worker(path.resolve(__dirname, './worker/worker.js'));

worker.on('error', err => {
// eslint-disable-next-line no-console
console.error('Unexpected error while rendering lit component in worker thread', err);
throw err;
});

let requestResolve;
const requestPromise = new Promise(resolve => {
requestResolve = resolve;
});

worker.on('message', message => {
switch (message.type) {
case 'initialize-response': {
requestResolve();
break;
}

case 'render-response': {
const { id, rendered } = message;
const resolve = requestIdResolveMap.get(id);
if (resolve === undefined) {
throw new Error(
'@lit-labs/eleventy-plugin-lit received invalid render-response message'
);
}
resolve(rendered);
requestIdResolveMap.delete(id);
break;
}
}
});

const message = {
type: 'initialize-request',
imports: resolvedComponentModules,
};

worker.postMessage(message);
await requestPromise;
});

eleventyConfig.on('eleventy.after', async () => {
await worker.terminate();
});

eleventyConfig.addTransform('render-lit', async function(content) {
if (!this.page.outputPath.endsWith('.html')) {
return content;
}

const renderedContent = await new Promise(resolve => {
requestIdResolveMap.set(requestId, resolve);
const message = {
type: 'render-request',
id: requestId++,
content,
page: JSON.parse(JSON.stringify(this.page)),
};
worker.postMessage(message);
});

const outerMarkersTrimmed = trimOuterMarkers(renderedContent);
return outerMarkersTrimmed;
}
);
};

73 changes: 73 additions & 0 deletions docs/_plugins/lit-ssr/worker/worker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/**
* @license
* Copyright 2022 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/

/** @import { RHDSSSRController } from '@rhds/elements/lib/ssr-controller.js' */
/** @import { ReactiveController } from 'lit' */

import { parentPort } from 'worker_threads';
import { render } from '@lit-labs/ssr';
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
import { collectResult } from '@lit-labs/ssr/lib/render-result.js';

import { LitElementRenderer } from '@lit-labs/ssr/lib/lit-element-renderer.js';

import { ssrControllerMap } from '@rhds/elements/lib/ssr-controller.js';

if (parentPort === null) {
throw new Error('worker.js must only be run in a worker thread');
}

let initialized = false;

/**
* @param {ReactiveController} controller
* @returns {controller is RHDSSSRController}
*/
function isRHDSSSRController(controller) {
return !!controller.isRHDSSSRController;
}

parentPort.on('message', async message => {
switch (message.type) {
case 'initialize-request': {
if (!initialized) {
await Promise.all(message.imports.map(module => import(module)));
parentPort.postMessage({ type: 'initialize-response' });
}
initialized = true;
break;
}

case 'render-request': {
const { id, content, page } = message;
const result = render(unsafeHTML(content), {
elementRenderers: [
class RHDSSSRableRenderer extends LitElementRenderer {
* renderShadow(renderInfo) {
const controllers = ssrControllerMap.get(this.element);
yield controllers?.map(async x => {
if (isRHDSSSRController(x)) {
x.page = page;
await x.ssrSetup();
return [];
}
}) ?? [];
yield* super.renderShadow(renderInfo);
}
},
],
});
const rendered = await collectResult(result);
parentPort.postMessage({
type: 'render-response',
id,
rendered,
});
break;
}
}
});

3 changes: 0 additions & 3 deletions docs/_plugins/rhds.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -368,9 +368,6 @@ module.exports = function(eleventyConfig, { tagsToAlphabetize }) {
}
});

eleventyConfig.addWatchTarget('docs/patterns/**/patterns/*.html');
eleventyConfig.addWatchTarget('docs/theming/**/patterns/*.html');

for (const tagName of fs.readdirSync(path.join(process.cwd(), './elements/'))) {
const dir = path.join(process.cwd(), './elements/', tagName, 'docs/');
eleventyConfig.addWatchTarget(dir);
Expand Down
2 changes: 0 additions & 2 deletions docs/_plugins/shortcodes.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ const RenderInstallation = require('./shortcodes/renderInstallation.cjs');
const RenderLightDom = require('./shortcodes/renderLightDom.cjs');
const RenderCodeDocs = require('./shortcodes/renderCodeDocs.cjs');
const SpacerTokensTable = require('./shortcodes/spacerTokensTable.cjs');
const UxdotPattern = require('./shortcodes/uxdotPattern.cjs');

module.exports = function(eleventyConfig) {
eleventyConfig.addPlugin(RepoStatusList);
Expand All @@ -17,5 +16,4 @@ module.exports = function(eleventyConfig) {
eleventyConfig.addPlugin(RenderLightDom);
eleventyConfig.addPlugin(SpacerTokensTable);
eleventyConfig.addPlugin(RenderCodeDocs);
eleventyConfig.addPlugin(UxdotPattern);
};
113 changes: 0 additions & 113 deletions docs/_plugins/shortcodes/uxdotPattern.cjs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { UxdotPattern } from './uxdot-pattern.js';
import { isServer } from 'lit';
import { RHDSSSRController } from '@rhds/elements/lib/ssr-controller.js';

/** Hydrate the results of SSR on the client */
export class UxdotPatternSSRControllerClient extends RHDSSSRController {
allContent?: Node;
htmlContent?: Node;
jsContent?: Node;
cssContent?: Node;
hasCss = false;
hasJs = false;
constructor(host: UxdotPattern) {
super(host);
const { shadowRoot, hasUpdated } = this.host;
if (!isServer && shadowRoot && !hasUpdated) {
this.allContent ||= shadowRoot.getElementById('content')!;
this.htmlContent ||= shadowRoot.querySelector('.language-html')!;
this.jsContent ||= shadowRoot.querySelector('.language-js')!;
this.cssContent ||= shadowRoot.querySelector('.language-css')!;
this.hasCss = !this.cssContent?.textContent?.trim();
this.hasJs = !this.jsContent?.textContent?.trim();
}
}
}

Loading
Loading