One way to bootstrap Vue3 project

npm create vite@latest
$ npm create vite@latest
...
○ → npm create vite@latest
> npx
> create-vite
│
◇ Project name:
│ vite-project
│
◇ Select a framework:
│ Vue
│
◇ Select a variant:
│ TypeScript
│
◇ Scaffolding project in /Users/.../workspace/kerja/vite-project...
│
└ Done. Now run:
cd vite-project
npm install
npm run dev
The scaffolded project is very bare bone. It is missing a few crucial components which we will install later in this page:
Code error finding formatting. We will use ESLint.
Unit testing library. We will use Vitest.
UI framework. We will use Vuetify.
State management. We will use Pinia
Install and setup ESLint
Add the following libraries
$ npm i -D eslint
$ npm i -D eslint-config-vuetify
Because we will use Vuetify as well, we use and configure eslint-config-vuetify. Which is an opinionated configuration that will find error and provide formatting as well.
And add the config file eslint.config.js to the root of the project with the following content:
import vuetify from 'eslint-config-vuetify'
export default vuetify()
Then enable the Automatic ESLint configuration in WebStorm
Install vitest for unit test
First, create a new empty component in the src/components
directory
Once created, we can use TDD to implement the component.
Install the following libraries:
$ npm i -D vitest
$ npm i -D @vue/test-utils
vitest
will give you the infrastructure to run the test just like Jest
@vue/test-utils
will give you mount() function among other things
Then add a test in tests/components
called Rando.spec.ts
import { mount } from '@vue/test-utils'
import { describe, expect, it } from 'vitest'
import Rando from '../../src/components/Rando.vue'
describe('Rando tests', () => {
it('should render component', async () => {
// action
const wrapper = mount(Rando, {
props: {
msg: 'Message from Rando',
},
})
// assert
expect(wrapper.text()).toContain('Message from Rando')
})
})
When you run the test, it will error
ReferenceError: document is not defined
This can be fixed by installing and configuring jsdom
library:
$ npm i -D jsdom
Then add the following in the vite.config.ts
file:
export default defineConfig({
...
test: {
environment: 'jsdom',
},
})
To fix the “no overload matches this call” error (actually just a warning):
// replace
import { defineConfig } from 'vite'
// with
import { defineConfig } from 'vitest/config'
Run the test again, and the error will allow you to do the implementation:
AssertionError: expected '' to contain 'Message from Rando'
Expected :Message from Rando
Actual :
Implementation for Rando.vue
to “fix” the test:
<script setup lang="ts">
defineProps<{ msg: string }>()
</script>
<template>
<p>{{ msg }}</p>
</template>
The test should now pass
Install and configure Vuetify
Follow the documentation: https://vuetifyjs.com/en/getting-started/installation/#existing-projects
$ npm i vuetify
And update the main.ts
Before:
import { createApp } from 'vue'
import App from './App.vue'
import './style.css'
createApp(App).mount('#app')
After:
import { createApp } from 'vue'
import { createVuetify } from 'vuetify'
import * as components from 'vuetify/components'
import * as directives from 'vuetify/directives'
import App from './App.vue'
import './style.css'
const vuetify = createVuetify({
components,
directives,
})
createApp(App).use(vuetify).mount('#app')
To make sure main.ts
is clean, you can also do the following:
...
import { vuetify } from './plugins/vuetify.ts'
...
createApp(App).use(vuetify).mount('#app')
And create new file /src/plugins/vuetify.ts
that contain all the definitions:
import { createVuetify } from 'vuetify'
import * as components from 'vuetify/components'
import * as directives from 'vuetify/directives'
import { mdi } from 'vuetify/iconsets/mdi-svg'
import 'vuetify/styles/main.css'
export const vuetify = createVuetify({
components,
directives,
icons: {
defaultSet: 'mdi',
sets: { mdi },
},
})
Add a similar test and component like Rando as above, but instead of <p>
, use vuetify component such as <v-card>
When you run the test, will get following warning:
[Vue warn]: Failed to resolve component: v-card-title
If this is a native custom element, make sure to exclude it from component resolution via compilerOptions.isCustomElement.
at <Morning msg="Good Morning" ref="VTU_COMPONENT" >
at <VTUROOT>
To fix this, update the mount to pass the vuetify:
...
import * as components from 'vuetify/components'
import * as directives from 'vuetify/directives'
...
const wrapper = mount(Morning, {
props: {
msg: 'Good Morning',
},
global: {
plugins: [createVuetify({ components, directives })],
},
})
Now when you re-run the test, you will get the following error:
TypeError: Unknown file extension ".css" for /Users/erfanjap/workspace/kerja/vite-2/node_modules/vuetify/lib/components/VCode/VCode.css
at Object.getFileProtocolModuleFormat [as file:] (node:internal/modules/esm/get_format:219:9)
at defaultGetFormat (node:internal/modules/esm/get_format:245:36)
at defaultLoad (node:internal/modules/esm/load:120:22)
at ModuleLoader.loadAndTranslate (node:internal/modules/esm/loader:580:32)
To fix this, update vite.config.ts
with the following:
export default defineConfig({
...
test: {
...
server: {
deps: {
inline: ['vuetify'],
},
},
},
})
Run the test again, and now it should be OK
Extra:
...
import * as components from 'vuetify/components'
import * as directives from 'vuetify/directives'
// add these imports to import vuetify icons and css/styles
import { mdi } from 'vuetify/iconsets/mdi-svg'
import 'vuetify/styles/main.css'
...
export const vuetify = createVuetify({
components,
directives,
icons: {
defaultSet: 'mdi',
sets: { mdi },
},
})
Install and setup Pinia
First, install Pinia
$ npm i pinia
Then set it up in main.ts
import { createPinia } from 'pinia'
...
const pinia = createPinia()
...
createApp(App)
...
.use(pinia)
.mount('#app')
Then define a store in a directory src/stores
// src/stores/app.ts
import { defineStore } from 'pinia'
import { ref } from 'vue'
export const useAppStore = defineStore('app', () => {
const someName = ref('John Doe')
return { someName }
})
To use the app store, in the component:
<script setup lang="ts">
import { useAppStore } from '../stores/app'
const store = useAppStore()
</script>
<template>
<p>{{ store.someName }}</p>
</template>
That’s All :-)
Subscribe to my newsletter
Read articles from EJ directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
