saadeghi / daisyui

๐ŸŒผ ๐ŸŒผ ๐ŸŒผ ๐ŸŒผ ๐ŸŒผ โ€ƒThe most popular, free and open-source Tailwind CSS component library
https://daisyui.com
MIT License
33.18k stars 1.27k forks source link

bug: All component's CSS ends up in build output? #1672

Closed gkatsanos closed 1 year ago

gkatsanos commented 1 year ago

What version of daisyUI are you using?

latest

Describe your issue

Is it safe to assume that once a specific component is used in the HTML, the daisyUI css isnt purged on a selector-level like typical tailwind utility classes would be, but all component's classes will be included in the final bundle?

What browsers are you seeing the problem on?

No response

Reproduction URL (optional)

No response

saadeghi commented 1 year ago

Tailwind CSS does the purge. So it works just like other Tailwind CSS class names. Unused class names will not be included in the production.

Let me know if you have any questions

gkatsanos commented 1 year ago

@saadeghi could you kindly point me to the tailwind/config in this library that manages the purging? context: we are trying to get inspiration from your library for a much more limited - internal tailwind extension that creates just a handful of prestyled 'components' for internal usage.. (I know that's not in the scope of this issue tracker but I'd appreciate it!)

saadeghi commented 1 year ago

daisyUI component styles are added to Tailwind using Tailwind's addComponents() function. After that, component styles (just like every other Tailwind CSS style) will only be included in the CSS file if Tailwind CSS finds its class name inside your markup files.
So, purging is handled by Tailwind. As long as you add styles to Tailwind CSS using the plugin API, Tailwind handles them for you as well. Otherwise you can use an external Post CSS plugin like Purge CSS.

Let me know if you have any questions

saadeghi commented 1 year ago

It's in this file: https://github.com/saadeghi/daisyui/blob/master/src/index.js

But this file is a little complex. You can see the simpler usage of that function on the Tailwind CSS docs I mentioned.

gkatsanos commented 1 year ago

Quick question, looking at https://github.com/saadeghi/daisyui/blob/master/package.json#L77 and running the build locally I see that the end result is one css file basically is this the end file imported into the apps and then tailwind does the purging? just trying to understand what the dist should be (in my case, only components, no utilities)

gkatsanos commented 1 year ago

daisyUI component styles are added to Tailwind using Tailwind's addComponents() function. After that, component styles (just like every other Tailwind CSS style) will only be included in the CSS file if Tailwind CSS finds its class name inside your markup files. So, purging is handled by Tailwind. As long as you add styles to Tailwind CSS using the plugin API, Tailwind handles them for you as well. Otherwise you can use an external Post CSS plugin like Purge CSS.

Let me know if you have any questions

Hey :) I managed to get it right, I was wondering if you've thought of a way to do this ( tailwind based UI components ) without using @apply ? The thing is that with @apply you end up duplicating a lot of css properties that would normally be utility classes so it's a little bit of a tailwind anti-pattern...

saadeghi commented 1 year ago

I see that the end result is one css file basically is this the end file imported into the apps and then tailwind does the purging?

Not a CSS file. There are CSS files for component class names and utility class names. They get converted to CSS-in-JS files then get imported to Tailwind CSS using Tailwind's plugin API (because tailwind doesn't accept a CSS file)

I was wondering if you've thought of a way to do this ( tailwind based UI components ) without using @apply ?

If you want to only have Tailwind CSS utility classes, in your template files, you wouldn't need daisyUI. You can use Tailwind CSS class names. But of course it takes more time to style everything from scratch.

The thing is that with @apply you end up duplicating a lot of css properties that would normally be utility classes so it's a little bit of a tailwind anti-pattern...

It's not anti-pattern. Tailwind CSS itself provides a lot of class names that provide more than 1 CSS rule per class name and they can be sliced down to other class names. For example whenever you use mx-1 and mr-1 you will have a duplicate CSS rule on both class names.
There are also class names in Tailwind CSS like container
Other than that, Tailwind CSS provides API for adding component class names: https://tailwindcss.com/docs/plugins
And that's what daisyUI is using.

