Skip to content

Long recompile times whenever updating css files #3427

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

Closed
joshxyzhimself opened this issue Jan 24, 2021 · 17 comments
Closed

Long recompile times whenever updating css files #3427

joshxyzhimself opened this issue Jan 24, 2021 · 17 comments

Comments

@joshxyzhimself
Copy link

Describe the problem:

When updating css files, the compile times are increasing (this is on a project that is not using Next.js)

Image below is example, when making small changes, e.g. changing one line.

image

It sometimes result in heap out of memory error, which looks like also encountered on next.js users using tailwind

I'm honestly unsure if it's a webpack thing or tailwind thing

@matthewmcvickar
Copy link

matthewmcvickar commented Jan 26, 2021

I am getting very long compilation times as well. Here's my setup:

postcss.config.js

module.exports = {
  plugins: [
    require('postcss-import'),
    require('tailwindcss'),
    require('postcss-calc'),
    require('postcss-nested'),
    require('postcss-simple-vars'),
    require('cssnano'),
    require('autoprefixer'),
  ]
}

tailwind.config.js

module.exports = {
  purge: {},
  darkMode: false,
  theme: {
    extend: {},
  },
  variants: {
    extend: {},
  },
  plugins: [],
}

gulpfile.js

const gulp = require('gulp');
const postcss = require('gulp-postcss');

// Paths.
const srcDir = './_src';
const assetsDir = './assets';
const paths = {
  css: {
    src: srcDir + '/css/*.css',
    dest: assetsDir + '/css'
  },
};

// Build CSS.
const compileCSS = () => {
  return gulp.src(paths.css.src)
    .pipe(postcss())
    .pipe(gulp.dest(paths.css.dest))
}

// Watch for changes.
const watch = () => {
  // CSS: Watch for source files to change, recompile CSS, and reload.
  gulp.watch(paths.css.src, compileCSS);
}

// Build assets.
const compileAssets = gulp.parallel(
  compileCSS
);

// Define tasks.
exports.dev = gulp.series(compileAssets, watch);

_src/css/main.css (set up as empty as possible, just default Tailwind modules)

@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";

And when I run gulp dev:

$ gulp dev
[14:46:55] Starting 'dev'...
[14:46:55] Starting 'compileCSS'...
[14:47:07] Finished 'compileCSS' after 12 s
[14:47:07] Starting 'watch'...
[14:47:11] Starting 'compileCSS'...
[14:47:21] Finished 'compileCSS' after 10 s

It takes 12 seconds just to generate the default Tailwind CSS export, and subsequent compilations take almost as long.


If I remove the postcss-calc, postcss-nested, postcss-simple-vars, and cssnano plugins from the postcss.config.js file, the compilation is quicker:

$ gulp dev
[14:47:33] Starting 'dev'...
[14:47:33] Starting 'compileCSS'...
[14:47:37] Finished 'compileCSS' after 3.58 s
[14:47:37] Starting 'watch'...

Still, four seconds to generate the CSS seems way too long. Do I have something set up wrong?


I am on macOS 10.14.6, node v15.7.0, gulp 4.0.2, tailwindcss 2.0.2, postcss 8.2.4, autoprefixer 10.2.3 (all latest as of this writing).

@iantearle
Copy link

12 seconds is average for me. All those post css plugins have got to run through 1000’s of lines of code, freeing up memory makes things run a little quicker sometimes, but it’s always been at least 3 seconds to complete.

@adamwathan
Copy link
Member

Duplicate of this unfortunately:

#2820

Webpack doesn't handle large CSS files well right now, and you have the same issue even if you are just using a very large (like 3mb) custom CSS file all authored by hand or generated by some tool other than Tailwind. We'd like to invest resources into improving this on the webpack side either by contributing to webpack or developing some sort of new custom CSS loader that avoids all of the in-memory processing webpack does for CSS but there's nothing we can really do in Tailwind itself so going to close.

@matthewmcvickar
Copy link

matthewmcvickar commented Jan 29, 2021

@adamwathan This is not just Webpack; see my example above which only uses PostCSS (run by Gulp). Should I open a new ticket?

@stepanjakl
Copy link

stepanjakl commented Jan 30, 2021

@matthewmcvickar @adamwathan Similar issue here, the compilation takes around 20 seconds with the config below (my tailwind.css file has 10MB un-purged). I don't use Webpack, purely running postcss script using onchange plugin

module.exports = {
	plugins: [
		require('postcss-import'),
		require('postcss-nested'),
		require('tailwindcss'),
		require('autoprefixer'),
		require('cssnano')
	]
}

EDIT: Turning off 'cssnano' does not help
EDIT2: Removing 'css-import' cut it down to 15secs

@adamwathan
Copy link
Member

