bridge icon indicating copy to clipboard operation
bridge copied to clipboard

Global styles are not inlined in HTML

Open Destaq opened this issue 2 years ago • 40 comments

Environment


  • Operating System: Darwin
  • Node Version: v14.17.4
  • Nuxt Version: 2.15.8
  • Package Manager: npm
  • Bundler: Webpack
  • User Config: head, css, plugins, bridge, components, buildModules, modules, build
  • Runtime Modules: [email protected], @nuxtjs/[email protected]
  • Build Modules: @nuxt/[email protected]

Describe the bug

TailwindCSS plugins requirements are not being loaded as they should, being run only after the plugin has been rendered. For this specific case, I'm using the TailwindCSS framework which is being enhanced by DaisyUI.

However, there is an initial flicker from TailwindCSS styling to DaisyUI after the page loads. See below recording:

https://user-images.githubusercontent.com/61620873/137582807-4ec2eec8-ab0a-437c-a15d-642447fda13a.mov

I brought up this issue on the DaisyUI repo here: https://github.com/saadeghi/daisyui/issues/249, but the creator noted that it was an issue with a lack of details on Nuxt 3 and Bridge documentation. They provided a working example for Nuxt 3 in addition to that for Nuxt 2, but neither is functional in Bridge.

Reproduction

Modified NuxtJS Bridge example.

Additional context

No response

Logs

No response

Destaq avatar Oct 18 '21 20:10 Destaq

I've noticed that if you throw an error inside of nuxtServerInit, as so:

export const actions = {
  async nuxtServerInit({ commit }, { req }) {
    throw new Error('Makes DaisyUI work');
  }
}

However, this obviously isn't a good solution. However, it may help in identifying the problem with Nuxt Bridge.

Destaq avatar Oct 20 '21 11:10 Destaq

If you set disable Tailwind's JIT mode, then there is a slightly different result.

Instead of there being a short flicker, the screen freezes on the unrendered, pre-plugin styling, and then styles everything. From there, in-app navigation works without styling issues - this only happens on page loading. This leads me to believe that Tailwind plugin style loading is somehow failing to block the page render.

https://user-images.githubusercontent.com/61620873/140575036-3c908585-51b7-4e77-b63f-22a8477a4e7b.mov

Destaq avatar Nov 05 '21 20:11 Destaq

Any chance of this getting addressed anytime soon?

I've been hesitant to continue working with Nuxt Bridge since there's been no fix to this Nuxt-caused issue for the past month.

Destaq avatar Nov 18 '21 20:11 Destaq

I'm facing the same issue with Tailwind and Nuxt 3

lucassimines avatar Nov 24 '21 14:11 lucassimines

I'm facing the same issue with Tailwind and Nuxt 3

Have you been able to come up with a solution?

Destaq avatar Dec 16 '21 22:12 Destaq

Any news on this bug? I figured out that any global styles that you define in the css property on nuxt.config are added to the page by a script and not inlined in the HTML on SSR.

This causes a flicker because the page is first shown without any styles and then the styles are loaded. This is also true if you generate static pages using nuxi generate using Nuxt Bridge. I tried to compile tailwindcss using the Tailwind CLI and the using the compiled output on nuxt.config -> Got the same result.

Would be a lot better if the global styles were added inline the same way style defined in the components are added.

Tiagogv avatar Jan 25 '22 00:01 Tiagogv

I found a workaround to remove the flickering. Instead of adding the global tailwind css file to nuxt.config css property, I have imported it into my layouts/default.vue file like so:

<style lang="postcss">
@import '@/assets/css/main.css';
</style>

This way the tailwindcss is inlined into the final HTML and not loaded with <link rel="preload">. The only drawback is that your HTML file becomes bigger. However my Lighthouse performance went from a 70 to a 92 because it no longer has a poor CLS score.

If you have more than one layout, you need to add this to every layout.

Tiagogv avatar Jan 26 '22 02:01 Tiagogv

Adding styles to layouts seems a reasonable workaround, however, it leads to style duplication (even when using sass @use which should theoretically dedupe). Inlining styles from NuxtConfig.css is something we really need

phoenix-ru avatar Jan 31 '22 18:01 phoenix-ru

Why not add the following to app.vue? instead of layouts?

<style lang="postcss">
@import '@/assets/css/main.css';
</style>

Blakeinstein avatar Feb 01 '22 14:02 Blakeinstein

Why not add the following to app.vue? instead of layouts?

<style lang="postcss">
@import '@/assets/css/main.css';
</style>

I think the role of app.vue is actually the same as of layouts/default.vue If not, I would be happy to be wrong

phoenix-ru avatar Feb 01 '22 16:02 phoenix-ru

I think the role of app.vue is actually the same as of layouts/default.vue

