Updated 2020/01/27, GitHub link for the Sapper template is added below 🎉
I've been using Tailwind since its early days and it is a complete life changer for me. That's why I tried to use it on a project written using Svelte. Existing methods to combine these two weren't sufficient in terms of developer experience that they have provided. So, I've tried to come up with a better approach. Wish you enjoy reading!
TL;DR
I've combined Svelte's preprocessing feature and PostCSS using svelte-preprocess
to handle Tailwind. You can skip the tutorial and use the template that I've published on GitHub:
sarioglu / svelte-tailwindcss-template
Template for building basic applications with Svelte
Looking for a shareable component template? Go here --> sveltejs/component-template
svelte-tailwindcss-template
This is a fork of Svelte's project template to enable usage of Tailwindcss. Refer to https://github.com/sveltejs/template for more info.
To create a new project based on this template using degit:
npx degit sarioglu/svelte-tailwindcss-template svelte-app
cd svelte-app
Note that you will need to have Node.js installed.
Get started
Install the dependencies...
cd svelte-app
npm install
...then start Rollup:
npm run dev
Navigate to localhost:5000. You should see your app running. Edit a component file in src
, save it, and reload the page to see your changes.
By default, the server will only respond to requests from localhost. To allow connections from other computers, edit the sirv
commands in package.json to include the option --host 0.0.0.0
.
If you're using Visual Studio Code we recommend installing the official extension Svelte for VS Code. If you are…
Existing methods
There are several other works to integrate Tailwind into Svelte. You can even find a couple of examples under Tailwind's GitHub account.
- setup-examples/examples/svelte at master · tailwindcss/setup-examples · GitHub
- setup-examples/examples/sapper at master · tailwindcss/setup-examples · GitHub
However, these methods have some structural weaknesses:
- They create another pipeline alongside Svelte to process external css. Tailwind will be processed by PostCSS while component styles are being processed by Svelte. That's why developers need to reconsider everything from transpiling to minimization.
- They make it impossible to use directives of Tailwind (like
@apply
or@screen
) in component styles. - They create an auto-generated css file within the codebase.
That's why I've come up with a new approach to make this integration smoother. So let's start with it:
1-Create a Svelte app
First, we need to initialize a Svelte app using the following commands. If you already have an existing one, you can skip this section.
npx degit sveltejs/template [my-svelte-project]
cd [my-svelte-project]
npm install
These commands clone the official Svelte app template and install required dependencies.
2-Initialize Tailwind
Following the previous step, install required dependencies for Tailwind integration using the following command:
npm i -D @fullhuman/postcss-purgecss postcss postcss-load-config svelte-preprocess tailwindcss
Then, run the following command to initialize Tailwind:
npx tailwind init
This will create a file named tailwind.config.js
in your codebase. You can edit or replace this file to extend your Tailwind config.
3-Make the integration
In order to make the integration we'll need following two files. We'll use postcss.config.js
to configure PostCSS to process styles with Tailwind. Note that PostCSS uses Purgecss to get rid of unused styles in production mode. We'll also need to whitelist css classes generated by Svelte itself since Svelte itself takes are of these.
postcss.config.js
const purgecss = require('@fullhuman/postcss-purgecss')({
content: [
'./src/**/*.html',
'./src/**/*.svelte'
],
whitelistPatterns: [/svelte-/],
defaultExtractor: content => content.match(/[A-Za-z0-9-_:/]+/g) || []
});
const production = !process.env.ROLLUP_WATCH
module.exports = {
plugins: [
require('tailwindcss'),
...(production ? [purgecss] : [])
]
};
Tailwindcss.svelte
file includes a Svelte component which only has a style definition. We'll use it to inject our utility classes into the app. global
directive here means that styles of this component will be available globally.
src/Tailwindcss.svelte
<style global>
@tailwind base;
@tailwind components;
@tailwind utilities;
</style>
We need to import this component into our app:
src/App.svelte
<script>
import Tailwindcss from './Tailwindcss.svelte';
...
</script>
...
<Tailwindcss />
...
By doing that, we'll be able to use the classes provided by Tailwind in our app.
Finally, we'll tweak the rollup config to use svelte-preprocess
to process components' styles.
rollup.config.js
import sveltePreprocess from 'svelte-preprocess'
...
svelte({
...
preprocess: sveltePreprocess({ postcss: true }),
...
})
...
Results
Using this new approach will enable us to benefit from every feature of Tailwind by combining Svelte's preprocessing ability and PostCSS. You can use utility classes, or call directives to combine them into component styles. All those styles will be processed by Svelte without creating additional pipeline.
To demonstrate the outcome let's run the app using npm run dev
command and change some styles in App.svelte
:
<style>
h1 {
@apply bg-black text-white;
}
</style>
You will see that styles provided by Tailwind are perfectly applied to our mighty Hello world!
message. So you can start using them for a better cause!
What about Sapper?
Not a problem! You can apply the same steps to integrate Tailwind into your Sapper app. Just be sure that you've changed both client and server configs.
I've published the Sapper template to GitHub. Since it is based on the official template, you can use either of rollup and webpack setups. Here is the link:
sarioglu / sapper-tailwindcss-template
Starter template for Sapper apps
sapper-template
This is a fork of Sapper's project template to enable usage of Tailwindcss. Refer to Sapper for more info.
Getting started
Using degit
To create a new Sapper project based on Rollup locally, run
npx degit "sarioglu/sapper-tailwindcss-template#rollup" my-app
For a webpack-based project, instead run
npx degit "sarioglu/sapper-tailwindcss-template#webpack" my-app
degit
is a scaffolding tool that lets you create a directory from a branch in a repository.
Replace my-app
with the path where you wish to create the project.
Using GitHub templates
Alternatively, you can create the new project as a GitHub repository using GitHub's template feature.
Go to either sapper-template-rollup or sapper-template-webpack and click on "Use this template" to create a new project repository initialized by the template.
Running the project
Once you have created the project, install dependencies and run the project in development mode:
cd my-app
npm install # or yarn
npm run dev
…
Other benefits
Using svelte-preprocess
to let PostCSS to handle component styles provides various other side benefits. You can use postcss.config.js
to import some other PostCSS plugins like autoprefixer
, etc. Those plugins will immediately take care of your component styles.
Latest comments (36)
everything works fine but important modifier like !bg-red-100 doesn't work.why and how can i fix it?
This doesn't seem to work for adding custom utilities: tailwindcss.com/docs/adding-new-ut...
If I try to add a new utility class, e.g.:
and try to use it with
@apply
, then I see something like the following:Thanks for making these templates. I noticed after switching the sapper template to typescript with
node scripts/setupTypeScriptRollup.js
,Tailwind stopped working. The TS script creates some conflicts in rollup.config.js. They are easy to fix though.preprocess: sveltePreprocess()
lines that got addedI am brand new to Svelte, so might have something wrong, but this seemed to both get me TypeScript and Tailwind.
Thank you Matt! I've noticed this issue.
scripts/setupTypeScriptRollup.js
does not check if there is an existingsveltePreprocess
. So it results with a silent failure. Your fix is correct. I am going to examine the script deeper to find a solution.This doesn't remove unused tailwindcss in dev mode but should remove it when building, right?
Ahh, simply.
This is great! Thank you!
Note:
If anyone facing css linting warning in
@tailwind
keyword, just addtype="text/postcss"
.Thanks so much for sharing!! Have you done or are you aware of any public recipe which used this svelte-tw-template?
It's just a minor annoyance, but since I've made those changes, the bundle.js.map file gets send twice on every request. Don't know why really. Everything else seems to be working great tho. :)
Something is wrong with your sapper-template. When exporting, builds are 2 or 3 megs because the extra Tailwind CSS is not getting purged.
Need extra config now, Tailwind added purgecss. tailwindcss.com/docs/controlling-f...
Any workaround to make it work with svelte-vscode?
thank you! this is a lot of help!
Thanks for sharing. I ran into a small issue where the production flag in the postcss config is always false and therefore purgecss is not invoked. The NODE_ENV is "development" even when running
npm run build
in my case. I am on windows and I am resolving this by changing the build script toset NODE_ENV=production && sapper build --legacy
. With that purgecss is invoked and everything is fabulous, thanks again.Same for me too. I didn't mention that because I couldn't find any official information whether it is an expected behavior or not. Thank you for mentioning.
This still happens even though I'm using
set NODE_ENV=production && sapper export --legacy
I find this super weird. Not sure what to do at all.The only way for me to avoid having all the classes in production is to use
purgecss
in both dev and prod. What a bummerWhat about?
Great article! I'm also using
.prettierrc.json
and.eslintrc.json
from this article.Thanks a lot for this wonderful article! Much appreciated!
I included it in Sapper by following exactly your description and then, instead of importing and including it in
src/App.svelte
, I just included it insrc/routes/_layout.svelte
. This way it should be included in all pages rendered by Sapper.Works like a charm and, as you mentioned, no additional workflow side-by-side with Sapper/Svelte.
Thanks man!
thank you so much for this! working perfectly...
i think this is great! i made a recipe blog based on the sapper at master-tailwind method you mentioned above. i would like to try this method instead. do you have any plans on coming out with sapper-tailwind template on github? i can't figure out which goes into the server and which into client configs as you said. i'm a noob with those sort of things and more of a UI/UX guy. thank you for this! i'll try it out on a svelte project. cheers!
Thanks for your reply. I'm planning to create the sapper version soon.