Giới thiệu
Chào tất cả các bạn, phần 1 mình đã giới thiệu tổng quát về source code và setup cơ bản về Vue 3 + Vite. Trong bài này mình tiếp tục tìm hiểu về và setup về vue-router, pinia và Vitest
Nội Dung
- ⚡️ Vue 3, Vite, pnpm
- 📦 Components auto importing
- 🎨 UnoCSS – 1 thư viện lấy ý tưởng từ Windi CSS, Tailwind CSS và Twind. ( Khá hay)
- 😃 Use icons from any icon sets with classes
- 📥 APIs auto importing – import tự động sử dụng Composition API,..
- 🦾 TypeScript, of course
- 🍍 State Management via Pinia, Vue Router
- ⚙️ Unit Testing với Vitest
Đây là cấu trúc thư mục của dự án sau khi 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 |
Cài đặt
Trong phần này mình sẽ hướng dẫn các bạn setup về:
🍍 State Management via Pinia, Vue Router
⚙️ Unit Testing với Vitest
Bây giờ chúng ta sẽ cài vue-router và pinia từ PNPM vào dự án của mình.
Vue Router
vue-router là bộ định tuyến chính thức cho Vue.js. Chúng ta sẽ cần cài đặt version 4 tương thích với Vue 3:
1 2 | $ <span class="token function">pnpm</span> i vue-router@4 |
Tạo 1 folder routes và tạo 1 file index.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 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 route vào file main.ts
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 là một trong những project mới nhất xuất hiện từ hệ sinh thái Vue và nó là công cụ quản lý trạng thái (State Management) chính thức mới cho các ứng dụng Vue.js. Api của nó rất giống với Vuex (tiền thân của nó) và nó được thiết kế để nhanh hơn và nhẹ hơn.
1 2 | $ <span class="token function">pnpm</span> i pinia |
Tạo 1 folder stores và tạo 1 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 vào file main.ts
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 là 1 unit test framework chạy rất nhanh được cung cấp bởi Vite.
Vitest requires Vite >=v3.0.0 and Node >=v14
1 2 | $ <span class="token function">pnpm</span> i -D vitest |
thêm script chạy test vào 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> |
Chúng ta sẽ thử viết 1 vài đoạn test trong file sample.spec.ts để kiểm tra test nó đã hoạt động hay chưa.
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> |
Sau đó chúng ta chạy pnpm run test và kết quả là:
Kết bài
Ở phần này chúng ta đã cùng nhau tìm hiểu và setup vue-router, pinia và testing. Ở phần tiếp theo chúng ta sẽ cùng nhau tìm hiểu về và setup eslint, prettierrc và rule commitlint.
Nguồn
https://github.com/trungpham71198/vue-template/tree/feat/chapter-2