vuetify-module icon indicating copy to clipboard operation
vuetify-module copied to clipboard

Critical CSS and theme CSS not included in the SSR response; instead applied at runtime which causes a FOUC

Open Janne252 opened this issue 5 years ago • 19 comments

Module version

"dependencies": {
    "@nuxtjs/vuetify": "^1.9.1",
    "nuxt": "^2.11.0"
}

Describe the bug Vuetify critical CSS and theme CSS are not included in the SSR response. Instead they are applied at run time which causes a flash of unstyled content (FOUC). Vuetify explicitly states that the theme CSS should be included in the SSR response:

Vuetify generates theme styles at run-time for SPA's and server side for SSR applications. The generated styles will be placed in a

https://next.vuetifyjs.com/en/customization/theme#options

To Reproduce Clone https://github.com/Janne252/issue-nuxt-vuetify-theme-missing-in-ssr-response and follow instructions on the readme.md.

Steps to reproduce the behavior: See readme.md on the reproduction repository.

Expected behavior Critical Vuetify CSS and theme CSS should be included in the SSR response. Instead they are applied at runtime, which causes a FOUC.

Screenshots Result:

Expected:

Janne252 avatar Dec 18 '19 11:12 Janne252

I managed to work around that by disabling the theme behavior and manually injecting the styles using the head function in my main layout. I'm afraid this recalculates the theme's CSS on every page view (server & client), though, but it's not really a performance issue.

// nuxt.config.js
{
  vuetify: {
    ...myOtherOptions,
    theme: {
      disable: true,
    },
  },
}
// layouts/default.vue
head() {
  return {
    style: [{
      hid: "vuetifyTheme",
      type: "text/css",
      cssText: this.$vuetify.theme.generatedStyles,
    }],
  }
},

erkstruwe avatar Jan 03 '20 10:01 erkstruwe

I investigated things last months, and I found that overall the issue is that Vuetify Components import their css inside their source code (at top of TypeScript source of components). At compilation time it bundles CSS in JS, and even if using extractCSS nuxt build option, it's still different how it is handles VS when css is specified in a Vue SFC (CSS is taken through vue compiler this way).

I created a repository with reproduction which doesn't include Vuetify but showcase that having CSS imported in JS instead of using Vue SFC, ends up in different behavior and makes the FOUC happens (in my repository case, we can see text turning black to red instead of being red directly, meanwhile everything is fine for the green text).

There are explanations in the README of the repistory.

Repository link : https://github.com/kevinmarrec/nuxt-css-issue

kevinmarrec avatar Jan 10 '20 10:01 kevinmarrec

This issue also seems to be a duplicate of #208, or at least is related.

kevinmarrec avatar Jan 10 '20 10:01 kevinmarrec

The workaround described in the related issue https://github.com/nuxt-community/vuetify-module/issues/208#issuecomment-564503274 by DispatchCommit (manually include ALL vuetify css in nuxt) can be used to fix all FOUC issues when combined with erkstruwe's workaround https://github.com/nuxt-community/vuetify-module/issues/232#issuecomment-570532783.

I would consider the combination of these 2 workarounds as an acceptable solution until the root cause of the issue is fixed.

Janne252 avatar Jan 11 '20 09:01 Janne252

Hello @kevinmarrec, do you know if there is any update on this?

asennoussi avatar Mar 27 '20 05:03 asennoussi

2nd this. SSR looks to still be excluding critical css from Vuetify. I upgraded to the latest Nuxt version, with SSR: true and still experience a healthy chunk of the CSS not showing up in production. It does show up in dev mode though.

TheScree avatar Apr 08 '20 03:04 TheScree

I experience something similar, I have a page with several async components. Most of the async components have their own (scoped) css, but just one of it does not export the css on ssr. When client hydration kicks in the css is applied.

It's not related to scoped css, if I kick out the scoped parameter there is no difference. I couldn't find any reason why exactly this one component is not working.

We use extractcss. Would say the issue is the same as the one with vuetify, except we do not use js css includes, but Vue sfc templates.

simllll avatar May 01 '20 09:05 simllll

I have tried the above workaround and it still doesn't seem to be working for me. Further updates on this would be much appreciated

JosephSaw avatar Jun 24 '20 01:06 JosephSaw

Also having a major layout shift in our target: static configured application. Simple css like the centering of containers is loading too late.

Our current workaround is in nuxt.config.js - build

splitChunks: {
  pages: false
},

This enforces the css to be inline for the index.html.

Unfortunately even with treeshaking and such, it still contains a lot of styling we do not use in our application. But that is another problem ;)

ItsMeDelanoDev avatar Jul 20 '20 14:07 ItsMeDelanoDev

Still having this issue, mode: 'universal' + target: 'static'..

My current workaround is extractCSS: true:

// nuxt.config.js

export default {
  // ...
  build: {
    extractCSS: true,
  },
};

1isten avatar Aug 31 '20 16:08 1isten

why this issue still open ? is vuetify still can not use for SSR's method ?

RioChndr avatar Mar 15 '21 08:03 RioChndr

Still having the same issues with a newly created project with Nuxt, Typescript and Vuetify. Is there any plan to fix this critical bug?

cprcrack avatar Mar 24 '21 13:03 cprcrack

Also experiencing this issue. the necessary css is being loading in a js and applied at run time.

hyrumwhite avatar May 06 '21 23:05 hyrumwhite

+1

vedraan avatar May 13 '21 16:05 vedraan

+1

husniramdani avatar Sep 14 '21 16:09 husniramdani

+1

romainfd avatar Feb 18 '22 13:02 romainfd

+1

Val-istar-Guo avatar Apr 17 '22 10:04 Val-istar-Guo

Got the same issue with the default nuxt vuetify setup, SSR mode and only in production.

This workaround works for me

  // Build Configuration: https://go.nuxtjs.dev/config-build
  build: {
    splitChunks: {
      pages: false
    }
  }

N0K0 avatar May 29 '22 20:05 N0K0

If anyone is experiencing this issue in vike/vite-plugin-ssr, you have to handle Vuetify theme styles manually, here is my rough draft solution using unjs/unhead for my app (your milage may vary.)

import { createHead } from 'unhead'

...
  const app = createSSRApp(PageWithWrapper)
  const head = createHead()

  // vuetify theme ssr
  // comaptibility manager
  app.provide('usehead', {
    push(getHead: Function) {
      console.log('push')
      head.push(getHead())
      return {
        patch(getHead: Function) {
          console.log('patch')
        },
      }
    },
  })

  // init vuetify
  app.use(vuetify)
...

then render the tags where they need to go (e.g. headtags, bodytags, etc)

...
  const app = createApp(ctx)
  const rendered = await renderSSRHead(app.head)
  const str = await renderToString(app)
  const documentHtml = escapeInject`
    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8">
        <meta name="description" content="" />
        <title>${title}</title>
        <link rel="icon" type="image/x-icon" href="/favicon.ico">
        <link rel="preconnect" href="https://fonts.googleapis.com">
        <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
        <link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@100;300;400;500;700;900&display=swap" rel="stylesheet">
        <link href="https://cdnjs.cloudflare.com/ajax/libs/MaterialDesign-Webfont/7.2.96/css/materialdesignicons.min.css" rel="stylesheet">
        ${dangerouslySkipEscape(rendered.headTags)}
      </head>
      <body>
        <div id="app">${dangerouslySkipEscape(str)}</div>
      </body>
    </html>`
...

**I know this is a nuxt community, but wanted to leave this message in case anyone else hits this issue w/ a custom SSR solution.

neutrino84 avatar Nov 27 '23 00:11 neutrino84