Not really, IIRC app.vue is the application entrypoint, and will be the first to render, any layout would be rendered in the place where <NuxtPage /> is in app.vue

Blakeinstein avatar Feb 01 '22 17:02 Blakeinstein

I am not really sure, but I think docs need to be updated then to indicate what is the role of app.vue other than replacing a single layout file.

http://v3.nuxtjs.org/docs/directory-structure/layouts

phoenix-ru avatar Feb 02 '22 05:02 phoenix-ru

I still dont think adding critical css files in app.vue is still the way to go. It results in a poor lighthouse score (as this is claimed to be bad js) and has partially resulted in this somehow? https://github.com/FortAwesome/vue-fontawesome/issues/342

Which is also the reason behind an initial flicker. when markup is loaded but the css is loaded when js executes.

A critical problem lies here because the vite bundler doesnt support dynamic glob imports (in the style of nuxt2)

Edit: I clearly missed the bridge tag on this issue, but this seems to occur on nuxt3 with vue3 too

Blakeinstein avatar Feb 02 '22 18:02 Blakeinstein

The flicker issue (on webpack at least) is related to the missing SSR critical CSS collection in vue-loader v16. I have managed to work around this by using a fork which adds naive inlining: https://github.com/phoenix-ru/vue-loader. I've written it for Vue 3 SSR but turns out that this also works for Nuxt 3. The Bridge works without any FOUCs though.

phoenix-ru avatar Feb 02 '22 18:02 phoenix-ru

turns out that this also works for Nuxt 3.

Can you explain usage?

Blakeinstein avatar Feb 02 '22 18:02 Blakeinstein

You need to install the packaged tarball in place of vue-loader and check that npm resolves to the patch.

npm i -D vue-loader@https://github.com/phoenix-ru/vue-loader/releases/download/critical-css/vue-loader.tgz

npm ls vue-loader

Beware that this patch only works for webpack (config.vite=false) and may introduce style duplication with Nuxt (or may not)

You can check the source code at https://github.com/phoenix-ru/vue-loader/tree/critical-css. Sorry for an inconvenient structure, this is a dirty patch and I had no time to update it for a merge request.

phoenix-ru avatar Feb 03 '22 05:02 phoenix-ru

npm ls vue-loader
├─┬ [email protected] invalid: "latest" from the root project
│ └─┬ @nuxt/webpack-builder@npm:@nuxt/[email protected]
│   └── [email protected]
└── [email protected] invalid: "https://github.com/phoenix-ru/vue-loader/releases/download/critical-css/vue-loader.tgz" from the root project

npm ERR! code ELSPROBLEMS

still good? I am using yarn and add this as a dependency instead of a dev dependency

Blakeinstein avatar Feb 03 '22 09:02 Blakeinstein

npm ls vue-loader
├─┬ [email protected] invalid: "latest" from the root project
│ └─┬ @nuxt/webpack-builder@npm:@nuxt/[email protected]
│   └── [email protected]
└── [email protected] invalid: "https://github.com/phoenix-ru/vue-loader/releases/download/critical-css/vue-loader.tgz" from the root project

npm ERR! code ELSPROBLEMS

still good? I am using yarn and add this as a dependency instead of a dev dependency

Seems like Nuxt has updated the loader to v17. I guess you could still use it?..

phoenix-ru avatar Feb 03 '22 12:02 phoenix-ru

Seems like Nuxt has updated the loader to v17. I guess you could still use it?..

Doesnt seem like it. Additionally, I cant even import things like windi-css which use virtual to mount css (which cannot be resolved in a style context). Proper style resolution is the only thing, as far as I can see that is stopping nuxt3 from being used in production, mainly because of the weird initial flicker that visitors experience.

Blakeinstein avatar Feb 04 '22 09:02 Blakeinstein

I am not really sure, but I think docs need to be updated then to indicate what is the role of app.vue other than replacing a single layout file.

The docs apparently do suggest the same, https://v3.nuxtjs.org/docs/directory-structure/app

Remember that app.vue acts as the main component of your Nuxt application. Anything you add in it (JS and CSS) will be global and included in every page.

Blakeinstein avatar Feb 05 '22 10:02 Blakeinstein

I cant even import things like windi-css which use virtual to mount css

Could you elaborate more on that please?

The patch I did is naive and works by providing the styles from the SFC to the SSR context in a beforeCreate hook via importing the SFC dependencies. It was initially developed to overcome the FOUC when loading modules through Webpack 5 Module Federation.

