vuetify-module
vuetify-module copied to clipboard
Critical CSS and theme CSS not included in the SSR response; instead applied at runtime which causes a FOUC
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:
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,
}],
}
},
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
This issue also seems to be a duplicate of #208, or at least is related.
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.
Hello @kevinmarrec, do you know if there is any update on this?
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.
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.
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
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 ;)
Still having this issue, mode: 'universal'
+ target: 'static'
..
My current workaround is extractCSS: true
:
// nuxt.config.js
export default {
// ...
build: {
extractCSS: true,
},
};
why this issue still open ? is vuetify still can not use for SSR's method ?
Still having the same issues with a newly created project with Nuxt, Typescript and Vuetify. Is there any plan to fix this critical bug?
Also experiencing this issue. the necessary css is being loading in a js and applied at run time.
+1
+1
+1
+1
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
}
}
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.