@@ -16,10 +16,12 @@ project.
1616Then add a workspace dependency on ` @rules_prerender ` . See the
1717[ releases] ( https://github.com/dgp1130/rules_prerender/releases/ ) page for the
1818latest 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")
7779prerender_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.
97102ts_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
203206web 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>`.
214217export 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
245248prerender_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
307314posts in a blog.
308315
309316``` typescript
310- // my_blog/posts_prerender.ts
317+ // my_blog/posts_prerender.tsx
311318
312319import * as fs from ' fs' ;
313- import { PrerenderResource } from ' rules_prerender' ;
320+ import * as path from ' path' ;
321+ import { PrerenderResource , renderToHtml } from ' @rules_prerender/preact' ;
314322import * as md from ' markdown-it' ;
315323
316324export 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
343363prerender_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