Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Imported CSS files not correctly injected in circumstances involving lazy-loaded components #27417

Open
tibineagu opened this issue May 31, 2024 · 1 comment

Comments

@tibineagu
Copy link

Environment

Nuxt project info: 19:03:45


  • Operating System: Linux
  • Node Version: v18.20.3
  • Nuxt Version: 3.11.2
  • CLI Version: 3.11.1
  • Nitro Version: -
  • Package Manager: npm@10.2.3
  • Builder: -
  • User Config: devtools, build
  • Runtime Modules: -
  • Build Modules: -

Reproduction

Minimal reproduction here

  • Run pnpm run build && pnpm run preview
  • Open the preview in a new tab
  • Open the network tab and throttle your network to something like "Slow 3G"
  • Refresh the page and notice that the styles for some sections are loaded after page load, causing FOUC and CLS
  • Look at the page source
    • notice that there is a <style> tag in the <head> containing ONLY the (correctly) inlined styles of the WorkingLocalComponent
    • notice there are no other styles included in the head
  • Look at the network requests and notice that there is an index.[hash].css file that is loaded, except the initiator for this is a .js file.

Describe the bug

When a page contains a component that's used multiple times, including once inside a lazy-component on the same page, nuxt will fail to correctly inject the styles that are imported by other components on the page.

The bug manifests when the styles are imported in the JS code, and not if they are part of the SFC's <style> tag. Please see the "Additional context" section for why this is important.

There are actually two different aspects of this bug:

  • style files imported in components that are exported as JS modules by a third-party library
    • the bug will always manifest
  • style files imported in components on the same Nuxt repo
    • the bug will manifest if the imported file requires a pre-processor like LESS or SASS (not for plain CSS files)

This is a very complex set of circumstances, so I will try to explain using the components used in the reproduction repository.

  • ReusedComponent - its contents is irrelevant, you can imagine it as very simple component, including even something like a "terms" fine print block.
    • the important part is that this component is used as-is on the page itself, but also rendered inside a lazy-loaded component
  • ComplexComponent - this is an optional component that might eventually get rendered; it includes ReusedComponent
    • the important part is that it's included on the page using the <lazy prefix
  • WorkingLocalComponent - this is a component that imports a .css file in the <script> section
    • this is unaffected by the bug
    • the styles in the CSS file are correctly inlined in the server-rendered HTML
  • BrokenLocalComponent - this is a component that imports a .less file in the <script> section
    • the styles in the LESS file are not inlined in the HTML
    • they are processed and extracted in the index.[hash].css file that gets injected in the document by a .js file on page load
  • One - this is a component that's part of a third-party Vue library
    • with regards to the library's internal code structure
      • the styles for this particular component are extracted in the dist/assets/One.css file, BUT:
      • that file is imported in dist/components/buttons/One.js so there is no overhead for the developers to manually import styles
    • with regards to the nuxt build:
      • the styles for this component are not inlined by Nuxt in the server-rendered HTML
      • they are extracted in the index.[hash].css file that gets injected in the document by a .js file on page load

Interesting tid-bits

  • Ways to make the bug go away (neither of which are really acceptable solutions):
    • remove ReusedComponent from ComplexComponent, or
    • use ComplexComponent on the page in a classic fashion (not "lazy")
  • In both of the situations above, the index.[hash].css file is included as a <link rel="stylesheet" in the <head>
    • this partially solves the FOUC issue but is suboptimal
    • it's peculiar that the styles are not inlined in a <style> tag

Expected behaviour

Any styles for components that are rendered on the page on load should be inlined in the <style> tag

Additional context

This is most relevant in the case of UI libraries that compile their components into JS files where the styles specific to each component are imported (e.g. using the vite-plugin-lib-inject-css plugin).

We generated a minimal demo library here, and you can see the aspect of the build code in the dist/components/button/One.js file, which imports dist/assets/One.css including the styles specific only to that particular component.

Logs

No response

Copy link

stackblitz bot commented May 31, 2024

Fix this issue in StackBlitz Codeflow Start a new pull request in StackBlitz Codeflow.

@danielroe danielroe removed the 3.x label Jun 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants