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

Reduce Tailwind CSS bundle size for unused components #877

Closed
benjamincanac opened this issue Oct 27, 2023 — with Volta.net · 36 comments · Fixed by #2005
Closed

Reduce Tailwind CSS bundle size for unused components #877

benjamincanac opened this issue Oct 27, 2023 — with Volta.net · 36 comments · Fixed by #2005
Labels
enhancement New feature or request

Comments

Copy link
Member

No description provided.

@benjamincanac benjamincanac added the enhancement New feature or request label Oct 27, 2023 — with Volta.net
@benjamincanac benjamincanac added the help wanted Extra attention is needed label Oct 27, 2023 — with Volta.net
@jrutila
Copy link
Contributor

jrutila commented Oct 30, 2023

Related to #802 do you want separate issues on reducing the unused colors (this could be an option parameter, even) and reducing bundle size for unused components?

Copy link
Member Author

benjamincanac commented Oct 30, 2023

Removing unused colors is already done through Smart safelisting and I already answered here #802 (comment) on how to select only desired colors, not sure why you want to create another issue.

@jrutila
Copy link
Contributor

jrutila commented Oct 30, 2023

I read the docs and that's what nuxt/ui is trying to achieve. But it doesn't seem to work as intended so I created a bug: #889. We can continue this color discussion there and leave the ticket for the unused component thing.

@ronenteva
Copy link

Sorry to jump in, but simply adding @nuxt/ui to an empty project creates an inline css of 243kb.
Is that related to this issue or something that I'm missing from the documentation?

Copy link
Member Author

It is related to this issue, the whole config is taken into account by Tailwind: https://github.com/nuxt/ui/blob/dev/src/runtime/ui.config.ts

@jrutila
Copy link
Contributor

jrutila commented Nov 1, 2023

Is that ui.config file now available for Tailwind to do it's magic? Or does it do something more in nuxt/ui code? I am trying to scope the fix here.
If nuxt/ui would know which components the dev has used in the code it could cherry-pick those definitions from the config file for Tailwind, right?

@divine
Copy link

divine commented Nov 1, 2023

Hello,

This is pretty serious affecting performance.

@atinux can this pushed forward please?

Thanks!

@raf202
Copy link

raf202 commented Nov 1, 2023

The build size is huge when using Static Site. Weirdly, NuxtUI is adding the tailwind styles inside a <style> tag inside all .HTML files. Is something broken or am I missing something?

@ronenteva
Copy link

@benjamincanac any timeline for this?
It's labeled as enhancement but I'm sure for many this issue is a deal-breaker for using @nuxt/ui

@ineshbose
Copy link
Member

Hey! We're researching into this and hoping to come up with a breakthrough soon. 😄

@jrutila
Copy link
Contributor

jrutila commented Nov 7, 2023

The build size is huge when using Static Site. Weirdly, NuxtUI is adding the tailwind styles inside a <style> tag inside all .HTML files. Is something broken or am I missing something?

@sigmaxf I think this is more of nuxt's features. Try to fiddle with https://nuxt.com/docs/guide/going-further/experimental-features#inlinessrstyles

@ineshbose
Copy link
Member

There should be a workaround available for this now, if someone would like to report back on this please.

See "Tailwind CSS bundle" section on release notes for https://github.com/nuxt/ui/releases/tag/v2.11.0.

@ronenteva
Copy link

@ineshbose thanks! your help is highly appreciated!

I've tried excluding everything (on an empty project), and went down from 253kb to 185kb.
Big improvement but still huge for production.

Just to understand the issue, is it not possible to load nuxt ui before cssnano?

Here's what I excluded, if it helps anyone:

      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/data/table.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/accordion.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/alert.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/avatar.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/avatarGroup.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/badge.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/button.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/buttonGroup.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/chip.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/dropdown.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/kbd.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/meter.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/meterGroup.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/progress.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/forms/checkbox.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/forms/radioGroup.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/forms/radio.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/forms/toggle.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/forms/formGroup.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/forms/select.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/forms/textarea.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/forms/selectMenu.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/forms/range.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/forms/input.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/layout/card.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/layout/container.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/layout/divider.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/layout/skeleton.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/navigation/breadcrumb.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/navigation/commandPalette.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/navigation/pagination.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/navigation/verticalNavigation.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/overlays/contextMenu.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/overlays/modal.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/overlays/notification.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/overlays/notifications.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/overlays/popover.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/overlays/slideover.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/overlays/tooltip.mjs')

@jrutila
Copy link
Contributor

jrutila commented Nov 24, 2023

@ronenteva have you limited the amount of color entries in the final outcome? It has an impact, too. See #889

@ronenteva
Copy link

@jrutila thanks! it's now down to 102kb

import colors from 'tailwindcss/colors';
import {resolve} from 'pathe';

export default {
  theme: {
    colors: {
      transparent: 'transparent',
      current: 'currentColor',
      black: colors.black,
      white: colors.white,
      gray: colors.gray,
      red: colors.red,
      green: colors.green
    }
  },
  content: {
    files: [
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/data/table.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/accordion.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/alert.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/avatar.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/avatarGroup.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/badge.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/button.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/buttonGroup.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/chip.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/dropdown.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/kbd.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/meter.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/meterGroup.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/progress.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/forms/checkbox.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/forms/radioGroup.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/forms/radio.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/forms/toggle.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/forms/formGroup.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/forms/select.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/forms/textarea.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/forms/selectMenu.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/forms/range.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/forms/input.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/layout/card.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/layout/container.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/layout/divider.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/layout/skeleton.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/navigation/breadcrumb.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/navigation/commandPalette.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/navigation/pagination.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/navigation/verticalNavigation.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/overlays/contextMenu.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/overlays/modal.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/overlays/notification.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/overlays/notifications.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/overlays/popover.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/overlays/slideover.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/overlays/tooltip.mjs')
    ]
  }
};

@ineshbose
Copy link
Member

Just to understand the issue, is it not possible to load nuxt ui before cssnano?

cssnano should include all the styles from NuxtUI after build.

@ineshbose
Copy link
Member

Let me add another solution to this problem: @nuxtjs/critters

This should remove unused styles from your page, but few things to note - load this module BEFORE @nuxt/ui, and it only works for generate/prerendered pages.

@ManasMadrecha
Copy link

@ineshbose Will the critters solution work for ssr:false and npm run generate project?

@ineshbose
Copy link
Member

Will the critters solution work for ssr:false and npm run generate project?

It needs SSR enabled. Rest, you can exclude files from Tailwind content (a for-loop or even a Nuxt module would be quite elegant) for now.

@iamrevolver
Copy link

image How painful it is to look at this in 2024

@ronenteva
Copy link

@benjamincanac @ineshbose
I'm sorry to bump the issue but I want to make sure you guys understand that anyone who relies on SEO can't afford using @nuxt/ui until this is fully resolved.

@ineshbose
Copy link
Member

@ineshbose

I'm sorry to bump the issue but I want to make sure you guys understand that anyone who relies on SEO can't afford using @nuxt/ui until this is fully resolved.

Hey! Thanks for pinging - this issue is still in mind. Unfortunately content detection is a tricky part of Tailwind JIT and a component library based on Tailwind would have such limitations. We'll have to come up with some ground breaking stuff to have dynamic content based on import (contributions welcome) which all of TW community would benefit from, but till then we have a workaround available.

@ronenteva
Copy link

Let me add another solution to this problem: @nuxtjs/critters

This should remove unused styles from your page, but few things to note - load this module BEFORE @nuxt/ui, and it only works for generate/prerendered pages.

Do you mind sharing an example of how to use critters to remove the unused styles?
I couldn't get it to make any difference.

Another workaround is to use nuxt-purgecss and safelist all classes in the components in use.

Copy link
Member Author

@ronenteva Excluding all of the config files did not do the trick?

@ronenteva
Copy link

ronenteva commented Feb 27, 2024

@benjamincanac I stopped using it at some point but I honestly can't remember what wasn't working.
I'll give it another try and let you know.

Update:
I tested again, adding @nuxt/ui to a clean project and excluding all components, still adds 114kb of inline style.

@ronenteva
Copy link

If dark mode is not needed, you can save another 30k by setting:

nuxt.config.js

  colorMode: {
    preference: 'light'
  }

tailwind.config.js

  darkMode: []

@benjamincanac benjamincanac mentioned this issue Mar 4, 2024
7 tasks
@benjamincanac benjamincanac added the v3 #1289 label Mar 9, 2024
@yuzh2001
Copy link
Contributor

