[Update] Using Svelte with Tailwindcss - A better approach
Tags: svelte, sapper, tailwindcss, javascript
Published: 2019-11-04 18:10:00

_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: {% github sarioglu/svelte-tailwindcss-template %}

## 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](https://github.com/tailwindcss/setup-examples/tree/master/examples/svelte)
- [setup-examples/examples/sapper at master · tailwindcss/setup-examples · GitHub](https://github.com/tailwindcss/setup-examples/tree/master/examples/sapper)

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.
```bash
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:
```bash
npm i -D @fullhuman/postcss-purgecss postcss postcss-load-config svelte-preprocess tailwindcss
```

Then, run the following command to initialize Tailwind:
```bash
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
```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
```html
<style global>
  @tailwind base;
  @tailwind components;
  @tailwind utilities;
</style>
```

We need to import this component into our app:
### src/App.svelte
```html
<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
```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`:

```html
<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:{% github sarioglu/sapper-tailwindcss-template %}

## 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.