Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/thescientist13/lit-v3-ssr-demo
A repo for running Lit+SSR demos using v3.
https://github.com/thescientist13/lit-v3-ssr-demo
Last synced: about 1 month ago
JSON representation
A repo for running Lit+SSR demos using v3.
- Host: GitHub
- URL: https://github.com/thescientist13/lit-v3-ssr-demo
- Owner: thescientist13
- Created: 2023-11-28T02:25:19.000Z (about 1 year ago)
- Default Branch: master
- Last Pushed: 2024-01-14T00:57:26.000Z (11 months ago)
- Last Synced: 2024-10-29T03:41:52.489Z (about 2 months ago)
- Language: JavaScript
- Size: 35.2 KB
- Stars: 0
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# lit-v3-ssr-demo
A repo for running Lit+SSR demos using v3.
## Setup
1. Clone the repo
1. Run `npm ci`## Demos
- `npm run demo:greeting`
- `npm run demo:async`
- `npm run demo:document` (server only templates example)
- `npm run demo:page` (server only "components" example, e.g. no DSD - experimental)
- `npm run demo:bundle`### Greeting ✅
This is the Greeting example taken from the [Lit playground](https://lit.dev/playground/) and following [this section of the docs](https://lit.dev/docs/ssr/server-usage/#rendering-templates) to demonstrate basic server rendering of a `LitElement`.
```js
import { html, css, LitElement} from 'lit';class SimpleGreeting extends LitElement {
static styles = css`p { color: blue }`;static properties = {
name: {type: String},
};constructor() {
super();
this.name = 'Somebody';
}render() {
return html`Hello, ${this.name}!
`;
}
}
customElements.define('simple-greeting', SimpleGreeting);
```The code is in _greeting.js_ and you can run it with `npm run demo:greeting`. The output is as expected with the attribute value being reflected in the output.
```sh
{
greetingHtml: '\n' +
' p { color: blue }Hello, World!
\n'
}
```### [Server Only Templates](https://www.npmjs.com/package/@lit-labs/ssr#server-only-templates) ✅
This is the "document" example taken from this [GitHub issue](https://github.com/lit/lit/issues/2441#issuecomment-1816903951) and following [this section of the docs](https://lit.dev/docs/ssr/server-usage/#collectresult()), primarily to demonstrate rendering a full HTML document on the server.
```js
import { render, html } from '@lit-labs/ssr';
import { collectResult } from '@lit-labs/ssr/lib/render-result.js'const template = ({ title, lang }) => html`
${title}
${title}
`;const ssrResult = render(template({ title: 'My Website', lang: 'en'}));
const ssrContent = await collectResult(ssrResult);console.log({ ssrContent });
```The code is in _document.js_ and you can run it with `npm run demo:document`, though currently getting an error about invalid locations though?
file:///Users/owenbuckley/Workspace/github/lit-v3-ssr-demo/node_modules/@lit-labs/ssr/lib/render-value.js:605
throw new Error(errorMsg);
^Error:
Unexpected final partIndex: 2 !== 3 while processing the following template:
${...}
${...}
This could be because you're attempting to render an expression in an invalid location. See
https://lit.dev/docs/templates/expressions/#invalid-locations for more information about invalid expression
locations.
edit: Looks like its the `lang=${...}` bit. If I remove it, it works fine. I guess the question is if its intentional that it should work or not in this case, since the docs do indicate [attribute are not allowed](https://lit.dev/docs/templates/expressions/#invalid-locations). Opened [an issue](https://github.com/lit/lit/issues/4417) with the Lit team.
```sh
{
ssrContent: '\n' +
' \n' +
' \n' +
' \n' +
' \n' +
' My Website\n' +
' \n' +
' \n' +
'My Website
\n' +
' \n' +
' \n'
}
```### [Async Operations](https://github.com/lit/lit/issues/2469) ❌
There are cases where doing `async` work on the server would be nice, like fetching data or reading from the filesystem. As an example:
> _This doesn't seem supported yet but a [PR is in draft](https://github.com/lit/lit/pull/4390) to expose these capabilities._
```js
import { html, css, LitElement} from 'lit';async function getGreeting() {
return Promise.resolve('ASYNC');
}class SimpleGreeting extends LitElement {
static properties = {
name: {type: String},
};async connectedCallback() {
this.name = await getGreeting();
}render() {
return html`Hello, ${until(greetingLoader)}!
`;
}
}customElements.define('simple-greeting', SimpleGreeting);
```But the contents just come out empty.
```sh
{
greetingHtml: '\n' +
'Hello, !
\n'
}
```---
> _**edit: from a call with the Lit team, they were not familiar with that `async` demo referenced and confirmed it would only have worked with hacks involved, so only current option would be to build the linked PR above from source.**_
There is also [this demo](https://github.com/PonomareVlad/lit-ssr-vercel) referenced in the linked issue, but I couldn't get it working; `greetingLoader.then` worked, but the template contents were empty. Not sure if that's because that demo is using Lit `2.x`_?
```js
import { html, css, LitElement} from 'lit';
import {until} from 'lit/directives/until.js'async function getGreeting() {
return Promise.resolve('ASYNC');
}class SimpleGreeting extends LitElement {
static styles = css`p { color: blue }`;static properties = {
name: {type: String},
};render() {
const greetingLoader = getGreeting();
greetingLoader.then(greeting => console.log({ greeting }));return html`
Hello, ${until(greetingLoader)}!
`;
}
}customElements.define('simple-greeting', SimpleGreeting);
```### Server Only Components / No DSD❓
Similar in spirit to Server Only Templates, this "page" example demonstrates what it would be like if we could use the `LitElement` component model but "unwrap" the Declarative Shadow DOM / SSR somehow and just get straight HTML, no shadow dom. The motivation is to be able to support [Greenwood's custom element as pages feature](https://www.greenwoodjs.io/blog/release/v0-26-0/#custom-elements-as-pages).
> _Though as pointed out in a call with the Lit team, that's kind of already what server only templates do I suppose, but combined with `async` support in components / SSR, this what a dynamic page server rendered could look like in a file-based routing context._
```js
// pages/products.js
import { LitElement } from 'lit';
import { html } from '@lit-labs/ssr';
import './card.js';export default class ProductsPage extends LitElement {
constructor() {
super();
this.products = [];
}// assuming this worked to escape from the Shadow DOM
createRenderRoot() {
return this;
}// assuming we get some sort of async support
async connectedCallback() {
this.products = await fetch('http://example.com/api/products').then(resp => resp.json());
}render() {
const { products } = this;return html`
${
products.map((product, idx) => {
const { title, thumbnail } = product;
return html`
`;
})
}
`;
}
}customElements.define('products-page', GreetingPage);
```As it stands, currently a couple things are a bit of an issue, based on the current output
```sh
{
ssrContent: '\n' +
' p { color: blue }Hello, World!
\n'
}
```1. [ ] We're stuck with a wrapping ``, which is part of Lit, as they are [DSD only](https://github.com/lit/lit/issues/3080). So will have to hack around that in the meantime to extract the Light DOM only content?
1. [ ] Still getting hydration markers (``) but I suppose this would be fine with or without hydration? Even when using the Server Only Templates based `html` function.## Bundling ✅
This demo is for testing the ability to entirely bundle Lit's SSR capabilities, like if bundling and deploying to a server or Lambda environment. Currently using Rollup for this and a basic test in _handler.js_.
```js
import { render } from '@lit-labs/ssr';
import { collectResult } from '@lit-labs/ssr/lib/render-result.js'
import { html } from 'lit';
import './components/simple-greeting.js';const template = (name) => html`
`;export async function handler(data) {
const { name } = data;
const ssrResult = render(template(name));
const contents = await collectResult(ssrResult);console.log({ contents });
return new Response(contents, {
headers: new Headers({
'Content-Type': 'text/html'
})
});
}(async () => {
await handler({ 'name': 'handler' });
})();
```
This was actually resolved by extending rollup.config.js nodeResolve plugin to support "node" as an exportCondition
Getting an error that `HTMLElement is undefined` from the bundled output.
➜ lit-v3-ssr-demo git:(master) ✗ npm run demo:bundle# ...
ReferenceError: HTMLElement is not defined
at file:///Users/owenbuckley/Workspace/github/lit-v3-ssr-demo/build/handler.dist.js:206:752
at ModuleJob.run (node:internal/modules/esm/module_job:193:25)
at async Promise.all (index 0)
at async ESMLoader.import (node:internal/modules/esm/loader:530:24)
at async loadESM (node:internal/process/esm_loader:91:5)
at async handleMainPromise (node:internal/modules/run_main:65:12)
Interestingly, just running the unbundled version things work fine
➜ lit-v3-ssr-demo git:(master) ✗ npm run demo:no-bundle# ...
{
contents: '\n' +
' p { color: blue }Hello, handler!
\n' +
''
}