Open ernsheong opened 6 years ago
I personally use Purgecss like we talk about in the documentation:
https://tailwindcss.com/docs/controlling-file-size#removing-unused-css-with-purgecss
Actually, I've been struggling with @apply
thing for a while, though otherwise having great times with Tailwind. We're using Tailwind + Vue for remaking UI of a pretty large project (was Angular 1.x + Semantic UI), and this is the issue (not an issue probably but rather workflow) I'd be happy to see worked out (and I'm all ready to assist with).
I hope @adamwathan can guide me better if this is not the right place to discuss it. So, we're using Vue's single file components and adding @import "tailwindcss/utilities";
to each <style>
block where we need to use @apply
. This adds whole utilities CSS to every Vue component. Later on, we remove redundant styles with PurgeCSS (along with OptimizeCssAssetsPlugin
and stuff). All works great, but our webpack build is taking ages, and yet growing. First build time is about 2-2.5 mins, subsequent builds are about 10 secs, and we have just 30-40 components. I've removed CSS part from webpack for testing purposes, and it took about 6 secs for full build. So, I assume this is because utilities being imported in every component. Importing utilities file into just entry file doesn't help, @apply
errors start showing up.
I'm following all the issues like https://github.com/tailwindcss/tailwindcss/issues/449, https://github.com/tailwindcss/tailwindcss/issues/231 and https://github.com/tailwindcss/tailwindcss/pull/169#issuecomment-343549111, but all these are closed, and as for now I don't see a right place to discuss this problem.
I'd be happy to hear your suggestions about it Adam, I really love Tailwind CSS and overall your awesome work with Steve on Refactoring UI. Thank you!
I'm planning to work on making @apply
work without having the CSS that you are trying to apply exist in the same CSS tree next month, but I'm worried the performance isn't really going to get better.
The reason for this is that right now the way people have their Vue projects like yours configured is that PostCSS runs all of your plugins completely independently for every single <style>
block in your project. Tailwind has to spin up and run from scratch on every single component, as does autoprefixer, etc.
This means that even if I make it possible to @apply
classes that aren't actually defined in that CSS tree, Tailwind still needs to generate those classes silently, then look up the matching class. So I fear that even after I get this working, Tailwind still needs to do the same amount of work for every single <style>
block as it does right now, and because each block is processed completely independently, I'm not sure if I can even do any sort of intelligent caching or anything.
I'm personally still not convinced this wouldn't be better solved using a Webpack configuration. I don't have enough Webpack experience to suggest how to do this myself, but it seems to me that the real problem is that if you have 100 components that all have <style>
blocks, PostCSS runs 100 times. It makes way more sense to me for PostCSS to run on a single CSS tree once; that being all of the styles from your whole project combined into one tree, then being run through PostCSS before those styles are inserted into the document.
If someone could figure out how to do that, we wouldn't need to change Tailwind at all, everything would just work.
The other thing worth mentioning is that in general, I'm not sure what the benefit of even using @apply
is inside of a Vue component. The point of that feature is to avoid duplication in your templates, but if you have already componentized something at the Vue level, there's no downside to just using the utilities directly in your markup.
Can you give an example of how you are using @apply
inside of a Vue component and why it's better than just using the utilities directly in the HTML?
Thank you for detailed answer, I see the whole problem now.
As for why we're using @apply
instead of raw utility classes in markup, I think, it can be boiled down to a few points:
@apply
, inlining just doesn't work here.:class
directive and, probably, some other cases.vue-multiselect
) with @apply rules, following the same style guide from tailwind.config.js
we've fine-tuned for our project.Probably this is not the best example, but here is one of our components using selectors for some more-advanced-than-usual layout stuff:
<template>
<div class="segment-placeholder">
<div class="segment-placeholder-icon">
<slot
name="icon"
></slot>
</div>
<div
v-if="title"
class="segment-placeholder-title"
>{{ title }}</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
export default Vue.extend({
props: {
title: {
type: String,
default: '',
},
},
});
</script>
<style lang="postcss" scoped>
@import "@/styles/utilities.pcss";
.segment-placeholder {
@apply .text-grey .text-center .mt-12;
& .segment-placeholder-icon {
& + .segment-placeholder-title {
@apply .mt-4;
}
}
&:not(:last-child) {
@apply .mb-12;
}
&:last-child {
@apply .mb-6;
}
}
</style>
May be related: https://github.com/vuejs/vue-loader/issues/328.
I'm planning to work on making @apply work without having the CSS that you are trying to apply exist in the same CSS tree
@adamwathan I think that would be a great start!
Hi @adamwathan, just wondering if there is any update on this?
I'm currently stuck with our dev bundle being 45 MB with 200 .vue
files due to utilities
inclusion for using @apply
in most components.
We also have workflow for removing duplicate styles and optimizing the bundle size with purgecss-webpack-plugin
, optimize-css-assets-webpack-plugin
, cssnano
and folks but this way our dev build takes 10 minutes for first call and about 50s for every change, which is pretty daunting.
@evenfrost I released v0.6.2 (but install v0.6.3, v0.6.2 had a major bug) today which includes support for this behind an experimental flag:
Please test it out and let me know what you think.
FWIW the interim approach I took was to split up my utilities into multiple small JS files and include them as needed into my web components. No the most DRY but removes the bloat.
@ernsheong Try that new shadowLookup
option and let me know how it works for you.
@adamwathan sorry for the delay, all working great! With shadowLookup
we reduced our dev bundle size from 50 MB to 5 MB, and build times are greatly improved as well. :tada:
@adamwathan Will the shadowLookup
option still work in the 1.x releases (beta, etc.)?
That is all enabled by default since I think 0.6 or 0.7, you don't need the experiments
config at all anymore 👍🏻
Hi all,
I understand that
@apply
can only be used to import classes that it can "see".I come from the perspective of web components, particularly using the Shadow DOM.
Hence I would like to generate classes from
@tailwind utilities
using@apply
, and then subsequently remove the utilities file after the class generation, as I want to lose the weight, and also not let the browser do more parsing work than it needs to. Otherwise each Shadow DOM component that I ship would contain an exact duplicate of all of Tailwind's CSS.I guess a corollary to this question is that is there a way for Tailwind (or some other tool) to parse the DOM and remove unused classes?
Is there a way to do the above?