@adamwathan This is not just Webpack; see my example above which only uses PostCSS (run by Gulp). Should I open a new ticket?

@matthewmcvickar 4 seconds is not outside the expected range I'm afraid depending on your hardware and how many features you have enabled in your Tailwind config. Generally the idea with Tailwind is you are almost never actually writing CSS, so you don't need to rebuild very often. We've already done a lot to optimize the performance and are always looking for new ways to speed things up but I'm afraid opening a new issue isn't really going to change anything unless someone can find and point out a very specific bottleneck.

@alinnert
Copy link

@adamwathan I just did some experimenting. I have a pretty large project (615 .pcss files, CSS is for multiple websites with a similar look) that uses PostCSS via Gulp and some plugins, but not Tailwind. By disabling all plugins except for postcss-easy-import (I use wildcard imports) I get a build time of a little more than 1 seconds. Adding more plugins one by one adds up more time that is at least 0.3 seconds per plugin, until I reach a build time of ~10 seconds. The one exception is postcss-preset-env which alone adds a whopping 20 seconds. I use the following config for this plugin:

presetEnv({
  stage: 1,
  features: {
    "custom-properties": { preserve: false }
  }
})

On the tailwind side: I've created a static website using Hugo (which runs PostCSS directly, no Gulp or Webpack in between) to build the html files. It alone has a build time that feels instant (a few milliseconds). Then I added Tailwind and configured it to check my 5 hello world templates to let purgeCSS do its thing. This already took 3 - 5 seconds.

