Skip to content

Commit

Permalink
docs: ssr for uxdot-pattern (#1971)
Browse files Browse the repository at this point in the history
* docs: reduce number of file watchers

* docs: reimplement lit-ssr plugin

enable ssr for uxdot-pattern

* docs: implement ssr-able uxdot-pattern

* docs: migrate uxdot-pattern usage to ssr

* docs: fix pattern styles

* docs: headings slotted into pattern

* docs: watch for pattern files

* docs: resizable demo container

* chore: core patch

* chore: remove extra file

* docs: uxdot-pattern review comments

* docs(tabs): patterns

* docs: uxdot-pattern is not a provider

Rather, it's color-palette attribute forwards to the internal rh-surface

* docs: uxdot-pattern hydrate ssr state on client

* docs: uxdot pattern responsive padding

* docs: uxdot-pattern attrs

* docs: pattern usage

* feat: make generic ssr controller

* chore: update pfe-core patch

see patternfly/patternfly-elements#2863

* chore: update deps

* style: whitespace

* chore: update deps
  • Loading branch information
bennypowers authored Oct 9, 2024
1 parent 31a0852 commit 2ecc6c9
Show file tree
Hide file tree
Showing 34 changed files with 774 additions and 477 deletions.
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

0 comments on commit 2ecc6c9

Please sign in to comment.