Skip to content

Commit 63cb9a6

Browse files
committed
Updates README to use Preact.
Refs #71. Also fixes a few miscellaneous things like file extensions.
1 parent 73f61b6 commit 63cb9a6

1 file changed

Lines changed: 88 additions & 68 deletions

File tree

README.md

Lines changed: 88 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@ project.
1616
Then add a workspace dependency on `@rules_prerender`. See the
1717
[releases](https://github.com/dgp1130/rules_prerender/releases/) page for the
1818
latest release and copy the snippet into your `WORKSPACE` file. Then install the
19-
`rules_prerender` NPM package.
19+
`rules_prerender` NPM package. We'll also want `@rules_prerender/preact` and
20+
[`preact`](https://www.npmjs.com/package/preact) itself to use JSX as a
21+
templating system.
2022

2123
```bash
22-
pnpm install rules_prerender --save-dev
24+
pnpm install rules_prerender @rules_prerender/preact preact --save-dev
2325
```
2426

2527
### TypeScript
@@ -77,9 +79,12 @@ load("@rules_prerender//:index.bzl", "prerender_component", "web_resources")
7779
prerender_component(
7880
name = "my_component",
7981
# The library which will prerender the HTML at build time in a Node process.
80-
srcs = ["my_component_prerender.ts"],
82+
srcs = ["my_component_prerender.tsx"],
8183
# Other `ts_project()` or `js_library()` targets used by `my_component_prerender.ts`.
82-
lib_deps = ["//:node_modules/rules_prerender"],
84+
lib_deps = [
85+
"//:node_modules/@rules_prerender/preact",
86+
"//:node_modules/preact",
87+
],
8388
# Client-side JavaScript to be executed in the browser.
8489
scripts = [":scripts"],
8590
# Styles for the component.
@@ -96,7 +101,7 @@ prerender_component(
96101
# Client-side scripts to be executed in the browser.
97102
ts_project(
98103
name = "scripts",
99-
srcs = ["my_component.ts"],
104+
srcs = ["my_component.mts"],
100105
declaration = True,
101106
deps = ["//some/other/package:ts_proj"],
102107
)
@@ -118,59 +123,57 @@ web_resources(
118123
)
119124
```
120125

121-
```typescript
122-
// my_component/my_component_prerender.ts
126+
```tsx
127+
// my_component/my_component_prerender.tsx
123128

124-
import { polyfillDeclarativeShadowDom } from '@rules_prerender/declarative_shadow_dom';
125-
import { includeScript, inlineStyle } from 'rules_prerender';
126-
import { renderOtherComponent } from '../my_other_component/my_other_component_prerender';
129+
import { polyfillDeclarativeShadowDom } from '@rules_prerender/declarative_shadow_dom/preact.mjs';
130+
import { Template, includeScript, inlineStyle } from '@rules_prerender/preact';
131+
import { VNode } from 'preact';
132+
import { OtherComponent } from '../my_other_component/my_other_component_prerender.js';
127133

128134
/**
129135
* Render partial HTML. In this case we're just using a string literal, but you
130136
* could reasonably use lit-html, React, or any other templating library.
131137
*/
132-
export function renderMyComponent(name: string): string {
133-
return `
134-
<div>
135-
<!-- Use declarative shadow DOM to isolate styles. If you're not familiar with
136-
declarative shadow DOM, you don't have to use it. But if you don't you'll need
137-
to manually namespace your styles or else styles in different components could
138-
conflict with each other! -->
139-
<template shadowroot="open">
140-
<!-- Polyfill declarative shadow DOM for any browsers which don't support it. -->
141-
${polyfillDeclarativeShadowDom()}
142-
143-
<!-- Render some HTML. -->
144-
<h2 class="my-component-header">Hello, ${name}</h2>!
145-
<button id="show">Show</button>
146-
147-
<!-- Use related web resources. -->
148-
<img src="/images/foo.png" />
149-
150-
<!-- Compose other components from the light DOM. -->
151-
<slot></slot>
152-
153-
<!-- Inject the associated client-side JavaScript. -->
154-
${includeScript('./my_component.mjs', import.meta)}
155-
156-
<!-- Inline the associated CSS styles, scoped to this shadow root. -->
157-
${inlineStyle('./my_component.css', import.meta)}
158-
</template>
159-
160-
<!-- Other components are placed in light DOM and visible at the \`<slot />\`. -->
161-
${renderOtherComponent({
162-
id: 'other',
163-
name: name.reverse(),
164-
})}
165-
</div>
166-
`.trim();
138+
export function MyComponent({ name }: { name: string }): VNode {
139+
return <div>
140+
{/* Use declarative shadow DOM to isolate styles. If you're not familiar
141+
with declarative shadow DOM, you don't have to use it. But if you
142+
don't you'll need to manually namespace your styles or else styles
143+
in different components could conflict with each other! */}
144+
<Template shadowroot="open">
145+
{/* Polyfill declarative shadow DOM for any browsers which don't
146+
support it. */}
147+
{polyfillDeclarativeShadowDom()}
148+
149+
{/* Render some HTML. */}
150+
<h2 class="my-component-header">Hello, {name}</h2>!
151+
<button id="show">Show</button>
152+
153+
{/* Use related web resources. */}
154+
<img src="/images/foo.png" />
155+
156+
{/* Compose other components from the light DOM. */}
157+
<slot></slot>
158+
159+
{/* Inject the associated client-side JavaScript. */}
160+
{includeScript('./my_component.mjs', import.meta)}
161+
162+
{/* Inline the associated styles, scoped to this shadow root. */}
163+
{inlineStyle('./my_component.css', import.meta)}
164+
</Template>
165+
166+
{/* Other components should be placed in light DOM and visible at the
167+
`<slot />`. */}
168+
<OtherComponent id="other" name={name.reverse()} />
169+
</div>;
167170
}
168171
```
169172

170173
```typescript
171-
// my_component/my_component.ts
174+
// my_component/my_component.mts
172175

173-
import { showDialog } from '../some/other/package/show_dialog';
176+
import { showDialog } from '../some/other/package/show_dialog.mjs';
174177

175178
// Register an event handler to show the other component. Could just as easily
176179
// use a framework like Angular, LitElement, React, or just define an
@@ -203,27 +206,27 @@ The second part of the rule set leverages such components to prerender an entire
203206
web page.
204207

205208
```typescript
206-
// my_page/my_page_prerender.ts
209+
// my_page/my_page_prerender.tsx
207210

208-
import { PrerenderResource } from 'rules_prerender';
209-
import { renderMyComponent } from '../my_component/my_component_prerender';
211+
import { PrerenderResource, renderToHtml } from '@rules_prerender/preact';
212+
import { MyComponent } from '../my_component/my_component_prerender.js';
210213

211214
// Renders HTML pages for the site at build-time.
212215
// If you aren't familiar with generators and the `yield` looks scary, you could
213216
// also write this as simply returning an `Array<PrerenderResource>`.
214217
export default function* render(): Generator<PrerenderResource, void, void> {
215218
// Generate an HTML page at `/my_page/index.html` with this content:
216-
yield PrerenderResource.of('/my_page/index.html', `
217-
<!DOCTYPE html>
218-
<html>
219-
<head>
220-
<title>My Page</title>
221-
</head>
222-
<body>
223-
${renderMyComponent('World')}
224-
</body>
225-
</html>
226-
`.trim());
219+
yield PrerenderResource.fromHtml('/my_page/index.html', renderToHtml(
220+
<html>
221+
<head>
222+
<title>My Page</title>
223+
<meta charSet="utf8" />
224+
</head>
225+
<body>
226+
<MyComponent name="World" />
227+
</body>
228+
</html>
229+
));
227230
}
228231
```
229232

@@ -245,7 +248,11 @@ load("@rules_prerender//:index.bzl", "prerender_pages", "web_resources_devserver
245248
prerender_pages(
246249
name = "prerendered_page",
247250
# Script to invoke the default export of to generate the page.
248-
src = "my_page_prerender.ts",
251+
src = "my_page_prerender.tsx",
252+
lib_deps = [
253+
"//:node_modules/@rules_prerender/preact",
254+
"//:node_modules/preact",
255+
],
249256
# Components used during prerendering.
250257
deps = ["//my_component"],
251258
)
@@ -307,10 +314,11 @@ more files. Take this example where we render HTML files for a bunch of markdown
307314
posts in a blog.
308315

309316
```typescript
310-
// my_blog/posts_prerender.ts
317+
// my_blog/posts_prerender.tsx
311318

312319
import * as fs from 'fs';
313-
import { PrerenderResource } from 'rules_prerender';
320+
import * as path from 'path';
321+
import { PrerenderResource, renderToHtml } from '@rules_prerender/preact';
314322
import * as md from 'markdown-it';
315323

316324
export default async function* render():
@@ -323,10 +331,22 @@ export default async function* render():
323331
// Read the post markdown, convert it to HTML, and then emit the file to
324332
// `rules_prerender` which will write it at
325333
// `/post/${post_file_name_with_html_extension}`.
326-
const postMarkdown = await fs.readFile(post, { encoding: 'utf8' });
334+
const postMarkdown =
335+
await fs.readFile(path.join(postsDir, post), 'utf8');
327336
const postHtml = md.render(postMarkdown);
328-
const htmlName = post.split('.').slice(0, -1).join('.') + '.html';
329-
yield PrerenderResource.of(`/posts/${htmlName}`, postHtml);
337+
const postBaseName = post.split('.').slice(0, -1).join('.');
338+
const htmlName = `${postBaseName}.html`;
339+
yield PrerenderResource.fromHtml(`/posts/${htmlName}`, renderToHtml(
340+
<html>
341+
<head>
342+
<title>Post {postBaseName}</title>
343+
<meta charSet="utf8" />
344+
</head>
345+
<body>
346+
<article dangerouslySetInnerHTML={{ __html: postHtml }} />
347+
</body>
348+
</html>
349+
));
330350
}
331351
}
332352
```
@@ -343,7 +363,7 @@ load("@rules_prerender//:index.bzl", "prerender_pages", "web_resources_devserver
343363
prerender_pages(
344364
name = "prerendered_posts",
345365
# Script to invoke the default export of to generate the page.
346-
src = "posts_prerender.ts",
366+
src = "posts_prerender.tsx",
347367
# Include all the markdown files at runtime in runfiles.
348368
data = glob(["posts/*.md"]),
349369
# Plain TypeScript dependencies used by `posts_prerender.ts`.

0 commit comments

Comments
 (0)