[labs/ssr] Feature request: Nuxt 3 SSR Integration
See original GitHub issueDescription
In the Lit & Friends Slack, I read Next and Remix integration DX is fairly high on the task list of the Lit team. I would also love to see this for Nuxt 3 (ESM only and currently in RC).
Note that the Nuxt 3 server, called Nitro, is cross-platform and not only supports Node, but also Deno, Workers, and more.
Steps to Reproduce
Live Reproduction Link
In this reproduction, I use the Nord web components (built with Lit).
https://stackblitz.com/edit/nuxt3-with-nord-ssr?file=plugins%2Fnord.ts
Expected Results
I know the web components depend on browser API’s that are not available in a server context, so I would expect errors. But I would love to be able to SSR the web components with Declarative Shadow DOM, and hydrate them on the client side (I know this is no trivial task).
Actual Results
Error is thrown: window is not defined
.
When I import @lit-labs/ssr/lib/install-global-dom-shim.js
beforehand, the window is not defined
error goes away, but then this error is thrown: matchMedia is not defined
. So, a shim for matchMedia seems to be missing.
Also please note this paragraph in the Vue docs:
Note that if a third-party library is not written with universal usage in mind, it could be tricky to integrate it into a server-rendered app. You might be able to get it working by mocking some of the globals, but it would be hacky and may interfere with the environment detection code of other libraries.
Notes
For now, I got Nuxt 3 SSR working by importing/defining the components dynamically on the client side after hydration: https://stackblitz.com/edit/nuxt3-with-nord-ssr-with-client-side-custom-elements?file=plugins%2Fnord.ts
Larger POC available on https://github.com/elwinvaneede/nuxt3-with-nord and running on https://nuxt3-with-nord.netlify.app/.
The web components need to be defined after the Vue hydration; otherwise you get hydration warnings where the client DOM differs from the server DOM. The app:mounted
lifecycle hook seemed to be working for this, but with a bit larger application with pages and nested components, some hydration warnings would start appearing. Using the page:finish
lifecycle hook instead of app:mounted
seemed to solve this.
But this solution doesn’t work together with the bundling/tree-shaking of Nuxt, because of the dynamic nature. And of course, the interface is only visible after hydration is done and the web components are imported/defined.
In an ideal situation, I would like to cherry-pick the components I need in the pages/components with a static import (for example import '@nordhealth/components/lib/Button.js'
or even better with the upcoming Vue wrappers for optimal DX such as typings in templates: import { Button } from '@nordhealth/vue'
). And then Nuxt does all the bundling & tree-shaking, and Lit’s Nuxt integration handles the SSR & hydration of the web components.
FYI: Injecting an HTML string into a spot during SSR is possible with v-html.
Happy to help where I can, and if you need any more information, please let me know.
Issue Analytics
- State:
- Created a year ago
- Comments:6 (3 by maintainers)
Top GitHub Comments
@elwinvaneede @prashantpalikhe and I are working on a Nuxt 3 plugin https://github.com/prashantpalikhe/nuxt-ssr-lit
It’s pre-release at the moment but looking promising
@elwinvaneede we’ve made the first release of nuxt-ssr-lit for Nuxt 3. Please test it out and provide feedback!