Introduce
Hello everyone, in part 1 , I gave an overview of the source code and basic setup of Vue 3 + Vite. In this article, I continue to learn about and setup vue-router , pinia and Vitest
Content
- β‘οΈ Vue 3 , Vite , pnpm
- π¦ Components auto importing
- π¨ UnoCSS – 1 library inspired by Windi CSS, Tailwind CSS and Twind. ( Pretty good)
- π Use icons from any icon sets with classes
- π₯ APIs auto import – import automatically using Composition API,..
- π¦Ύ TypeScript , of course
- π State Management via Pinia , Vue Router
- βοΈ Unit Testing with Vitest
This is the folder structure of the project after setup.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | vue-template/ βββ public/ | βββ favicon.ico βββ src/ | βββ assets/ | | βββ logo.png | βββ components/ | | βββ HelloWorld.vue | βββ core/ | βββ hooks/ | | βββ useAuth.ts | βββ layouts/ | | βββ BlankLayout.vue | | βββ MainLayout.vue | βββ pages/ | | βββ Dashboard.vue | | βββ Error.vue | | βββ NotFound.vue | βββ routes/ | | βββ index.ts | βββ stores/ | | βββ auth.ts | βββ test/ | | βββ components/ | | | βββ Sample.spec.ts | βββ App.vue | βββ main.ts | βββ vite-env.d.ts | βββ vue-shim.d.ts βββ package.json βββ README.md βββ .cz-config.ts βββ .env.sample βββ .eslintrc βββ .prettierrc βββ .commitlint.config.cjs βββ tsconfig.json βββ tsconfig.node.json βββ vite.config.js βββ unocss.config.ts |
Setting
In this section, I will guide you to setup:
π State Management via Pinia , Vue Router
βοΈ Unit Testing with Vitest
Now we will install vue-router and pinia from PNPM into our project.
Vue Router
vue-router is the official router for Vue.js. We will need to install version 4 compatible with Vue 3 :
1 2 | $ <span class="token function">pnpm</span> i vue-router@4 |
Create a routes folder and create an index.ts . file
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | <span class="token comment">// index.ts</span> <span class="token keyword">import</span> <span class="token punctuation">{</span> createRouter <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vue-router'</span> <span class="token keyword">import</span> Homepage <span class="token keyword">from</span> <span class="token string">'./home/Home.vue'</span> <span class="token punctuation">;</span> <span class="token keyword">import</span> SignIn <span class="token keyword">from</span> <span class="token string">'./sign-in/SignIn.vue'</span> <span class="token punctuation">;</span> <span class="token keyword">import</span> Cart <span class="token keyword">from</span> <span class="token string">'./cart/Cart.vue'</span> <span class="token punctuation">;</span> <span class="token keyword">export</span> <span class="token keyword">const</span> routes <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> path <span class="token operator">:</span> <span class="token string">'/'</span> <span class="token punctuation">,</span> component <span class="token operator">:</span> MainLayout <span class="token punctuation">,</span> requiresAuth <span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">,</span> children <span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> path <span class="token operator">:</span> <span class="token string">'dashboard'</span> <span class="token punctuation">,</span> name <span class="token operator">:</span> <span class="token string">'Dashboard'</span> <span class="token punctuation">,</span> <span class="token function-variable function">component</span> <span class="token operator">:</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">import</span> <span class="token punctuation">(</span> <span class="token string">'@pages/DashBoard.vue'</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> meta <span class="token operator">:</span> <span class="token punctuation">{</span> requiresAuth <span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">,</span> headerTitle <span class="token operator">:</span> <span class="token string">'Dashboard'</span> <span class="token punctuation">,</span> searchConfig <span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> storeConfig <span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> path <span class="token operator">:</span> <span class="token string">'/login'</span> <span class="token punctuation">,</span> component <span class="token operator">:</span> BlankLayout <span class="token punctuation">,</span> children <span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> path <span class="token operator">:</span> <span class="token string">'login'</span> <span class="token punctuation">,</span> name <span class="token operator">:</span> <span class="token string">'Login'</span> <span class="token punctuation">,</span> <span class="token function-variable function">component</span> <span class="token operator">:</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">import</span> <span class="token punctuation">(</span> <span class="token string">'@pages/Login.vue'</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> path <span class="token operator">:</span> <span class="token string">'/:pathMatch(.*)*'</span> <span class="token punctuation">,</span> name <span class="token operator">:</span> <span class="token string">'Page Not Found'</span> <span class="token punctuation">,</span> <span class="token function-variable function">component</span> <span class="token operator">:</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">import</span> <span class="token punctuation">(</span> <span class="token string">'@pages/NotFound.vue'</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> path <span class="token operator">:</span> <span class="token string">'/error'</span> <span class="token punctuation">,</span> name <span class="token operator">:</span> <span class="token string">'Error'</span> <span class="token punctuation">,</span> <span class="token function-variable function">component</span> <span class="token operator">:</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token keyword">import</span> <span class="token punctuation">(</span> <span class="token string">'@pages/Error.vue'</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token punctuation">(</span> <span class="token parameter">history</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">createRouter</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> history <span class="token punctuation">,</span> routes <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> |
Import routes into main.ts . file
1 2 3 4 5 6 | <span class="token keyword">import</span> router <span class="token keyword">from</span> <span class="token string">'./router'</span> <span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">createApp</span> <span class="token punctuation">(</span> App <span class="token punctuation">)</span> app <span class="token punctuation">.</span> <span class="token function">use</span> <span class="token punctuation">(</span> router <span class="token punctuation">)</span> <span class="token operator">...</span> |
Pinia
Pinia is one of the newest projects to emerge from the Vue ecosystem and it is the new official State Management tool for Vue.js applications. Its api is very similar to Vuex (its predecessor) and it is designed to be faster and lighter.
1 2 | $ <span class="token function">pnpm</span> i pinia |
Create a folder stores and create a file auth.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | <span class="token keyword">import</span> <span class="token punctuation">{</span> defineStore <span class="token punctuation">,</span> acceptHMRUpdate <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'pinia'</span> <span class="token keyword">interface</span> <span class="token class-name">IUser</span> <span class="token punctuation">{</span> email <span class="token operator">:</span> string name <span class="token operator">:</span> string <span class="token punctuation">}</span> <span class="token keyword">export</span> <span class="token keyword">const</span> useAuthStore <span class="token operator">=</span> <span class="token function">defineStore</span> <span class="token punctuation">(</span> <span class="token string">'auth'</span> <span class="token punctuation">,</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> isLoggedIn <span class="token operator">=</span> <span class="token function">ref</span> <span class="token punctuation">(</span> <span class="token boolean">false</span> <span class="token punctuation">)</span> <span class="token keyword">const</span> info <span class="token operator">=</span> ref <span class="token operator"><</span> IUser <span class="token operator">|</span> <span class="token keyword">null</span> <span class="token operator">></span> <span class="token punctuation">(</span> <span class="token keyword">null</span> <span class="token punctuation">)</span> <span class="token keyword">const</span> <span class="token function-variable function">setInfo</span> <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token parameter">user <span class="token operator">:</span> IUser</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> info <span class="token punctuation">.</span> value <span class="token operator">=</span> user <span class="token punctuation">}</span> <span class="token keyword">const</span> <span class="token function-variable function">setIsLoggedIn</span> <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token parameter">value <span class="token operator">:</span> boolean</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> isLoggedIn <span class="token punctuation">.</span> value <span class="token operator">=</span> value <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token punctuation">{</span> isLoggedIn <span class="token punctuation">,</span> info <span class="token punctuation">,</span> setInfo <span class="token punctuation">,</span> setIsLoggedIn <span class="token punctuation">,</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token keyword">import</span> <span class="token punctuation">.</span> meta <span class="token punctuation">.</span> hot <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">import</span> <span class="token punctuation">.</span> meta <span class="token punctuation">.</span> hot <span class="token punctuation">.</span> <span class="token function">accept</span> <span class="token punctuation">(</span> <span class="token function">acceptHMRUpdate</span> <span class="token punctuation">(</span> useAuthStore <span class="token punctuation">,</span> <span class="token keyword">import</span> <span class="token punctuation">.</span> meta <span class="token punctuation">.</span> hot <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> |
Import pinia into main.ts . file
1 2 3 4 5 6 | <span class="token keyword">import</span> <span class="token punctuation">{</span> createPinia <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'pinia'</span> <span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">createApp</span> <span class="token punctuation">(</span> App <span class="token punctuation">)</span> <span class="token operator">...</span> app <span class="token punctuation">.</span> <span class="token function">use</span> <span class="token punctuation">(</span> <span class="token function">createPinia</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token operator">...</span> |
Vitest
Vitest is a very fast unit test framework powered by Vite.
Vitest requires Vite >=v3.0.0 and Node >=v14
1 2 | $ <span class="token function">pnpm</span> i -D vitest |
add test script to package :
1 2 3 4 5 6 7 | <span class="token property">"scripts"</span> <span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"dev"</span> <span class="token operator">:</span> <span class="token string">"vite"</span> <span class="token punctuation">,</span> <span class="token property">"build"</span> <span class="token operator">:</span> <span class="token string">"vue-tsc && vite build"</span> <span class="token punctuation">,</span> <span class="token property">"preview"</span> <span class="token operator">:</span> <span class="token string">"vite preview"</span> <span class="token punctuation">,</span> <span class="token property">"test"</span> <span class="token operator">:</span> <span class="token string">"vitest"</span> <span class="token punctuation">}</span> |
We will try to write some tests in the sample.spec.ts file to check whether the test is working or not.
1 2 3 4 5 6 7 8 | <span class="token keyword">import</span> <span class="token punctuation">{</span> expect <span class="token punctuation">,</span> test <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'vitest'</span> <span class="token function">test</span> <span class="token punctuation">(</span> <span class="token string">'Math.sqrt()'</span> <span class="token punctuation">,</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">expect</span> <span class="token punctuation">(</span> Math <span class="token punctuation">.</span> <span class="token function">sqrt</span> <span class="token punctuation">(</span> <span class="token number">4</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">toBe</span> <span class="token punctuation">(</span> <span class="token number">2</span> <span class="token punctuation">)</span> <span class="token function">expect</span> <span class="token punctuation">(</span> Math <span class="token punctuation">.</span> <span class="token function">sqrt</span> <span class="token punctuation">(</span> <span class="token number">144</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">toBe</span> <span class="token punctuation">(</span> <span class="token number">12</span> <span class="token punctuation">)</span> <span class="token function">expect</span> <span class="token punctuation">(</span> Math <span class="token punctuation">.</span> <span class="token function">sqrt</span> <span class="token punctuation">(</span> <span class="token number">2</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">.</span> <span class="token function">toBe</span> <span class="token punctuation">(</span> Math <span class="token punctuation">.</span> <span class="token constant">SQRT2</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> |
Then we run pnpm run test and the result is:
End
In this part we have learned and setup vue-router , pinia and testing . In the next part we will learn about and set up eslint , prettierrc and the commitlint rule .
The source
https://github.com/trungpham71198/vue-template/tree/feat/chapter-2