How to use Tailwind with Svelte and Nrwl NX
Tailwind is more popular than ever. If you've been following me, you know that I'm a huge fan. Recently I've started exploring Svelte, and wanted to know how to combine it with Tailwind. Not only that, but I also wanted to use Nrwl NX. This is a summary of my findings.
This is a short, but very practical article. If you hope to learn how Svelte/Tailwind work and why you should use those then this article is not for you.
First, we'll create a Nrwl NX workspace to structure our project.
Once we're done, we'll install the Svelte plugin into the workspace, and we'll use it to create our Svelte application.
Then, we'll install Tailwind, and a few supporting tools (e.g., PostCSS and autoprefixer). After that, we'll configure Tailwind, PostCSS, and our Svelte application. Finally, we'll load Tailwind's base styles in our application, and we'll add some styling.
Creating the Nx workspace
NX is a really powerful tool that I use in most of my projects. NX supports many frameworks and programming languages.
Creating an Nx workspace is as simple as running the following command:
npx create-nx-workspace <workspace name>
At the moment, NX does not natively support Svelte, so we need to create an empty workspace. The
create-nx-workspace command should generate the following structure for you:
This is the standard structure for Nx workspaces. The key elements are:
appsfolder, which will later contain our Svelte application
libsfolder, which we can use to host parts of our monorepo to make those easily reusable across projects
nx.jsonfile, which is the configuration file of Nx
package.jsonfile in which we can manage our dependencies
workspace.jsonfile, which is the configuration file for our Nx workspace
Installing the Svelte plugin for Nx
Now that our workspace is created, we need to install the Svelte community plugin, created and maintained by Dominik Pieper. This plugin makes it possible to create and build Svelte applications in a Nrwl NX workspace. You can find the official documentation here.
For this example, I'll use
npm, but feel free to use
yarn if you prefer. Installing the plugin is quite straightforward:
npm install @nxext/svelte --save
Once done, we have access to the schematics and builders.
Creating the Svelte application
The Svelte plugin for NX includes a schematic that we will use to create our Svelte application:
npx nx g @nxext/svelte:app app_name
This command will generate the application and store it inside the
apps/<app_name> folder. Pick any name you fancy.
Inside that folder, you should find the following:
The code of the application can be found under
src, while the assets (e.g., images, fonts, global styles, etc) will go into the
svelte.config.cjs file. This is the configuration file for Svelte. We'll adapt it in a minute.
Svelte application configuration
In the previous section, I've mentioned the
svelte.config.cjs file that you should find under
apps/<app name>. Let's take a look at it:
All this file does is export a configuration object for the build of our Svelte application. By default, it uses the svelte-preprocess package, which is a preprocessor for Svelte providing support for PostCSS, SCSS, TypeScript, and much more.
The question is: how is that file used by the build system? To answer that question, we need to look at the
workspace.json file at the root of the NX workspace. It has been updated by the Svelte plugin for NX:
As you can see, the different targets (e.g., build and serve) use a specific executor:
@nxext/svelte:build, which is provided by the Svelte plugin for NX. That executor supports a number of options. In the example above, we care about the
svelteConfig setting, which defines the configuration file to use for Svelte.
When we build the Svelte application using NX, here's what happens:
- NX loads the
workspace.jsonfile to know about the different applications and libraries
- It executes the requested operation (let's imagine a build of the Svelte app)
- When the Svelte app is being built, NX knows which executor to launch to take care of the grunt's work
- The Svelte NX plugin executor loads its configuration and notices the
svelteConfigoption. It loads the corresponding file (i.e.,
svelte.config.cjs), and updates its default build configuration accordingly
To install Tailwind, we need to add a few packages to our project, as explained in the official documentation:
We'll also install a few additional ones:
Next up we'll configure Tailwind.
To configure Tailwind, create a file called
tailwind.config.js at the root of the NX workspace with the following contents:
Now, we need to configure PostCSS.
PostCSS is a CSS processor that Tailwind relies on to do its magic.
The details about PostCSS are out of scope for this article, but let me explain something anyway. One thing you need to understand is that PostCSS can be used to define a processing pipeline for CSS code. The very first step of that pipeline receives the CSS as you wrote it, and processes it in some way. Then, the next step receives the result of the previous one and applies its own processing. And so on and so on. Now that you know this, you'll understand that the order of the elements in the configuration below does matter.
Go ahead and create a file called
postcss.config.js at the root of the NX workspace, with the following contents:
What does this do?
- First, we apply the
postcss-importplugin, which adds support for the
@importsyntax in our CSS code
- Second, we enable Tailwind and its support for CSS nesting
- Third, we enable the
postcss-preset-envplugin, which adds support for many other cool things
Alright, our CSS processing pipeline is configured!
Loading our PostCSS configuration
By default, the Svelte plugin for Nrwl NX uses its own Svelte preprocessing configuration. To make sure that our PostCSS configuration is loaded, we need to adapt the Svelte configuration file that we saw earlier.
Open up the
svelte.config.cjs file under
apps/<app name> and adapt it as follows:
As you can see, all we did was pass a configuration to the
sveltePreprocess method and define the
postcss configuration, associating it with an empty object. We only did this to replace the default
postcss configuration included by the Svelte NX plugin. This ensures that our own PostCSS configuration is loaded.
Load Tailwind in the Svelte application
We're almost ready to start using Tailwind in our code.
The next thing we need to do is load the default styles of Tailwind. To do so, go ahead and create a file called
apps/<app name>/src, with the following contents:
There are a few things to notice here:
- We have marked the styles as
globalto make sure that those get applied on the global scope
- We have set
lang="postcss"to state that we're using PostCSS
- We have loaded Tailwind's global styles using the
Next, we need to load and use our Tailwind component inside the
App component. Open the
src/<app name>/src/App.svelte file and adapt the contents as follows:
What we did here is simply import the
Tailwind.svelte file, and use it.
We're done with the configuration! Great.
Running the application
To run the application, we can now use the following command:
npx nx serve <app_name>
I recommend getting used to the
nx command, which is the CLI of Nrxl NX.
If you're anything like me, then you might want to update the
scripts section of your
The names of the script should be self-descriptive. Just replace
<app_name> with the application name you've chosen.
To run our application, we can now use
To learn more, make sure to look at the NX CLI documentation.
Alright, we can now start playing with Tailwind!
Let's look at a few ways we can use Tailwind in our Svelte application. Edit the
App.svelte file again as follows:
In this example, we've used Tailwind in three different ways:
- Inside the HTML template, we've used
class="..."to modify the styles of an element using Tailwind. This is the approach you can find in most Tailwind examples out there
- Inside the
styletag, we've defined global styles by using the
:globalscope supported by Svelte, and we've defined our styles using the
- Inside the
styletag, we've defined a class called
example, in which we've also used
@apply. This approach creates locally scoped styles that only exist for the current component.
If you look at the application now, it should look like this:
If you're in a hurry, then you can use the template I've prepared and published on Github with the results of this experiment. You can find it here: https://github.com/dsebastien/svelte-tailwind-nx-template
In this article, I've explained how to create a Svelte application using Nrwl NX. I've also covered how to add Tailwind support. Hopefully, this will have taught you a few things about how to configure Svelte applications, PostCSS and Tailwind.
That's it for today! ✨