quasar icon indicating copy to clipboard operation
quasar copied to clipboard

Quasar + Nuxt3 + SSR

Open piscis opened this issue 3 years ago • 15 comments

Is your feature request related to a problem? Please describe. I would really like to integrate Quasar into Nuxt 3 with SSR mode enabled. I have a working prototype (yarn dev) that uses the Quasar Vite Plugin + Nuxt3.

The repo is here: https://github.com/piscis/nuxt-quasar-boilerplate/tree/example/quasar-vite-nuxt3-working

How every as soon as I enable SSR in nuxt.config.ts and restart vite I get the following error when my components render on the server:

window is not defined
  at $id_91abbf3f (file://./.nuxt/dist/server/server.mjs:3359:1154)  
  at async __instantiateModule__ (file://./.nuxt/dist/server/server.mjs:3812:3)

Looking at the server.mjs bundle I noticed helper referencing "window" for example:

const hasTouch="ontouchstart"in window||window.navigator.maxTouchPoints>0;

Describe the solution you'd like I would like to enable Nuxt3 SSR mode and use Quasar Components and beeing able to render Quasar Components on the server side.

Describe alternatives you've considered

  • Using Quasar SSR Mode, but it laks the massive plugin ecosystem nuxt has like: nuxt-image, nuxt-head, nuxt-recatpcha aso. Also all of the new features like deployment to Cloudflare worker aso. Are missing with quasar SSR.
  • Keep SSR disabled not really an alternative, but more of a workaround.
  • I also tried to set:
__QUASAR_SSR__: true,
__QUASAR_SSR_SERVER__: true

But that didn't help.

Additional context I think supporting Nuxt 3 instead of shipping a custom build SSR integration could expose Quasar Framework even more in the VUE/Nuxt ecosystem. Probably the new Nuxt CLI nuxi could help to build a wrapper around nuxt so quasar cli could provide similar support like it does today with capacitor / cap cli.

please note yarn build fails at the moment due to: nuxt/bridge#27

piscis avatar Oct 30 '21 16:10 piscis

@piscis link "The repo is here: https://github.com/piscis/nuxt-quasar-boilerplate/tree/example/quasar-vite-nuxt3-working" not work :(

JeRabix avatar Oct 30 '21 17:10 JeRabix

@JeRabix sorry have forgotten to make it public it should work now

piscis avatar Oct 30 '21 19:10 piscis

@rstoenescu Same issue, do we have any plans to support Nuxt3 ? thanks

webfansplz avatar Nov 08 '21 08:11 webfansplz

image Looks like a limit. Is there a support plan ?

webfansplz avatar Nov 08 '21 08:11 webfansplz

Looking at the type-definitions of the vite plugin I could find that a ssr-server and ssr-client mode could be available at some point:

Source: https://github.com/quasarframework/quasar/blob/3311a20827c4858e2a9f794ad262308b5068eac1/vite-plugin/index.d.ts#L24-L31

But I'm confused if that means that Quasar + Vite + SSR could eventually work with SSR / SSG frameworks like nuxt?

piscis avatar Nov 08 '21 09:11 piscis

https://github.com/quasarframework/quasar/issues/11231

hawkeye64 avatar Nov 08 '21 13:11 hawkeye64

I am having the same issue with quasar-app-vite and it is caused by defining quasar in noExternal, which bundles quasar.esm.prod.js which in turn is a browser build.

stefanvanherwijnen avatar Nov 15 '21 20:11 stefanvanherwijnen

~~For anyone who is interested.~~

~~https://github.com/piscis/nuxt-quasar-boilerplate/tree/example/quasar-vite-nuxt3-working ~~

~~This branch contains a Nuxt3 + Quasar setup that produces a production build.~~

~~ Spoiler:~~

Screenshot 2021-12-06 at 17 09 18

~~There are still some limitations:~~

~~1. No real SSR support due a problem with the ssr flag set to false in nuxt-config, in order to get it to work I wrapped the root element with <client-only /> and build it with SSR enabled.~~ ~~2. There is a problem mit vue vite plugin + Nuxt and the new quasar transformAssetUrls helper from quasar. I think at the moment it's not possible to use multiple vue vite plugins in nuxt and therefore using transformAssetUrls helper will break the Nuxt vite config.~~

~~But in theory its possible to get quasar working with nuxt via vite and build it.~~

Update: please see my comment here: https://github.com/quasarframework/quasar/issues/11165#issuecomment-1312528612

piscis avatar Dec 06 '21 16:12 piscis

I managed to get it working like this:

  1. In root folder (or if you are using srcDir in Nuxt's config it would be the src folder), create a plugins folder.
  2. Inside plugins folder, create a quasar.client.ts file.
  3. Inside quasar.client.ts, add the following code:
import { NuxtApp } from 'nuxt/dist/app/nuxt';
import {Quasar} from 'quasar';
import '@quasar/extras/roboto-font/roboto-font.css'
import '@quasar/extras/material-icons/material-icons.css'
import '@quasar/extras/fontawesome-v6/fontawesome-v6.css'

// Import Quasar css
import 'quasar/dist/quasar.css'

export default defineNuxtPlugin((nuxtApp: NuxtApp): unknown => {
  nuxtApp.vueApp.use(Quasar, {})
  return {
    
  }
})

(remember to run npm install quasar @quasar/extras)

  1. Everything will render, but a [Vue Warn] warnings come up about adding some Vue Compiler options to specify Quasar's components as custom components, so I finally solved this by setting ssr: false in Nuxt's config.

Even though I'm glad I finally can render Quasar in Nuxt 3, some questions came up: Why can't Quasar work SSR? Why can't Quasar be smoothly installed as a Quasar Vite Plugin if Nuxt supports Vite now?

angelhdzdev avatar Aug 03 '22 00:08 angelhdzdev

Quasar has its own SSR logic and functions which need to be handled appropriately. In contrast to most UI frameworks, Quasar has built in support for SSR and things are rendered differently depending on if its rendered on the server or the client: https://github.com/quasarframework/quasar/blob/ac8441d83dd8b2f71e80ef69c27681d8b8a2a51b/ui/src/plugins/Platform.js#L14-L20

Quasar only officially supports using @quasar/app-vite. It is possible to use Quasar SSR with Nuxt, but Nuxt will have to add support for Quasar. It definitely is possible, but not without some workarounds.

If you want to use SSR with Quasar, use Quasar CLI.

stefanvanherwijnen avatar Aug 03 '22 09:08 stefanvanherwijnen

Providing SSR rendered Quasar components to Nuxt seems pretty straight forward (replace the platform variables with the correct import.meta.env.SSR value and build from src), but in order to prevent hydration errors the generated HTML needs to be transformed.

If any experienced Nuxt user knows how to do this, it should be possible to have Quasar SSR support in Nuxt.

stefanvanherwijnen avatar Aug 08 '22 17:08 stefanvanherwijnen

Im new to Nuxt and to SSR. No idea. I just wanted to have Quasar as UI in Nuxt instead of Vuetify.

angelhdzdev avatar Aug 08 '22 18:08 angelhdzdev

For anyone who is interested.

https://github.com/piscis/nuxt-quasar-boilerplate/tree/example/quasar-vite-nuxt3-working

This branch contains a Nuxt3 + Quasar setup that produces a production build.

Not with the latest and greatest Nuxt 3 and your latest components.

, "dependencies": { "@quasar/extras": "^1.15.1", "nuxt": "^3.0.0-rc.6", "quasar": "^2.7.7" }, "devDependencies": { "@quasar/vite-plugin": "^1.1.1", "sass": "1.32.0" }

node 16.15.1

nuxt.conifg.ts => Should just be i**mport { defineNuxtConfig } from "nuxt";**

And I get these errors. Something in the syntax must have changed for registering components. I am completely new with your product and would appreciate a little help. Thanks!

[Vue warn]: Failed to resolve component: q-layout [Vue warn]: Failed to resolve component: q-header [Vue warn]: Failed to resolve component: q-toolbar [Vue warn]: Failed to resolve component: q-btn [Vue warn]: Failed to resolve component: q-toolbar-title [Vue warn]: Failed to resolve component: q-drawer [Vue warn]: Failed to resolve component: q-list [Vue warn]: Failed to resolve component: q-item-label [Vue warn]: Failed to resolve component: q-item [Vue warn]: Failed to resolve component: q-item-section [Vue warn]: Failed to resolve component: q-icon [Vue warn]: Failed to resolve component: q-page-container

TomMiller-mas avatar Aug 10 '22 03:08 TomMiller-mas

Yes sorry it turns out using quasar + vite + nuxt is a bit more challenging, and I decided to abandone Quasar as UI only solution and use something else. Also updated the comment so it's not misleading for other people looking for a solution.

piscis avatar Aug 10 '22 05:08 piscis

Everything will render, but a [Vue Warn] warnings come up about adding some Vue Compiler options to specify Quasar's components as custom components, so I finally solved this by setting ssr: false in Nuxt's config.

This solved my warning problems. It seems to be working with the original template with just two changes. Both of them are in the nuxt.config.ts.

TomMiller-mas avatar Aug 10 '22 14:08 TomMiller-mas

There is an update for Nuxt3 (now rc13) and Quasar 2 here: https://github.com/piscis/nuxt-quasar-boilerplate

By using JSDOM as server plugin and mocking browser dependencies it is now possible to run a full SSR build. But for complicated layouts using q-layout there are still hydration errors probably caused by resize observer.

Demo: https://nuxt3-quasar.piscis.io/

piscis avatar Nov 12 '22 17:11 piscis

Im new to Nuxt and to SSR. No idea. I just wanted to have Quasar as UI in Nuxt instead of Vuetify.

@Jason What was funny about my message!?

image

angelhdzdev avatar Nov 13 '22 23:11 angelhdzdev

Im new to Nuxt and to SSR. No idea. I just wanted to have Quasar as UI in Nuxt instead of Vuetify.

@Jason What was funny about my message!?

image

@angelhdzmultimedia, I found it funny because I had the exact same mindset. All the other emoticons didn't accurately describe on how I felt about your comment, so I choose the laughing one.

JasonLandbridge avatar Dec 11 '22 20:12 JasonLandbridge

Im new to Nuxt and to SSR. No idea. I just wanted to have Quasar as UI in Nuxt instead of Vuetify.

@Jason What was funny about my message!? image

@angelhdzmultimedia, I found it funny because I had the exact same mindset. All the other emoticons didn't accurately describe on how I felt about your comment, so I choose the laughing one.

Oooh. That makes sense. My apologies for being paranoid but I've received the laughing reaction before as a way of judging my answers so I'm always in full paranoia mode, also I suffer from generalized anxiety.

So cool that other people faced the same wall I faced with Nuxt+ Quasar. Hope there's an official solution soon other than disabling SSR and making then app an SPA one.

Also, I'm considering trying Quasar CLI + Vite and its SSR.

Thank you for your time! Cheers.

angelhdzdev avatar Dec 11 '22 20:12 angelhdzdev

@angelhdzmultimedia I had similar issue and went with Quasar + Vite route.

Copied most of Vite plugins from https://github.com/antfu/vitesse to make Quasar feel more like Nuxt (auto-imports of components, pages, layouts etc).

Using it's SSR with tRPC v10 for backend.

Pretty good DX, a bit slow to start due to bloat of plugins strapped.

NikolaStojicic avatar Jan 30 '23 02:01 NikolaStojicic

By using JSDOM to mock the DOM, we can use Quasar 2 with Nuxt 3. You can refer to this article for more details.

Quasar 2 with Nuxt3

import { JSDOM } from "jsdom";

const dom = new JSDOM(
  "<!DOCTYPE html><head></head><body><h1>FAKE DOM</h1></body></html>",
  {
    url: "https://example.org/",
    referrer: "https://example.com/",
    contentType: "text/html",
    includeNodeLocations: true,
    storageQuota: 10000000,
  }
);

const { XMLHttpRequest } = dom.window;
global.XMLHttpRequest = XMLHttpRequest;
// @ts-ignore
global.window = dom.window;
global.navigator = dom.window.navigator;
global.document = dom.window.document;
// @ts-ignore
global.FileList = dom.window.FileList;
global.File = dom.window.File;
global.getComputedStyle = dom.window.getComputedStyle;

export default defineNuxtPlugin((_nuxtApp): void => {});

buithaibinh avatar Jan 30 '23 02:01 buithaibinh

By using JSDOM to mock the DOM, we can use Quasar 2 with Nuxt 3. You can refer to this article for more details.

Quasar 2 with Nuxt3

import { JSDOM } from "jsdom";

const dom = new JSDOM(
  "<!DOCTYPE html><head></head><body><h1>FAKE DOM</h1></body></html>",
  {
    url: "https://example.org/",
    referrer: "https://example.com/",
    contentType: "text/html",
    includeNodeLocations: true,
    storageQuota: 10000000,
  }
);

const { XMLHttpRequest } = dom.window;
global.XMLHttpRequest = XMLHttpRequest;
// @ts-ignore
global.window = dom.window;
global.navigator = dom.window.navigator;
global.document = dom.window.document;
// @ts-ignore
global.FileList = dom.window.FileList;
global.File = dom.window.File;
global.getComputedStyle = dom.window.getComputedStyle;

export default defineNuxtPlugin((_nuxtApp): void => {});

Does not this approach disable Quasar CLI?

NikolaStojicic avatar Jan 30 '23 04:01 NikolaStojicic

@angelhdzmultimedia I had similar issue and went with Quasar + Vite route.

Copied most of Vite plugins from https://github.com/antfu/vitesse to make Quasar feel more like Nuxt (auto-imports of components, pages, layouts etc).

Using it's SSR with tRPC v10 for backend.

Pretty good DX, a bit slow to start due to bloat of plugins strapped.

Yup, same here. I went full Quasar with router/layouts/modules auto-import . Could deploy to Android with Capacitor and Desktop with Electron.

But then I got back to Nuxt 3 to check if support for Quasar was added after Vuetify 3 was released. And I realized I didn't need SSR so I turned SSR off and then Quasar worked as a SPA.

With Nuxt 3, we have the auto-imports already. No need to install bunch of packages. I hope Quasar team adds a module/plugin for Nuxt 3 so we could be free to use Quasar only as an UI library and not being tied to their ecosystem and that also they add auto-imports in Quasar Vite CLI project.

angelhdzdev avatar Jan 30 '23 05:01 angelhdzdev

Does not this approach disable Quasar CLI?

@NikolaStojicic , Yes, you cannot use quasar cli and Nuxt together. Nuxt 3 also does not support the quasar.conf.js file

buithaibinh avatar Jan 30 '23 08:01 buithaibinh

There is an update for Nuxt3 (now rc13) and Quasar 2 here: https://github.com/piscis/nuxt-quasar-boilerplate

By using JSDOM as server plugin and mocking browser dependencies it is now possible to run a full SSR build. But for complicated layouts using q-layout there are still hydration errors probably caused by resize observer.

Demo: https://nuxt3-quasar.piscis.io/

Got it working thanks. Though any ideas how to get rid of these Vue warnings? image

I followed the boilerplate carefully. Nuxt config is the same. fake-dom.server.ts is the same. quasar.client.ts is the same.

angelhdzdev avatar Feb 09 '23 06:02 angelhdzdev

Hello everybody, I did some more work on this topic and now it seems, that fully SSR support with quasar is possible. To get SSR to work I used the happy-dom package which has a far better DOM implementation as JSDOM when using it together with Quasar and Nuxt. JSDOM is not needed anymore and the implementation for the fake-dom part are basically 3 lines of code:

https://github.com/piscis/nuxt-quasar-boilerplate/blob/main/plugins/fake-dom.server.ts

A boilerplate with the full source code can be found here: https://github.com/piscis/nuxt-quasar-boilerplate/ and the demo is here: https://github.com/piscis/nuxt-quasar-boilerplate

piscis avatar Feb 09 '23 14:02 piscis

Also please note what gets promoted here https://github.com/quasarframework/quasar/issues/11165#issuecomment-1407905736 a old implementation with JSDOM. This is problematic when it comes to SSR and Quasar because some APIs quasar needs are not provided via JSDOM and lead to rehydration errors with q-layout / q-page when used with Nuxt3 + SSR

piscis avatar Feb 09 '23 14:02 piscis

@piscis What you've done is quite nice, do you think it's possible to go further and make it a nuxt module, just like element-plus?

xuzuodong avatar Feb 13 '23 03:02 xuzuodong

@xuzuodong yes that is possible I guess. The biggest problem with the current implementation is that you need to wire everything by hand in a plugin. If this is covered via a module, we would need some sort of component configuration. I already toke some inspiration from https://github.com/sfxcode/nuxt-primevue to see how they solve it for primevue

piscis avatar Feb 13 '23 11:02 piscis

Closing this as using our CLI(s) to develop SSR is the official way to go, at least for now. And this ticket is confusing some developers into thinking that Quasar does not supports SSR, which couldn't be more WRONG.

Our Vite plugin supports SSR through its params (configures all the __QUASAR__* aliases for both client and server), but it may or may not not be enough when it comes to Nuxt. Currently, we don't have time to fully investigate or create a Nuxt plugin due to the heavy load with our current tooling. This may however change in the future and we will make sure to announce it, but Nuxt is not currently on our radar because through our CLIs we have greater control over the SSR experience and we can make it be as efficient as possible.

Everyone please feel free to still comment on this thread with your findings, but again, take into account that our Vite plugin has specific params for SSR. https://github.com/quasarframework/quasar/blob/dev/vite-plugin/index.d.ts#L32

rstoenescu avatar Feb 18 '23 09:02 rstoenescu

Closing this as using our CLI(s) to develop SSR is the official way to go, at least for now. And this ticket is confusing some developers into thinking that Quasar does not supports SSR, which couldn't be more WRONG.

Our Vite plugin supports SSR through its params (configures all the __QUASAR__* aliases for both client and server), but it may or may not not be enough when it comes to Nuxt. Currently, we don't have time to fully investigate or create a Nuxt plugin due to the heavy load with our current tooling. This may however change in the future and we will make sure to announce it, but Nuxt is not currently on our radar because through our CLIs we have greater control over the SSR experience and we can make it be as efficient as possible.

Everyone please feel free to still comment on this thread with your findings, but again, take into account that our Vite plugin has specific params for SSR. https://github.com/quasarframework/quasar/blob/dev/vite-plugin/index.d.ts#L32

Thank you! I have a question: Does quasar in SSR mode, have layouts, routes/pages, and modules auto-imports, or do we still have to rely in packages like unplugin-vue-router, unplugin-auto-import, and vite-plugin-vue-layouts to achieve it?

That's the reason I've been working with Nuxt 3 lately instead of Quasar with Vite.

angelhdzdev avatar Feb 19 '23 00:02 angelhdzdev