All of this makes me feel that PostCSS itself is the bottleneck (especially because really no plugin that I've tried adds an acceptable amount of time to the build time), which is why I'm not a fan of Tailwind being based on it. I don't know if it helps if the code was written in another language that's being compiled to WASM. But I wouldn't be surprised if it doesn't.

On the other hand: Does Tailwind really need PostCSS? I think it could also be written in some native, compiled language or plain JS. Maybe Dart to compile it to native code and JS, like Sass does it now. You could still provide a PostCSS wrapper for those who need it, right?

@adamwathan
Copy link
Member

@alinnert I'm sure we could rewrite Tailwind in Rust but then we'd lose interop with every other tool in the ecosystem, and we'd have to write autoprefixer ourselves, as well as any other PostCSS features people need ourselves. It would probably take 6 months of engineering time and then just a lot of hope and prayer that people would even be willing to add something totally new to their tool chain. Nothing would work out of the box with popular frameworks like Next.js and we'd have to beg them to add support, etc. So as much as it is technically possible, it's really unrealistic I'm afraid.

@alinnert
Copy link

@adamwathan Um... Sass and Autoprefixer is a pretty popular combination. Why would that not work with Tailwind? All you need to do is run two commands in succession, like tailwind && npm run postcss or whatever. Plus I've mentioned a PostCSS wrapper that calls tailwind internally, which is where a compile-to-JS/WASM language (or JS itself) would shine. How would this break the ecosystem or require you to re-implement something yourself? The question is if the latter gives you any performance plus, but you could opt-out of it for simpler projects or if you know how to setup everything yourself.

I rather worry about introducing breaking changes about how you use Tailwind. E.g. the possibility to use @tailwind, @apply and tailwind.config.js. But that's not impossible either. So, I don't see why it would be as bad as you picture it. Of course, it sure will take its time.

Another possibility would be to switch to Sass (there's already a discussion thread about that: #2249). It already has a big working ecosystem you can leverage. Honestly, I'm thinking about actually trying that out.

@iantearle
Copy link

@alinnert This discussion has taken a rather detour to the original (now closed thread). PostCSS was (if I'm not mistaken) chosen because of its closeness to writing vanilla CSS, it encourages authors to write spec driven CSS (as opposed to SASS' own spec).
To ask a maintainer of an open source project to completely refactor everything they've worked on for the last few years is a bit insulting. I get that you are trying to reduce compile speeds, but as you have already mentioned, adding plugin upon plugin is mounting up the speed not solely tailwind.
At the end of the day, if Tailwind isn't working for your build process, try something else (Like what you have mentioned #2249 ), or write your own, as it is I'm sure thousands of developers are having a wild time with Tailwind as is.
I for one am completely happy with tailwind being postcss driven, that's been my ecosystem for the last 4 years, if Tailwind moved to Sass I'd probably find something else.

I've even had success compiling sass with tailwind with a compile time of 5s, (I'm forced to work with sass in a new team role). My personal work environment on a new M1 Mac has reduced postcss (css + tailwind) only environment from 12s build time on my 2013 imac to 3s. Plus the beauty of working with tailwind, if you don't purge during development, you don't have to compile all the time, run once, work, build out your styles, purge for production. Then the only wait time is however long before you go live. I don't get why compile time is such an issue?

Apologies, if I have spoken out of turn, and I don't mean to offend you in any way, just think @adamwathan has said his point of view, closed this off, and you should just carry on and leave it closed.

@alinnert
Copy link

This discussion has taken a rather detour to the original (now closed thread).

Has it? Isn't it still about how to reduce "long recompile times whenever updating css files"?

PostCSS was (if I'm not mistaken) chosen because of its closeness to writing vanilla CSS, it encourages authors to write spec driven CSS (as opposed to SASS' own spec).

That was also my idea and that's why I've chosen PostCSS for said website project. Now a lot of the specs have changed and my code and that of Tailwind are proprietary. Even more than Sass' code, because Sass at least has a stable spec you can rely on. I can't even update the npm packages because they also change with the CSS spec. This is a dead-end.

To ask a maintainer of an open source project to completely refactor everything they've worked on for the last few years is a bit insulting.

If you ask me to rewrite the CSS of said project and that choosing PostCSS was a bad idea I'd totally agree with you. If it's about another project it depends. If it solves a problem it's something worth thinking or talking about. Why should I or someone else feel insulted about that? Rewrites are also not very uncommon. Also, as you now might know: I'm in a very similar situation.

I basically have two options now: a) help improving an existing technology or b) make another framework™. I've already spent quite some time making something that was already there or was in the makings by someone else. I hope you understand it's preferable to check out a) (= in this case: share my ideas and check if they have been considered or if there are problems I didn't think about) before throwing myself into b). Plus: I don't know if I should feel bad if I "steal" all the ideas, values and colors from Tailwind.

I don't get why compile time is such an issue?

You feel it everytime you change your configuration. Especially when you set everything up at the start of your project or try out different configs like color palettes and you switch between A - B - A - B - A - ... to find out, which one looks better. This is where it gets really frustrating.

btw: If Tailwind was written in Sass that doesn't mean you have to write Sass code. It's not my intention to change how Tailwind is being used. It's about how Tailwind's CSS is being generated. You can still use normal .css files on top of that.

@adamwathan
Copy link
Member

Um... Sass and Autoprefixer is a pretty popular combination.

Sass is an existing tool with a huge ecosystem. Whatever we built would be brand new, we'd need to write a custom webpack loader for it for example and who knows what other integration tooling that already exists for Sass due to it's popularity. The more totally new build tooling you throw on someone's plate, the more friction you introduce to them adopting the tool.

PostCSS is not a syntax, it's a tool for transforming CSS at the AST level. We would have to create a new tool for doing that in a faster language if that's what we wanted to do. We chose PostCSS because it is incredibly widely adopted, and it provides all of the tooling we needed to actually make Tailwind work. They have APIs for generating CSS, parsing an AST, walking and updating the AST, etc. Tailwind was originally written in Less and then later we tried to write it in Sass and both approaches were extremely limited, totally unmaintainable, and even slower than the PostCSS version. Tailwind is not written "in PostCSS", it's written in JavaScript, which means we have the power of a full programming language available to us to implement maintainable programming patterns, and can easily write automated tests for it.

For what it's worth, I don't even think rewriting Tailwind in something faster would have a super meaningful impact on the developer experience. Following best practices you almost never write new CSS, so you rarely need to recompile. And when you do, Tailwind takes less than 1s to recompile on my machine when running in a watcher:

It's slower when you use webpack but that's because webpack handles large CSS files poorly and has nothing to do with Tailwind's code. If you used Rust to generate a 3mb CSS file, webpack would take 25 seconds to process that as well.

In a perfect world if we could snap our fingers and have a version of Tailwind exist written in a much faster language so that it took 30ms to compile instead of 800ms that would be great, sure. But there's no way to get that by snapping our fingers, only by investing months of work and hundreds of thousands of dollars (we're a company with payroll), and even then we'd be risking upsetting more people than we'd make happy because of the enormous break in the ecosystem. No existing Tailwind plugins would work, no existing tooling people have written for integrating Tailwind into popular frameworks would work, etc.

@stepanjakl
Copy link

stepanjakl commented Feb 16, 2021

Just for the completeness of this discussion, there is windicss/windicss that claims to provide faster load times (20~100x). I haven't tried it myself yet, but might be worth a shot ✌️

@et-hh
Copy link

et-hh commented Mar 23, 2021

@stepanjakl windicss/windicss is good but it doesn't support react

@adamwathan
Copy link
Member

Try our new JIT library, should solve this issue 👍🏻

https://blog.tailwindcss.com/just-in-time-the-next-generation-of-tailwind-css

@alinnert
Copy link

Yes, I've tried it out and it works really well. Thank you a lot.

@et-hh
Copy link

et-hh commented Jul 7, 2021

可以通过webpack插件解决这个问题:
https://juejin.cn/post/6956424977184718856

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

7 participants