nuxt / bridge

πŸŒ‰ Experience Nuxt 3 features on existing Nuxt 2 projects
MIT License
270 stars 29 forks source link

Global styles are not inlined in HTML #26

Closed Destaq closed 5 months ago

Destaq commented 2 years ago

Environment


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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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.

lucassimines commented 2 years ago

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

Destaq commented 2 years ago

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

Have you been able to come up with a solution?

Tiagogv commented 2 years ago

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 commented 2 years ago

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.

phoenix-ru commented 2 years ago

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

Blakeinstein commented 2 years ago

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

<style lang="postcss">
@import '@/assets/css/main.css';
</style>
phoenix-ru commented 2 years ago

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

Blakeinstein commented 2 years ago

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 is in app.vue

phoenix-ru commented 2 years ago

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

Blakeinstein commented 2 years ago

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

phoenix-ru commented 2 years ago

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.

Blakeinstein commented 2 years ago

turns out that this also works for Nuxt 3.

Can you explain usage?

phoenix-ru commented 2 years ago

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.

Blakeinstein commented 2 years ago
npm ls vue-loader
β”œβ”€β”¬ nuxt3@3.0.0-27386975.6e06d2b invalid: "latest" from the root project
β”‚ └─┬ @nuxt/webpack-builder@npm:@nuxt/webpack-builder-edge@3.0.0-27386975.6e06d2b
β”‚   └── vue-loader@17.0.0
└── vue-loader@16.8.2 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

phoenix-ru commented 2 years ago
npm ls vue-loader
β”œβ”€β”¬ nuxt3@3.0.0-27386975.6e06d2b invalid: "latest" from the root project
β”‚ └─┬ @nuxt/webpack-builder@npm:@nuxt/webpack-builder-edge@3.0.0-27386975.6e06d2b
β”‚   └── vue-loader@17.0.0
└── vue-loader@16.8.2 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?..

Blakeinstein commented 2 years ago

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 commented 2 years ago

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.

phoenix-ru commented 2 years ago

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.

Blakeinstein commented 2 years ago

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.

shldhee commented 2 years ago

When will it be resolved??

n4an commented 2 years ago

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
  //         }
  //       }
  //     }
  //   }
  // },
Torgian commented 2 years ago

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.

phoenix-ru commented 2 years ago

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>
Torgian commented 2 years ago

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.

patrickalima98 commented 2 years ago

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

phoenix-ru commented 2 years ago

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'
);
justindasilva commented 2 years ago

@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 commented 2 years ago

My solution for now was to remove this from my nuxt.config.ts

css: [
    `~/assets/scss/index.scss`,
  ],

And add this to my layouts/default.vue

<style lang="scss">
@import '~/assets/scss/index.scss';
</style>
azelalynetan commented 2 years ago

@justindasilva I have the same issue. I tried your solution but it didn't worked for me. I'm still seeing my app being unstyled for a second after hard refresh. I'm using nuxt bridge with tailwind.

Do you have or does anyone have a suggestion or workaround for this?

enkot commented 2 years ago

I also have this issue, but when disable nitro - it works fine (inlines css in SSR):

export default defineNuxtConfig({
  ...
  bridge: {
    nitro: false,
  }
})
azelalynetan commented 2 years ago

I tried disabling the nitro and it works. I no longer encountered unstyled components for a second after reloading the page. Is there other way to fix it without disabling the nitro?

AndrewBogdanovTSS commented 2 years ago

Disabling nitro is not the solution as well as placing CSS in layouts, all of that are dirty workarounds. Nuxt Bridge should support it's default feature of referencing CSS files in nuxt config.

AndrewBogdanovTSS commented 1 year ago

@danielroe any ETA for this fix? Could it be prioritized for RC11 ?

danielroe commented 1 year ago

Just looking into this, I can't reproduce - in production - with the following config:

import { defineNuxtConfig } from '@nuxt/bridge'

export default defineNuxtConfig({
  bridge: {
    nitro: true,
    vite: false
  },
})

Note that:

  1. I can reproduce with vite enabled (as it is by default), as vite currently does not have support for inlining styles
  2. I can reproduce in development mode with webpack
AndrewBogdanovTSS commented 1 year ago

@danielroe yes, that's correct, the issue is reproducible only in development mode with Webpack, but it has to work the same as in production, right?

AndrewBogdanovTSS commented 1 year ago

@danielroe is there any issue where I could track progress on adding inline styles for Vite?

maxarias-io commented 1 year ago

This still seems to be an issue on Bridge 3.0.0-27833237.ddd8ecc with Nitro(nuxi), running yarn build && yarn start

Even with this config: https://github.com/nuxt/bridge/issues/26#issuecomment-1256707353

github-actions[bot] commented 5 months ago

Would you be able to provide a reproduction? πŸ™

More info ### Why do I need to provide a reproduction? Reproductions make it possible for us to triage and fix issues quickly with a relatively small team. It helps us discover the source of the problem, and also can reveal assumptions you or we might be making. ### What will happen? If you've provided a reproduction, we'll remove the label and try to reproduce the issue. If we can, we'll mark it as a bug and prioritise it based on its severity and how many people we think it might affect. If `needs reproduction` labeled issues don't receive any substantial activity (e.g., new comments featuring a reproduction link), we'll close them. That's not because we don't care! At any point, feel free to comment with a reproduction and we'll reopen it. ### How can I create a reproduction? We have a couple of templates for starting with a minimal reproduction: πŸ‘‰ https://stackblitz.com/github/nuxt/starter/tree/v2-bridge πŸ‘‰ https://codesandbox.io/p/github/nuxt/starter/v2-bridge-codesandbox A public GitHub repository is also perfect. πŸ‘Œ Please ensure that the reproduction is as **minimal** as possible. See more details [in our guide](https://nuxt.com/docs/community/reporting-bugs/#create-a-minimal-reproduction). You might also find these other articles interesting and/or helpful: - [The Importance of Reproductions](https://antfu.me/posts/why-reproductions-are-required) - [How to Generate a Minimal, Complete, and Verifiable Example](https://stackoverflow.com/help/mcve)
github-actions[bot] commented 5 months ago

This issue was closed because it was open for 7 days without a reproduction.