Using daisyUI, you will have some duplicate CSS rules in your class names but it's better than other solutions:
For example if you create a JS component for every element you have and conditionally add needed utility class names using JS, you should address all your component files in Tailwind CSS content config. This way Tailwind CSS generates class names for all the string you have in your JS component. Either you use them in the app or not. So you will have a lot of unused class names. For example if your button CAN have a specific color name (primary, red, or anything) that utility class name will be in production even if you don't actually set the attribute to your button for using that specific color. This scenario also happens in server rendered pages.
So if you want to have design system or if you want to use any UI component using any framework, you can end up with hundreds of unused class names in the production anyway. This is inevitable because Tailwind has no way to see which class name actually will get rendered in the production. It can only find strings in template files and generate CSS for all the class names it finds.

This problem won't happen with daisyUI because you're just using CSS class names in HTML. Without any JS component to conditionally apply or not apply used or unused class names. So you will only get class names that you actually used. Even with duplicate CSS rules in daisyUI class names this is much more efficient than having a lot of unused class names for all those possible component variants.

Let me know if you have any questions.

rnwonder commented 1 year ago

Hello I used postcss cli to build this is the actuall command

postcss src/index.css -o dist/index.css

my post css config

module.exports = ({ env }) => ({
  plugins: [
    require("tailwindcss")(),
    require("autoprefixer")(),
  ],
});

I notice the css file it creates was large around 64kb. So I opened it and found out that the styles for all the themes were included. When I manually deleted them the css size dropped to 37kb almost 50%. Is there a way we can get only the styles for the theme we are using on build. I didn't specify any theme so I assume I am using the light theme.

Or if I am doing something wrong too please let me know

saadeghi commented 1 year ago

@rnwonder see this: https://daisyui.com/docs/themes/#-1

rnwonder commented 1 year ago

Thank you @saadeghi! Yes this works but there are also unused styles too. like select, range, button group, even keyframes and the likes that are for components I didn't use. I only used the button component but I get all these extra styling which is about 600+ lines of code. For now I remove them manually which is a pain

saadeghi commented 1 year ago

@rnwonder

Some of the "extra" lines you're mentioning are from Tailwind. I can't do anything about it but you can control them using Tailwind's config. For example if you don't need the reset styles, you can disable it like this: https://tailwindcss.com/docs/preflight#disabling-preflight

If you only used btn class, every style related to .btn will be included (like btn-group) and that's expected behavior because the Tailwind's class name processor is only searching your raw template files one by one using a simple regex pattern. It has no idea how your components are mixing together so if it sees btn string, it adds every class name with word btn. Same thing happens for any other string. If you have a simple text (not html tags) that includes the word select in it, the processor will add .select to your CSS.
As I said, it's a really really simple string finder. It's not AI and it doesn't know what programming language you're writing so it can not predict if the string you used is just a text or a variable or class name. It really can be anything in different languages.

If it's really important for you, you can use prefix config for both daisyUI and Tailwind. this way, all your class names will have a specific prefix which can not be randomly found inside your template files so Tailwind will generate much less unused styles.

Another thing you can do is using Post CSS plugins to remove unused stuff after Tailwind's style generation.
For example this one removes all the unused CSS variables: https://www.npmjs.com/package/postcss-prune-var
Or this one https://purgecss.com removes unused CSS and has a lot of configs for best result.

There are many other packages you can try but never remove generated styles manually. That't just waste of time.

And another advice, saving 1 or 2 kilobytes doesn't really make a difference. For example here you can see Tailwind's default style with 1 daisyUI button results 800 lines of CSS (including all the reset styles, CSS variables, etc) but how much is the size? only 2kB

Or look at this CSS file. It's the huge CSS file of daisyUI's docs site generated by Tailwind. It's huge because the website has demos and examples with every possible components and class names. It's 225 KB but the compressed file that actually gets downloaded by the browser is here Only 26.2 KB

rnwonder commented 1 year ago

Alot of info thanks. Will try them out

sovetski commented 2 weeks ago

@saadeghi I just discovered that I have unused classes on the final build file like "mockup-browser" etc. but it is not used on my project

saadeghi commented 2 weeks ago

The class mockup-browser will get added only if you have mockup-browser string in one of the files you addressed in tailwind.config.js in content array. Of the config is correct, you shouldn't get unused class names.

sovetski commented 2 weeks ago

The class mockup-browser will get added only if you have mockup-browser string in one of the files you addressed in tailwind.config.js in content array.

Of the config is correct, you shouldn't get unused class names.

I checked in my entire project and there is no any "mockup-browser" string. I will try to see tomorrow if i find the problem