Building a Vue3 Typescript Environment with Vite

Introduction
Vite is a build tool developed by Evan You, the author of Vue. It uses native ES Module imports to provide a fast running development environment with no bundling required. Vue3, React and Preact are also supported.
In this article, I'll build a Vue3 project environment using Vite.
You can find the template in here.
Things to do
The goal is to get you close to the default vue/cli template, and I'll implement the necessary tools for development. I'm going to walk you through each of these tools so that you can introduce them individually.
Typescript- ESLint
- Prettier
- Stylelint
- husky and lint-staged
- Path Alias
- vue-tsc
Building Environments
Verified in the next version:
@vitejs/create-app@2.4.5
First, let's expand the vite template.
npm init @vitejs/app <project-name> -- --template vue-ts
cd <project-name>
npm iOnce the development server is up, you'll be impressed by how fast it is.
⤵️ No longer needed.
Typescript
Next, let's make your project Typescripted. Since Vue3 has Typescript by default, you only need to do the following three things.
1.Add lang="ts"to the scripttag in all .vuefiles. 2.Change main.jsto main.ts. 3.Change the src of the script tag ofindex.htmlto /src/main.ts.
Now you can start up the development server and see that it runs without any problem.
It will actually work on its own, but you can add more settings to improve the user experience in the editor.
If you're using VSCode, you should see a main.tswith a ts(2307)error.
To fix this, need to create a type declaration file for vue.
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<Record<string,unknown>, Record<string,unknown>, unknown>
export default component
}Place the tsconfig.jsonin your project root. This will tell the editor to recognize the project as a Typescript project.
{
"compilerOptions": {
"target": "es5",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node",
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"baseUrl": ".",
"paths": {
"/@/*": [ // / to begin with.
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
],
"exclude": [
"node_modules"
]
}That's the end of Typescript.
Introducing ESLint
Development without a linter is tough, so be sure to install it.
npm i -D eslint eslint-plugin-vue @vue/eslint-config-typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin{
"root": true,
"env": {
"browser": true,
"es2021": true,
"node": true
},
"extends": [
"plugin:vue/vue3-recommended",
"eslint:recommended",
"@vue/typescript/recommended"
],
"parserOptions": {
"ecmaVersion": 2021
},
"plugins": [
],
"rules": {
}
}This will result in an error, so we will modify the type definition.
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<Record<string,unknown>, Record<string,unknown>, unknown>
export default component
}It is easy to prepare a linting command in the script of the package.json for later.
"scripts": {
"lint:script": "eslint --ext .ts,vue --ignore-path .gitignore ."
}Personally, I don't want to fix some situations, so I use --fix from outside.
Now let's run this.
npm run lint:script --fixVSCode users can also set up the following settings to make the automatic formatting work. An extension to ESLint is required, so if you don't have it, please install it see here.
{
"editor.codeActionsOnSave": {
"source.fixAll": true
}
}This allowed me to format the file on save.
Configuring husky and lint-staged
Before committing, let's run a static check to make sure you can't commit the error code.
npm i -D husky lint-stagedAdd the following to package.json.
{
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"*.{ts,vue}": "eslint --fix"
}
}This causes ESLint to run against any files with the appropriate extensions in the commit file before you commit.
Of course, on a linting error, the commit is canceled.
Configuring Prettier
Let Prettier do the formatting for your entire project. Also, let Prettier automatically remove semicolons in Typescript code.
npm i -D prettier eslint-plugin-prettier @vue/eslint-config-prettier{
"singleQuote": true,
"semi": false,
"vueIndentScriptAndStyle": true
}When ESLint and Prettier are used together, I need to fix the .eslintrc to avoid duplicate rules.
{
"extends": [
"plugin:vue/vue3-recommended",
"eslint:recommended",
"@vue/typescript/recommended",
// Add under other rules
"@vue/prettier",
"@vue/prettier/@typescript-eslint"
]
}command to execute the formatter.
npm run prettier -w -u .I want to apply automatic formatting before committing, so add the setting to lint-staged.
{
"lint-staged": {
"*.{ts,vue}": "eslint --fix",
"*": "prettier -w -u" // Set prettier to last
}
}VSCode users can format it automatically with the following settings. Also, an extension is required, so if it is not available, please install it here.
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
}Configuring Stylelint
Let's make the style a target for linting as well.
npm i -D stylelint stylelint-config-recommended stylelint-config-standard{
"extends": ["stylelint-config-recommended", "stylelint-config-standard"]
}Edit the package.json and set the commands and lint-staged.
{
"scripts": {
"lint:style": "stylelint src/**/*.{css,scss,vue}"
},
"lint-staged": {
"*.{ts,tsx}": "eslint --fix",
"*.{css,scss,vue}": "stylelint --fix",
"*": "prettier -w -u"
}
}VSCode users can format it automatically with the following settings. Extensions are required, so if you don't have them, install them see here.
That's the end of the basic setup of the linker and formatter.
Configuring Path Alias
The import of the module is relative by default, but you want to set an alias to always refer to the same root.
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'
export default defineConfig({
resolve: {
alias: {
'@': resolve(__dirname, 'src')
}
},
plugins: [vue()]
})Also change tsconfig.json.
{
"compilerOptions": {
//...
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}Now you can set up alias. I'll use it like this.
<script lang="ts">
import HelloWorld from '@/components/HelloWorld.vue'
</script>Checking template statically with vue-tsc
You can statically check your template tags with vue-tsc.
It is installed when the template is generated. However, as of @vue/runtime-dom@3.1.4, it does not work unless skipLibCheck in tsconfig.json is set to true.
{
"compilerOptions": {
//...
"skipLibCheck": true
},
}{
"scripts": {
//...
"lint:markup": "vue-tsc --noEmit",
}
}I recommend running static checks in CI rather than before committing, as static checks can take quite a bit of time as the number of Vue files increases.
That's the minimum environment you'll need to build.