How to setup VueJS 3 with Vite, UnoCSS and ESLint/Prettier

J. David Mendoza
5 min readAug 31, 2023

This is an updated version of this article. This other article is now 2 years old and I’ve picked up some other tools since then. So now I’m using pnpm instead of yarn, and unocss instead of tailwindcss.

Let’s start by opening a terminal and typing:

pnpm create vite todos

It will ask if you want to use a JavaScript framework. Let’s go with Vue. It will also add if you want to use TypeScript or JavaScript. I will strongly suggest to select TypeScript instead of JavaScript and gradually add some TypeScript into your code.

Now move into the folder, install the dependencies and start it.

cd todos
pnpm i
pnpm dev

This will start the vite server on port 5173 by default, so if you open it in a browser you’ll see something like this:

Like I mentioned at the beginning of the post, I’ve started using UnoCSS instead of TailwindCSS after reading this post by Anthony Fu.

To get it working I install the following packages on the todos project (if it’s still running just press Command + C on a mac or Ctrl + C on windows/linux):

pnpm add -D @iconify/json @julr/unocss-preset-forms \
@unocss/preset-icons @unocss/preset-typography \
@unocss/preset-uno @unocss/transformer-directives unocss

Let’s go through what we’re doing with this instruction. First of all, we’re adding these dependencies to the dev dependencies (dependencies that are used to make your build, but won’t be part of your build). I’m adding iconofy which will enable our project to use any of these icon packs. Then I add a set of presets that extend how I use UnoCSS. I’ll show you later the steps required to setting them up inside of UnoCSS. After the presets I add transformer directives, which will allow us to do something like @apply bg-red-100 in a css class. And finally I’m adding the unocss dependency.

We need to add another dependency to help us with how the different browsers render our page. This dependency is going to be part of our build, so we need to add it to the other set of dependencies.

pnpm add @unocss/reset

Now we need to configure UnoCSS. Please open the vite.config.ts file and add the UnoCSS plugin:

// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import UnoCSS from 'unocss/vite'

// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue(), UnoCSS()],
})

Then we need to add the uno.config.ts along side the vite.config.ts file with the following configuration:

// uno.config.ts
import {
defineConfig,
presetIcons,
presetTypography,
presetUno,
presetWebFonts,
transformerDirectives
} from 'unocss'
import { presetForms } from '@julr/unocss-preset-forms'

export default defineConfig({
presets: [
presetIcons({
extraProperties: {
display: 'inline-block',
'vertical-align': 'middle'
}
}),
presetForms(),
presetUno(),
presetTypography(),
presetWebFonts({
provider: 'google',
fonts: {
sans: 'Open Sans:100,200,300,400,500,600,700'
}
})
],
transformers: [transformerDirectives()]
})

Ok, our last step to configure UnoCSS on our project is to add a couple of lines in the src/main.ts file.

import { createApp } from 'vue'
import '@unocss/reset/tailwind.css'
import 'virtual:uno.css'
import './style.css'
import App from './App.vue'

createApp(App).mount('#app')

You’ll notice that I’ve added 2 lines above the style.css import. The first one adds the reset css so that our page looks the same on the different browsers. And the next line is needed to add UnoCSS.

Let’s check if this works by modifying our src/style.css:

html {
font-family: 'Open Sans', Verdana, Geneva, Tahoma, sans-serif;
}

body {
@apply bg-gray-700 text-white;
}

With this we’re making sure we‘ve enabled the transform directives. And now let’s test the UnoCSS classes by modifying our src/App.vue:

<template>
<div class="container mx-auto max-w-prose p-2 min-h-screen flex items-center justify-center">
<h1 class="text-5xl tracking-widest">TODOS</h1>
</div>
</template>

We’ve configured UnoCSS and added the classes, now let’s run it and see if it worked. To do that, we need to go to the terminal again and run:

pnpm dev

Open a browser in localhost:5173 and we should see something like this:

See how our background is dark gray and our TODOS title is white? This was set in the src/style.css file with the @apply instruction. Then in the src/App.vue file we added some html with a lot of CSS classes, all part of UnoCSS. I won’t go into to much detail on why you should use it, just know that ever since I picked it up (back when I was using TailwindCSS) it has made my CSS Styling life so much easier.

The title mentions ESLint and Prettier. If you don’t know what these tools are for let me give you a brief explanation. ESLint will look into your JavaScript for patterns that are not good practice and point it out so you know that you shouldn’t do that. Prettier on the other hand (as the name implies) is used to format your code so it looks, well, prettier.

We need to add the ESLint and Prettier packages in the terminal by running:

pnpm add -D @typescript-eslint/parser eslint eslint-config-prettier \
eslint-plugin-prettier eslint-plugin-vue \
prettier stylelint stylelint-config-recommended typescript

If you read through the dependencies you’ll notice that I’m adding a dependency called StyleLint, this one is used to make your CSS prettier.

To configure them we need to add a couple of files on our root of our project. The first one is the .eslintrc.cjs file:

module.exports = {
env: {
browser: true,
node: true,
es2021: true
},
extends: ['eslint:recommended', 'plugin:vue/vue3-recommended', 'prettier'],
parser: 'vue-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser'
// sourceType: 'module',
},
plugins: ['vue', 'prettier'],
rules: {
'vue/no-v-html': 'off',
'vue/multi-word-component-names': 'off',
'prettier/prettier': ['error']
}
}

The next one is the .prettierrc.cjs file:

module.exports = {
semi: false,
singleQuote: true,
tabWidth: 4,
trailingComma: 'none'
}

With that we’ve configured both ESLint and Prettier. Now we need to configure StyleLint by creating the stylelint.config.cjs file right next to them:

module.exports = {
extends: ['stylelint-config-recommended'],
rules: {
indentation: 4,
'at-rule-no-unknown': [
true,
{
ignoreAtRules: [
'tailwind',
'apply',
'variants',
'responsive',
'screen'
]
}
],
'declaration-block-trailing-semicolon': null,
'no-descending-specificity': null
}
}

Please notice that this file does not start with a dot (.). Let’s work on getting VSCode to apply these rules for us on save (the other option is to create tasks in the package.json that we can run manually, but who wants to do that when VSCode can do it for you, right?). We need to create the .vscode/settings.json file:

{
"eslint.validate": ["vue", "javascript", "typescript"],
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true,
"source.fixAll.stylelint": true
},
"editor.quickSuggestions": {
"other": true,
"comments": false,
"strings": true
},
"css.validate": false
}

That’s it! Now when you reload your VSCode, and you start coding inside your vue, typescript and css files, they should auto format on save.

--

--

J. David Mendoza

Software developer interested in providing easy to use solutions.