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

Slow compile when using @apply #443

Closed
ghost opened this issue Apr 2, 2018 · 24 comments
Closed

Slow compile when using @apply #443

ghost opened this issue Apr 2, 2018 · 24 comments

Comments

@ghost
Copy link

ghost commented Apr 2, 2018

I've been experiencing slow compile times when using the @apply rule in my CSS. Here's an example:

.HomePage main .plan h3 { @apply .content-none .absolute .block .border-solid }

Despite having a powerful machine, as the CSS grows, the compile time goes up. It's now gotten to a point where even when running a watcher on save it is over 1.5s. Enough to slow down my workflow. I'm only looking at 100+ lines of CSS (for components).

Are there any reasons why it might be slow?
Thanks!

EDIT:

I've determined that it is being caused by the size of the tailwind config JS file. The resulting CSS file being generated is ~500 KB. I've stripped out some colours, but I've added items too e.g. margins and padding. If I have to remove them to get a usable compile time, doesn't that kinda defeat the point of the framework? I want to have many utilities available to me.

I think the solution is too structure the build process so that the tailwind config isn't recompiled every time. However, I wonder if this presents a problem with using @apply?

@adamwathan
Copy link
Member

There might be ways to make it faster but currently it's already as fast as I really know how to make it; I actually made some drastic performance improvements to it a month or so ago. Previously, using many calls to @apply would slow things down over time (some people with big projects had 1 minute or longer build times), but in recent versions that time should be more or less constant, so using lots of @apply calls shouldn't be any slower than using a single @apply call.

Are you on an older version by chance? If you're already on a recent version then I don't have much advice unfortunately; @apply needs to look at all the classes that exist to find a match so there's no way to avoid processing the whole config file since that's where all the classes come from.

@ghost
Copy link
Author

ghost commented Apr 2, 2018

Thanks for the reply.

I'm on the latest version, so sadly it's not related to earlier problems.

I have confirmed though that delay is in the generation of the CSS from tailwind config. Using @apply in my other CSS files creates only a minimal delay. So, it's really a case of trying to compile the config at a faster speed.

I wonder if there's value in tracking changes to the config file and using that in some way to only generate / re-generate the classes that are new or have changed?

@adamwathan
Copy link
Member

Got it, so it's not really anything to do with @apply at all; you'd see the same compilation time even if you didn't use it right?

It would be nice if there was a simple way to just do partial rebuilds of the CSS when things change but I think it's more complicated than it sounds, because you can add things to your own CSS like @responsive that generate code that needs to be placed inside of Tailwind's existing media queries, so even if we tried to cache Tailwind's generated CSS it wouldn't really help because you can change Tailwind's generated CSS from outside of the config file.

Any improvements we can make in compilation speed are of course great but I'm going to close this issue as "not a bug" at least; it just takes time to generate thousands and thousands of CSS classes, heh. It would be nice to get it faster than 1.5 seconds but I'm just not sure there's any low hanging fruit there right now.

@ghost
Copy link
Author

ghost commented Apr 2, 2018

Fair enough. Thanks for the feedback :)

@jakewtaylor
Copy link

Hi, I'm still seeing a significantly slow build time using tailwind with laravel mix. I don't know if its the same issue as this, but running yarn run watch (I only have one CSS file being compiled), each build is taking anywhere between 3-6 seconds.

On OSX 10.11.6

Thanks

@dolanmiu
Copy link

dolanmiu commented Jan 7, 2020

I am still experiencing the same. 3-6 seconds with apply

@Life-Hex
Copy link

Hurts that i want to use this beautiful framework but i'm being maltreated by slow compile times.
Coming from a place where you're used to snap save/checks - it's going to take alot of getting used to.
I was wondering if, maybe we could build to a different file from the already heavy tailwind preconfig - or make some sort of buffer for just testing your style on local, before it's "committed" to your actual stylesheet.

@Life-Hex
Copy link

I am still experiencing the same. 3-6 seconds with apply

I don't think it's apply. OP says so too.

@knynkwl
Copy link

knynkwl commented Jun 22, 2020

I am seeing really slow build time as well. Without Tailwind my builds are running around 500-600ms, with tailwind it's around 6000-8000ms!

I don't think this is due to @apply directive, all I only adding the base config and no custom css.

It looks like the slowest builds come from adding @import "tailwindcss/utilities"; since that is where most of the heavy lifting is taking place.

@estevanmaito
Copy link
Contributor

@knynkwl are you using Laravel Mix? If so, take a look #1514 (reply in thread)