Providing a workaround:

  1. first, build you app and launch it.
  2. curl http://localhost:3000 (for example)
  3. copy the longest <style>line starting as /* tailwind 4.3.1 ...
  4. save it to a seperate css file and upload it to cdn
  5. in nuxt.config.js/ts, set tailwindcss:{cssPath:false}, and in app:{head:{link:{... import the css on cdn

significantly drop from ~700kb to ~160kb

(the 160kb is because another ui library I use.

@ralph-burstsms
Copy link

Any updates on this? Or is there a way for nuxt ui to only bundle tailwind classes from used nuxt ui components? This defeats the purpose of tailwind.

@yuzh2001
Copy link
Contributor

Any updates on this? Or is there a way for nuxt ui to only bundle tailwind classes from used nuxt ui components? This defeats the purpose of tailwind.

nope.

@yuzh2001
Copy link
Contributor

Any updates on this? Or is there a way for nuxt ui to only bundle tailwind classes from used nuxt ui components? This defeats the purpose of tailwind.

The key problem is that even if you only import the tailwind classes used, it's still a lot of classes considering how many tailwind classes are used in nuxt-ui. There is just no way around.

  1. SSR needs the css embed in the webpage itself rather than importing another css file.
  2. NuxtUI uses a bunch of tailwind classes.

I just gave up. There is little difference between 70kb and 700kb nowadays.

Copy link
Member Author

The only solution available at this time is to exclude components you're not using as mentioned in #877 (comment). We hope to fix this issue in v3 with the Tailwind CSS vite plugin!

@yuzh2001
Copy link
Contributor

The only solution available at this time is to exclude components you're not using as mentioned in #877 (comment). We hope to fix this issue in v3 with the Tailwind CSS vite plugin!

Having different opinions.
As long as nuxt doesn't change its inline css policy, this problem cannot be fixed.

  • for better ssr performance, nuxt will inline all style from tailwind.
  • nuxtui is a huge ui library, it will use ton of css classes.

therefore, this problem cannot be solved.

@ralph-burstsms
Copy link

Already did excluding components, and the unnecessary colors. That's better now. Thanks!

How about disabling nuxt ui on specific pages, or enabling it on some? So that SSR will only need to render this on specific pages. For example, in my case, i only use Nuxt UI for forms, and i don't need it to load in the homepage, in most of the pages actually.

@yuzh2001
Copy link
Contributor

yuzh2001 commented Aug 1, 2024

@benjamincanac The problem comes from safelisting for colors.

Tried it on the minimal playground in this repository, still generates ~250kb.

runtime/utils/color.ts:286 ...safelistByComponent['notification'](colorsAsRegex(globalColors)), import all colors and their alpha-value. If removed, ~100kb. (253Kb -> 159Kb)

runtime/utils/color.ts:283 ...baseSafelist, import primary color with its tons of <alpha-value>. If removed, ~80kb. (159Kb -> 82.19Kb)


I did read the Theming part in documentation and understand the reason for above safe-listing.

However, there should be at least one better way to resolve this problem rather than safelisting them all.

  1. Let's say the user never changed the original colors. Neither add nor remove. At this scenerio, all the safelisting colors can be extracted to an external, precompiled css file. As mentioned above, this will rescue ~180kb.
  2. (not sure if this works) follow the official tailwindcss guide,
Instead, map props to complete class names that are statically detectable at build-time:

Always map props to static class names

function Button({ color, children }) {
  const colorVariants = {
    blue: 'bg-blue-600 hover:bg-blue-500',
    red: 'bg-red-600 hover:bg-red-500',
  }

  return (
    <button className={`${colorVariants[color]} ...`}>
      {children}
    </button>
  )
}

@yuzh2001
Copy link
Contributor

yuzh2001 commented Aug 1, 2024

#2005 should fix above problem.

@martinholovsky
Copy link

@jrutila thanks! it's now down to 102kb

import colors from 'tailwindcss/colors';
import {resolve} from 'pathe';

export default {
  theme: {
    colors: {
      transparent: 'transparent',
      current: 'currentColor',
      black: colors.black,
      white: colors.white,
      gray: colors.gray,
      red: colors.red,
      green: colors.green
    }
  },
  content: {
    files: [
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/data/table.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/accordion.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/alert.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/avatar.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/avatarGroup.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/badge.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/button.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/buttonGroup.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/chip.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/dropdown.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/kbd.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/meter.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/meterGroup.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/elements/progress.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/forms/checkbox.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/forms/radioGroup.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/forms/radio.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/forms/toggle.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/forms/formGroup.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/forms/select.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/forms/textarea.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/forms/selectMenu.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/forms/range.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/forms/input.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/layout/card.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/layout/container.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/layout/divider.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/layout/skeleton.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/navigation/breadcrumb.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/navigation/commandPalette.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/navigation/pagination.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/navigation/verticalNavigation.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/overlays/contextMenu.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/overlays/modal.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/overlays/notification.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/overlays/notifications.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/overlays/popover.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/overlays/slideover.mjs'),
      '!' + resolve('node_modules/@nuxt/ui/dist/runtime/ui.config/overlays/tooltip.mjs')
    ]
  }
};

Have you considered using PurgeCSS to remove zombie classes? https://purgecss.com/guides/nuxt.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.