In this walk through I show my preferred setup for SPAs with Svelte, Typescript and Tailwind.
11/04/2021 Update: If you use SvelteKit check out this update blog posthttps://www.liip.ch/en/blog/sveltekit-and-tailwind-windi-css
TL;DRFor the very impatient among us:
npx degit munxar/svelte-template my-svelte-project
cd my-svelte-project
npm i
npm run dev
Enjoy!
OverviewIn this article I'll give you some insights how I set up Svelte with TypeScript and style components with Tailwind. There are plenty of articles around, but I found a lot of them overcomplicate things, or don't fit my requirements.
So here are my goals for the setup:
You'll need at least some node version with npm on your machine. At time of writing I have node version 15.6.0 and npm version 7.4.0 installed on my machine.
node -v && npm -v
v15.6.0
7.4.0
Install the Svelte Default Template
To setup Svelte I open a terminal and use the command from the official Svelte homepage. TypeScript support has been already added to this template, so nothing special here.
npx degit sveltejs/template my-svelte-project
# or download and extract
cd my-svelte-project
Enable TypeScript
# enable typescript support
node scripts/setupTypeScript.js
At this point I try out if the setup works by installing all dependencies and start the development server.
# install npm dependencies
npm i
# run dev server
npm run dev
If everything worked so far, pointing my browser at http://localhost:5000 displays a friendly HELLO WORLD. Let's stop the development server by hitting ctrl-c
in the terminal.
Back in the Terminal I add Tailwind as described in their documentation.
npm install -D tailwindcss@latest postcss@latest
After this step I generate a default tailwind.config.js file with
npx tailwindcss init
Configure Rollup to use PostcssIf you prefer a full Tailwind config use the --full argument:
npm tailwindcss init --full
See the Tailwind documentation for more infos about this topic.
The default Svelte template uses Rollup as a bundler. When I run the setupTypeScript.js from the first setup step, I get the famous svelte-preprocess plugin already integrated into the rollup setup. The only thing left is that I add the config for postcss as options to the svelte-preprocess plugin. Here are the changes that I make in rollup.config.js:
// rollup.config.js (partial)
...
export default {
...
plugins: [
svelte({
preprocess: sveltePreprocess({
postcss: {
plugins: [require("tailwindcss")],
},
}),
}),
...
],
...
};
At this point Rollup should trigger postcss and therefore the Tailwind plugin. To enable it in my application, I still need one important step.
Adding a Tailwind Component to the AppNow it's time to create a Svelte component that contains the postcss to generate all the classes. I call mine Tailwind.svelte but the name doesn't really matter.
// src/Tailwind.svelte
<style global lang="postcss">
@tailwind base;
@tailwind components;
@tailwind utilities;
</style>
Some things to note here:
Now use the Tailwind component in src/App.svelte
// src/App.svelte
<script lang="ts">
import Tailwind from "./Tailwind.svelte";
</script>
<Tailwind />
<div class="bg-gray-200 px-4 py-2 rounded">Hello Tailwind!</div>
Now my browser displays a Tailwind styled div. Very nice!
Let's clean up the public/index.html and remove the global.css link tag and remove the corresponding file from public/global.css I don't use it.
<!-- public/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset='utf-8'>
<meta name='viewport' content='width=device-width,initial-scale=1'>
<title>Svelte app</title>
<link rel='icon' type='image/png' href='/favicon.png'>
<link rel='stylesheet' href='/build/bundle.css'>
<script defer src='/build/bundle.js'></script>
</head>
<body>
</body>
</html>
Let's finish the setup for production builds. Right now it's perfect for development. I can use any Tailwind class and except for the first start of the development server, where all the Tailwind classes get generated, it behaves very snappy on rebuilds.
Production Builds PurgeWhen it comes to production builds, right now I have not configured anything so I'll get a bundle.css with all Tailwind classes. I don't want that for a production build, so I modify the tailwind.conf.js to use it's integrated purgecss for that purpose.
// tailwind.config.js
module.exports = {
purge: ["src/**/*.svelte", "public/index.html"],
darkMode: false, // or 'media' or 'class'
theme: {
extend: {},
},
variants: {
extend: {},
},
plugins: [],
};
With this modification Tailwind removes all classes that are not used in .svelte files and in the public/index.html html file. I added the public/index.html file because sometimes I add containers or some responsive design utilities directly on the tag. If you don't need this, you can remove the index.html file from the purge list, or add additional files I don't have listed here. For example: if I use some plugins that contain .js, .ts, .html, ... files that use Tailwind classes, I would add them to this purge array too.
There is one little detail about the Tailwind purge: it only is executed if NODE_ENV=production which makes sense. I set this environment directly in my package.json scripts:
// package.json (partial)
{
...
"scripts": {
"build": "NODE_ENV=production rollup -c",
...
},
...
}
With these settings my bundle.css only contains the Tailwind classed I really use, plus the mandatory css reset code that Tailwind provides.
AutoprefixerOne last thing to add for production is vendor prefixes. I usually go with the defaults and just add autoprefixer as postcss plugin. If you need more control, add configuration as you please.
Install autoprefixer with npm:
npm i -D autoprefixer
Add it as postcss plugin in rollup.config.js:
// rollup.config.js (partial)
{
...
preprocess: sveltePreprocess({
postcss: {
plugins: [
require("tailwindcss"),
require("autoprefixer"),
],
},
})
...
}
That's it.
Features of this Setup Tailwind ClassesI can apply every Tailwind class on a every html element even in the index.html template.
Tailwind @applyAdditionaly I can use @apply inside a style tag of a Svelte component like this:
<!-- src/Button.svelte -->
<button>
<slot />
</button>
<style lang="postcss">
button {
@apply bg-blue-800 text-white px-3 py-2 rounded hover:bg-blue-900;
}
</style>
This will generate a class scoped to the button of this component. Important part here is the attribute lang="postcss", without this postcss would not process the content of the style tag.
Typesave ComponentsLet's implement a simple logo component with an attribute name of type string and a default value of "Logo".
<!-- src/Logo.svelte -->
<script lang="ts">
export let name = "Logo";
</script>
<div>{name}</div>
When I use this component the svelte language service of my IDE (visual studio code) will yell at me, if I try to pass something as the name attribute that is not of type string.
<!-- src/App.svelte -->
<script lang="ts">
import Logo from "./Logo.svelte";
</script>
<!-- this results in an error -->
<Logo name={42} />
<!-- valid type -->
<Logo name="Hello, World" />
<!-- valid because of the default value -->
<Logo />
If you have a IDE that supports the svelte language service, you get all the intellisense stuff you would expect inside your editor. I use Visual Studio Code with the very good svelte.svelte-vscode extension.
RecapI demonstrated how easy it is to setup a Svelte project with the default template enable TypeScript and add production ready Tailwind support.
I hope you find some helpful information and write some amazing apps!
The source code is available at: https://github.com/munxar/svelte-template
Update - 23. Feb. 2021A few days after my blog post a fantastic library named windicss was released.
Check out my repo:
npx degit munxar/svendi my-svendi-project
cd my-svendi-project
npm i
npm run dev
Do you have a question, a comment, or just feeling inspired? Mention us or share this article on Mastodon or LinkedIn.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4