@knynkwl
Copy link

knynkwl commented Jun 22, 2020

No, I'm using a custom webpack config.

@Frulko
Copy link

Frulko commented Jun 23, 2020

Hi there, 👋

The workaround I've found to handle this slow time is to separate style code in two files :

  • the first (called : tailwind.css) with the code from the doc :
/** Tailwind base styles – includes modified normalize.css */
@tailwind base;

/** Tailwind plugins – included in tailwind.js */
@tailwind components;

/** Tailwind utilities – generated from config in tailwind.js */
@tailwind utilities;
  • a second (called: main.css or main.scss with my code.
.Component{
  @apply bg-red-600;
}

As reading the documentation : docs/adding-base-styles
They said :

Define any of your own custom base styles directly after @tailwind base and before @tailwind components to avoid specificity issues

With my above attempt i've have (for now) no issues yet.
@apply work fine and the custom config file too.

Maybe it's a bad idea but w/ this I have a correct fast build time because, I did'nt have to rebuild each time the whole tailwind in development mode.

I'll post here my return about that and if it was a good or bad idea.

@tleish
Copy link

tleish commented Jul 21, 2020

I experienced this same issues (which brought me here). Any time I modified custom css, recompile time took over 5 seconds. The majority of the time came from @import "tailwindcss/utilities";

Based on the prior tip, I created 3 css files for my webpack app (previously only had application.css).

  1. tailwind/before.css
@import "tailwindcss/base";
  1. tailwind/after.css
@import "tailwindcss/components";
@import "tailwindcss/utilities";
  1. application.css
/* custom styles */
h1 { @apply text-2xl uppercase; }

Then in my application.js file, I import them in the following order:

import 'stylesheets/tailwind/before.css';
import 'stylesheets/application.css';
import 'stylesheets/tailwind/after.css';

Recompile time went from 5752ms down to 337ms. Files are still combined into 1 single application.css file, but webpack seems to know it does not need to recalculate the specific tailwindcss files when imported this way.

Thanks @Frulko for the tip!

@knynkwl
Copy link

knynkwl commented Jul 21, 2020

@tleish Do you mind showing your webpack setup? I get errors when breaking them up that way.

@tleish
Copy link

tleish commented Jul 21, 2020

@knynkwl - Are you using a css loader of any kind to extract CSS from javascript files into a separate css file? My webpack config includes the css loader mini-css-extract-plugin.

@knynkwl
Copy link

knynkwl commented Jul 21, 2020

@tleish Hm yeah I'm using MiniCssExtractPlugin

new MiniCssExtractPlugin(  {
        path: path.resolve(__dirname, settings.paths.dist.base),
        filename: path.join('./css', `[name].[chunkhash].css`),
    })

@tleish
Copy link

tleish commented Jul 21, 2020

@knynkwl - what error are you getting?

@tleish
Copy link

tleish commented Jul 21, 2020

Since @import "tailwindcss/utilities"; causes the majority of the slowness, a simpler approach to the above suggestion is to have 2 files.

  1. application.css
/* using @tailwind directive */

@tailwind base;

/* custom styles */
h1 { @apply text-2xl uppercase; }

@tailwind components;

or

/* using poscss-import */

@import "tailwindcss/base";

/* custom styles */
h1 { @apply text-2xl uppercase; }

@import "tailwindcss/components";
  1. tailwind_utilities.css
/* using @tailwind directive */

@tailwind utilities;

or

/* using poscss-import */

@import "tailwindcss/utilities";

Then in my application.js file, I import them in the following order:

// when using postcss-import
import 'stylesheets/application.css';
import 'stylesheets/tailwind_utiltiies.css';

Similar performance improvement as reported before.

@rnmp
Copy link

rnmp commented Aug 6, 2020

Just ran into this issue. Thanks so much for sharing, this is really helpful! I feel like this should be documented somehow if it isn’t already.

user512 added a commit to zinc-collective/convene that referenced this issue Oct 17, 2020
This changes reduce slow webpack compilation when using Tailwind @apply
Before this changes, it takes 10 seconds to recompile whenever change is made on application.scss
According to the ref articale, Tailwind CSS's components and utilites have large file sizes,
making the recompilation very slow.
This workaround separate Tailwind CSS and custom @apply CSS so webpack never have to recompile
the large Tailwind CSS stuff since it wasn't changed.

Ref: https://rubyyagi.com/solve-slow-webpack-compilation/
Another workaround, similar idea but without using @layer:
tailwindlabs/tailwindcss#443 (comment)
user512 added a commit to zinc-collective/convene that referenced this issue Oct 17, 2020
…pile (#140)

This changes reduce slow webpack compilation when using Tailwind @apply
Before this changes, it takes 10 seconds to recompile whenever change is made on application.scss
According to the ref articale, Tailwind CSS's components and utilites have large file sizes,
making the recompilation very slow.
This workaround separate Tailwind CSS and custom @apply CSS so webpack never have to recompile
the large Tailwind CSS stuff since it wasn't changed.

Ref: https://rubyyagi.com/solve-slow-webpack-compilation/
Another workaround, similar idea but without using @layer:
tailwindlabs/tailwindcss#443 (comment)
@nickjj
Copy link

nickjj commented Oct 22, 2020

Is there by chance a CSS-only solution to this? One that doesn't require importing your CSS through JS.

I noticed I jumped from about 250ms changes to 3.5 seconds after updating Tailwind versions from 1.3.x to 1.9.x.

@marlongerson
Copy link

marlongerson commented Nov 30, 2020

I experienced this same issues (which brought me here). Any time I modified custom css, recompile time took over 5 seconds. The majority of the time came from @import "tailwindcss/utilities";

Based on the prior tip, I created 3 css files for my webpack app (previously only had application.css).

  1. tailwind/before.css
@import "tailwindcss/base";
  1. tailwind/after.css
@import "tailwindcss/components";
@import "tailwindcss/utilities";
  1. application.css
/* custom styles */
h1 { @apply text-2xl uppercase; }

Then in my application.js file, I import them in the following order:

import 'stylesheets/tailwind/before.css';
import 'stylesheets/application.css';
import 'stylesheets/tailwind/after.css';

Recompile time went from 5752ms down to 337ms. Files are still combined into 1 single application.css file, but webpack seems to know it does not need to recalculate the specific tailwindcss files when imported this way.

Thanks @Frulko for the tip!

Thank you so much. This reduced my compile time significantly (was ~5000ms now down to 1000ms).

@nickjj
Copy link

nickjj commented Dec 2, 2020

I also bit the bullet and went with the above approach. From 5500ms down to 110ms for making changes in application.css. Thanks for the workaround!

However, there's still a 5500ms penalty when starting your project up (with the webpack watcher at least).

For example when I start my project, I get:

webpack_1   | webpack 5.9.0 compiled successfully in 5590 ms
[webpack-cli] watching files for updates...

This delays starting up my project by about 5.5 seconds. It's a nuisance due to using Docker because if my main web app's process crashes and I need to restart Docker Compose in development it means waiting 5.5 extra seconds before everything is ready to go.

Does anyone have any tips on how to reduce initial start up times?

@itsfarseen
Copy link

itsfarseen commented Dec 3, 2020

@nickjj that is probably because webpack rebuilds all the css files on startup.
One solution is to compile the css files separately from webpack.
Remove the import <css file> lines from your index.js file.
Then use <link> tag to link those to your base html file.

Use npx tailwindcss build input.css -o output.css to compile your application.css.
Put this in your docker file to run on startup.
And you may use something like entr or some other watcher utility to recompile application.css when the source changes.

Manually do npx tailwindcss build input.css -o output.css to compile other two files, only when needed.

cammarin added a commit to cammarin/cammarin.me that referenced this issue Mar 18, 2021
It seems utilities import hogs the building process.

The solution is to have base styles separated.

tailwindlabs/tailwindcss#443 (comment)
@xdivby0
Copy link

xdivby0 commented Apr 3, 2021

I experienced this same issues (which brought me here). Any time I modified custom css, recompile time took over 5 seconds. The majority of the time came from @import "tailwindcss/utilities";

Based on the prior tip, I created 3 css files for my webpack app (previously only had application.css).

1. tailwind/before.css
@import "tailwindcss/base";
1. tailwind/after.css
@import "tailwindcss/components";
@import "tailwindcss/utilities";
1. application.css
/* custom styles */
h1 { @apply text-2xl uppercase; }

Then in my application.js file, I import them in the following order:

import 'stylesheets/tailwind/before.css';
import 'stylesheets/application.css';
import 'stylesheets/tailwind/after.css';

Recompile time went from 5752ms down to 337ms. Files are still combined into 1 single application.css file, but webpack seems to know it does not need to recalculate the specific tailwindcss files when imported this way.

Thanks @Frulko for the tip!

This. It's not even such a hacky way, it makes sense and from my point of view this hint should be given on the tailwindcss documentation :) gone from 7 seconds to one second.

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

No branches or pull requests