Note that it does not really inject the styles, as that is done by Nuxt, but only provide them to the context (and that's the reason I assume that I move in the right direction). The critical CSS collection is tricky and hasn't been solved since the introduction of vue-loader v16.

I know that windicss uses JIT-like compilation, but I haven't checked their webpack implementation (https://github.com/windicss/windicss-webpack-plugin).

I'd really like to contribute to Nuxt and to Vue renderer in general by solving this problem because we already invested a big chunk of time and resources and seeing Nuxt introduce breaking changes is something we really want to avoid.

P.S. I have no information about the Vite implementation and will not be looking there.

phoenix-ru avatar Feb 05 '22 17:02 phoenix-ru

I cant even import things like windi-css which use virtual to mount css

Could you elaborate more on that please?

Ah apologies, I didnt intend to point anything on your implementation, my statement was more in general towards nuxt.

I just tested vite with windicss, and it actually seems to work as intended. (Granted i still cant use taildwindcss/ui with windicss). Overall my intention was that anything that goes to the css field in config, should also be uglified if possible. (https://github.com/FortAwesome/vue-fontawesome/issues/342, this issue is a thorn on my end, as the css is shipped in js somehow, and is very large in size) Lighthouse even complains for the same.

Blakeinstein avatar Feb 05 '22 17:02 Blakeinstein

When will it be resolved??

shldhee avatar Mar 04 '22 13:03 shldhee

When will it be resolved??

In october 2021 i used i think

  // build: {
  //   optimization: {
  //     runtimeChunk: true,
  //     splitChunks: {
  //       maxSize: 240000,
  //       name: true,
  //       cacheGroups: {
  //         styles: {
  //           name: 'styles',
  //           test: /\.(css|vue)$/,
  //           chunks: 'all',
  //           enforce: true
  //         }
  //       }
  //     }
  //   }
  // },

n4an avatar Apr 11 '22 13:04 n4an

I've tried quite a few different things to try to resolve this issue on my own project;

  1. Add the css file in an app.vue file
  2. Add the css to the default.vue layout
  3. Import it in the style block
  4. Original css import in Nuxt.config did not seem to work

Basically, css seemed to work fine in nuxtjs. But, after adding Nuxt Bridge, we get that flash of un-styled pages when doing a hard refresh of the browser.

Haven't found a solution. Pretty much stuck at this point.

Torgian avatar Apr 14 '22 12:04 Torgian

I've tried quite a few different things to try to resolve this issue on my own project;

Hi, in my setup everything works fine when adding it via SCSS to layouts/default.vue and all other layout files (Nuxt Bridge):

<style lang="scss">
@use './my_styles.css';
</style>

phoenix-ru avatar Apr 14 '22 17:04 phoenix-ru

I've tried quite a few different things to try to resolve this issue on my own project;

Hi, in my setup everything works fine when adding it via SCSS to layouts/default.vue and all other layout files (Nuxt Bridge):

<style lang="scss">
@use './my_styles.css';
</style>

Thanks for the reply, but this did nothing for me. I even tried setting the styles directly in the default.vue file for my default layout, but this also did nothing. It has something to do with processing the style and setting it before the screen renders. This has never been a problem before attempting to update to bridge.

As it is, this, as well as an issue with nuxt auth compatibility makes bridge a non-starter for our app.

Torgian avatar May 18 '22 04:05 Torgian

I've tried quite a few different things to try to resolve this issue on my own project;

Hi, in my setup everything works fine when adding it via SCSS to layouts/default.vue and all other layout files (Nuxt Bridge):

<style lang="scss">
@use './my_styles.css';
</style>

HI, this works for me, but I get a new error when my CSS is from my node_modules with relative paths for font-files, like the bellow screenshot.

image

patrickalima98 avatar Jun 06 '22 00:06 patrickalima98

I've tried quite a few different things to try to resolve this issue on my own project;

Hi, in my setup everything works fine when adding it via SCSS to layouts/default.vue and all other layout files (Nuxt Bridge):

<style lang="scss">
@use './my_styles.css';
</style>

HI, this works for me, but I get a new error when my CSS is from my node_modules with relative paths for font-files, like the bellow screenshot.

image

This is not related to the topic, but I had the same issue. If that is your library, make sure you either set webpack's publicPath to the name of your library (e.g. publicPath: '@yourscope/yourlib') or you do a construction like this:

// your_library.scss
$module-path: '@' !default; // or any alias to project root

// same file, in your font-face definition
src: url(#{$module-path}/path/to/font)

// when consuming (e.g. in nuxt)
@use '@yourscope/yourlib/your_library.scss' with (
  $module-path: '@yourscope/yourlib'
);

phoenix-ru avatar Jun 06 '22 04:06 phoenix-ru

@pi0 Any ideas for us on this one? Whenever I do a hard refresh, I get about a second of the app being unstyled. Wondering what the solution might be.

justindasilva avatar Jun 23 '22 16:06 justindasilva