Vue 3 + Vite + TypeScript
Tags: vue3, vite, typescript, vuerouter
Published: 2020-08-09 11:19:49

---
title: Vue 3 + Vite + TypeScript
published: true
date: 2020-08-09 08:46:54 UTC
tags: vue3,vite,typescript,vuerouter
canonical_url: 
---

ทดลองเล่น Vue 3 สักหน่อย ไหนๆ ก็มี Vite ให้ก็ลองใช้ Vite ไปด้วย ส่วนใหญ่จะใช้ JavaScript กันเยอะแล้วเลยลองกับ TypeScript ดูด้วยมั่วๆ เอา

# **UPDATE**

เนื่องจากความไม่ชัดแจ้งนักในการเขียนจึงทำให้เข้าใจผิดเกี่ยวกับการ setup project Vite TypeScript สำหรับ Vue 3 ซึ่ง Vite พร้อมใช้งาน TypeScript อยู่แล้วโดยใช้ esbuild เป็นตัว transpile TypeScript จึงขอ Update บทความบางส่วนเพื่อไม่ให้สับสนนะครับ



ใครมือใหม่ยังติดตั้ง Node.js กับ Yarn ไม่เป็นก็ติดตั้งกันก่อนนะครับ

{% youtube 9Icy6FJjkhs %}

#### Code ตัวอย่างสำหรับบทความนี้

[mrchoke/vue3-vite-typescript-ex1](https://github.com/mrchoke/vue3-vite-typescript-ex1)

### Create App

```
yarn create vite-app vue3-typescript-ex1
```

รอแป๊บหนึ่งก็จะได้ directory vue3-typescript-ex1 พร้อม source code ให้เข้าไปและสั่งติดตั้ง packages ต่างๆ

```
cd vue3-typescript-ex1

yarn
```

ถ้าไม่มีปัญหาใดๆ ก็สามารถทำการ dev ได้แล้ว โครงสร้างจะเป็นประมาณนี้

![](https://cdn-images-1.medium.com/max/1024/1*o-xe8G31WKxgrHOD3EWR7g.png)<figcaption>Vue 3 + Vite Project</figcaption>

### Dev

เมื่อเราสร้าง app ได้แล้วติดตั้ง packages เรียบร้อยก็สั่ง

```
yarn dev
```

![](https://cdn-images-1.medium.com/max/873/1*ZqSQpvmpuM3o3gelOUcICQ.png)<figcaption>yran dev output</figcaption>

ตอนนี้สามารถเปิดเว็บ browser ดูผลได้เลยที่

```
[http://localhost:3000/](http://localhost:3000/)
```

![](https://cdn-images-1.medium.com/max/1024/1*UBw9fawyc-us4kOwU7x-ww.png)<figcaption>Vue 3 app</figcaption>

ตอนนี้เราสามารถแก้ไข source code ต่างๆ เมื่อ save ก็จะแสดงผลให้ทันที

### ติดตั้ง TypeScript และ เครื่องมือต่างๆ

#### TypeScript

Vite สามารถใช้ TypeScript ได้ทันที โดยใช้ esbuild โดยไม่ต้องลง TypeScript เพิ่ม แต่ถ้าจะใช้ eslint plugin สามารถติดตั้งได้นะครับ แต่ตอนนี้ผลักภาระให้ vetur ตัวล่าสุดในการจัดการตรวจสอบ code ให้เราแทนนะครับ

#### vue-router

ถือโอกาสลองใช้ vue-router ตัวใหม่สักนิดหน่อย

```
yarn add vue-router@next
```


#### tsconfig.json

สร้าง config สำหรับ TypeScript นั้น Vite ได้ preconfig ไว้ให้แล้วโดย target จะเป็น esnext แต่ทั้งนี้เพื่อให้ IDE เข้าใจตรงกันให้ config บางส่วนดังนี้ในเบื้องต้น

```
{

 "compilerOptions": {
  "target": "esnext",
    "module": "esnext",
    "moduleResolution": "node",
    "importHelpers": true,
    "isolatedModules": true,
    "noEmit": true
 }
}
```

#### Rename main.js -> main.ts

เราจะเขียนด้วย TypeScript ดังนั้นก็ให้เปลี่ยนจาก js เป็น ts เสีย

```
mv src/main.js src/main.ts
```

เมื่อเปลี่ยนนามสกุล file เสร็จแล้วตอนนี้หน้าเว็บจะเข้าไม่ได้ให้เราเปลี่ยนใน file index.html ด้วย save เสร็จหน้าเว็บก็จะกลับมา

![](https://cdn-images-1.medium.com/max/791/1*NtNoOBUkT3Kcdkc5zai7oA.png)<figcaption>เปลี่ยนนามสกุลเป็น .ts</figcaption>

ตอนนี้เราเขียนด้วย TypeScript ได้แล้วนะ

#### src/shims-vue.d.ts

ถ้าเปิด src/main.ts ขึ้นมาก็จะเห็นขีดเส้นใต้โวยวายหน่อย แต่ vite ยังคงทำงานได้

![](https://cdn-images-1.medium.com/max/1024/1*JrhmgFnvkExA1JJlgxgMPA.png)<figcaption>Warning</figcaption>

ตรงนี้เราต้องตั้งค่า Type ให้กับ .vue เสียก่อนโดยสร้าง file .d.ts ใน src จริงๆ จะชื่ออะไรก็ได้เพื่อความเข้าใจก็ตั้งตามชื่อเดิมๆ ที่เคยใช้มาคือ

```
src/shims-vue.d.ts
```

ใส่ code ประกาศ module Type

```
declare module '\*.vue' {
  import { defineComponent } from 'vue'
  const Component: ReturnType<typeof defineComponent>
  export default Component
}
```

ทำนองเดียวกันถ้าเกิดมี error ไม่รู้จัก file อื่นๆ ก็ต้องทำคล้ายๆ กันนี้แต่ต่างกันที่ contain ข้างใน แต่เท่าที่ดูเหมือน vite จะรู้จักซะส่วนใหญ่ เช่น .css .svg เป็นต้น เมื่อ save file เสร็จ error ก็จะหายไป

### Coding

ตอนนี้ตัวอย่างที่ vite สร้างมาให้ยังเป็น code ที่เขียนแบบเดิมคือ options-api แต่ไหนๆ ก็ลอง Vue 3 ก็ลองเขียนแบบ composition-api ไปเลย

อ้อ !! ตอนนี้ยังไม่ได้สร้าง router ก็จะยังเรียกได้แค่หน้าเดียวเท่านั้นเดี๋ยวมาทำ router เพิ่มอีกนิดสร้าง component เพิ่มขึ้นมาก่อน

```
mkdir src/views
```

#### src/views/About.vue

![](https://cdn-images-1.medium.com/max/651/1*Kn1JDndsT2PwzBpxWm1OEw.png)<figcaption>src/views/About.vue</figcaption>

#### vue-router

สร้าง file src/router.ts

```
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
import Home from './components/HelloWorld.vue'
import About from './views/About.vue'

const routes: RouteRecordRaw[] = [

{
  path: '/',
  name: 'Home',
  component: Home
},
{
  path: '/about',
  name: 'About',
  component: About
}
]

const router = createRouter({
  history: createWebHistory(),
  routes: routes
})

export default router
```

ตอนนี้ vue-router ก็ทำงานได้แล้วแต่ใน src/App.vue ยังไม่ได้เรียกให้ใช้ router แก้ src/App.vue กันต่อ

src/App.vue

ใช้ <router-view> ในการเรียก component ต่างๆ จาก vue-router

```
<router-view />
```

![](https://cdn-images-1.medium.com/max/893/1*OY9tBb6r1DVzZScTNiiopQ.png)<figcaption>App.vue เดิม</figcaption>

![](https://cdn-images-1.medium.com/max/819/1*y_3WqhDaz1a_9nAEwbATAQ.png)<figcaption>ใช้ &lt;router-view&gt;</figcaption>

ลองเรียกไปที่ path

```
[http://localhost:3000/about](http://localhost:3000/about)
```

![](https://cdn-images-1.medium.com/max/1024/1*6bo-HfGq9fz1N9H-8yJYjg.png)<figcaption>ผลลัพธ์จาก About.vue</figcaption>

ลองสร้าง Nav bar ง่ายๆ ดู

```
<div>

  <router-link :to="{ name: 'Home' }">Home</router-link> |

  <router-link :to="{ name: 'About' }">About</router-link>

</div>
```

![](https://cdn-images-1.medium.com/max/962/1*q0HZp4SVDG3ptieTA-C2tg.png)<figcaption>เพิ่ม Nav Bar</figcaption>

![](https://cdn-images-1.medium.com/max/1024/1*RMPoqQMtLTGvjpdxWSUrmg.png)

![](https://cdn-images-1.medium.com/max/1024/1*TNewBeDRzJtGXH1L7sozDQ.png)<figcaption>ตัวอย่าง &lt;router-link&gt;</figcaption>

### Composition API

เมื่อมี router ให้เล่นแล้วก็มาลองเข้าเรื่องเขียน แบบ composition-api เบื้องต้นกันเลย ส่งที่น่าสนใจและต้องใช้ในอนาคตคือ setup function เป็น component options function ใหม่ถ้าเขียนแบบไม่ซับซ้อนอะไรมากก็จบใน setup ได้เลยซึ่ง setup จะทำงานก่อนช่วง beforeCreate และถ้าจะ hook พวก mounted ก็เรียกใน setup ได้ด้วย

#### defineComponent

ถ้าจะให้ครบตั้งแต่เริ่มก็สร้าง component ด้วย defineComponent ตั้งแต่ต้น จริงๆถ้ามีแค่ template และ ตัวแปรไม่กี่ตัวสร้างแบบในตัวอย่างที่ vite สร้างไว้ให้ก็ได้นะ

![](https://cdn-images-1.medium.com/max/652/1*F_1H8CiqXQJ3Rv0yP-CAqQ.png)<figcaption>defineComponent</figcaption>

#### setup()

component options function คล้ายๆ data ของเดิมมาก จะส่งให้ template render ก็ให้ export ตัวแปรออกไปเช่น

![](https://cdn-images-1.medium.com/max/694/1*yMETMJMgxvf6btM-lUvn0Q.png)<figcaption>setup()</figcaption>

#### ref() and reactive()

รายละเอียดลึกคงต้องให้ไปศึกษากันต่อเอานะครับเพราะผมเองก็ยังไม่ได้ลึกซึ้งอะไรมากกำลังลองเขียนอยู่เหมือนกัน สำหรับ ref() และ reactive() จะคล้ายๆ กันตามเอกสารจะแนะนำว่าถ้าเป็น single value ก็ให้ใช้ ref() แต่ถ้าเป็น object ก็ให้ใช้ reactive() เช่น

![](https://cdn-images-1.medium.com/max/797/1*Hoom8y48XI2GD0bFCOD52Q.png)<figcaption>template</figcaption>

![](https://cdn-images-1.medium.com/max/779/1*_66iAk5oiWWCtZookAUeWw.png)<figcaption>script</figcaption>

![](https://cdn-images-1.medium.com/max/1024/1*WKpKKBJIk4Vgb9_r3PciSg.png)<figcaption>web output</figcaption>

#### v-model

ลองให้ input v-model มายัง reactive ดู

![](https://cdn-images-1.medium.com/max/1024/1*iyeoKftTpc0_GZy_cJmXgA.png)<figcaption>Template</figcaption>

![](https://cdn-images-1.medium.com/max/905/1*l0Q4B2HUgtpLlPPtrHWixg.png)<figcaption>Script</figcaption>

![](https://cdn-images-1.medium.com/max/1024/1*3kXnsumnYB_zUae9m7UjYw.png)<figcaption>รอรับข้อมูล</figcaption>

![](https://cdn-images-1.medium.com/max/1024/1*ZUCEmBeEhi5NEGsq_fmR7w.png)<figcaption>หลังจาก input</figcaption>

#### computed()

computed() ทำงานเหมือนกับ computed ของ option-api สามารถใช้ getter และ setter ได้ คือทำ v-model ได้ด้วย แต่ตัวอย่างเอาแบบง่ายๆ คือ เอา nick กับ name มาต่อกันเป็น fullname แสดงใน template

![](https://cdn-images-1.medium.com/max/1024/1*VRtHUcZjQUPxLM9umWXo6g.png)<figcaption>template</figcaption>

![](https://cdn-images-1.medium.com/max/1024/1*PkB7XLxEYwMiPK53kRMoMQ.png)<figcaption>script</figcaption>

![](https://cdn-images-1.medium.com/max/1024/1*1L756fli2QeL8EefKxIhsA.png)<figcaption>กรอกแค่ name</figcaption>

![](https://cdn-images-1.medium.com/max/1024/1*Xlgl8Ydc61gjgxhUbQhSKw.png)<figcaption>เมื่อกรอกทั้งคู่</figcaption>

#### State

ถ้าสังเกตจะพบว่าเมื่อเราเปลี่ยน route ไปมาค่าต่างๆ ที่เราใส่ไว้ก็จะหายไปหมด เมื่อก่อนเราอาจจะใช้ vuex ในการจัดการ state แต่มันมีวิธีที่ง่ายและสะดวกกว่าคือใช้ reactive นี่แหละเก็บ state ลองมาดูกัน

สร้าง src/state.ts

![](https://cdn-images-1.medium.com/max/992/1*MF-VavlUljPrG7JOTQJBZA.png)<figcaption>state.ts</figcaption>

โดยผมจะสร้าง reactive ขื่อ state โดยใน state จะมี properties ย่อออีกสองตัวคือ myinfo และ counter ซึ่ง จะใช้ myinfo แทนของเดิมใน about และ counter จะไว้เก็บการ click หน้าต่างๆแล้วนับจำนวนไว้

ปรับ src/views/About.vue

![](https://cdn-images-1.medium.com/max/1024/1*AhyWwJEQ1ttt4LBgiNPMKw.png)<figcaption>template</figcaption>

![](https://cdn-images-1.medium.com/max/809/1*A0cEx13d77QJ5HEMj39Thw.png)<figcaption>script</figcaption>

#### counter

ส่วน counter จะทำการปรับใช้สองที่คือ

1. router
2. App.vue

#### src/router.ts

ผมดักตรง

![](https://cdn-images-1.medium.com/max/1024/1*1VSgsmQgF6E4LdGiT2iU8w.png)<figcaption>beforeEach</figcaption>

beforeEach เป็น NavigationGuard ถ้าใครจะมาตรวจ auth ก็มักจะทำกันตรงนี้ ผมก็ทำการนับจำนวนการเข้าของ route ต่างๆ โดยใช้ to.name แปลงเป็น string แล้วยัด key ไว้ใน state.counter และทำการเพิ่มค่าถ้ามีเข้ามาอีก

#### src/App.vue

![](https://cdn-images-1.medium.com/max/900/1*1k5DJQGG-6nx1M1J9kS-MA.png)<figcaption>template</figcaption>

![](https://cdn-images-1.medium.com/max/1024/1*7mK9S6Ykurb-eGE_Dtj2PA.png)<figcaption>script</figcaption>

ซึ่งจะดึงค่า counter โดยดูจาก route ปัจจุบันแล้วนำไป render ใน template

![](https://cdn-images-1.medium.com/max/1024/1*lTWjfeO5q0rO1VZGXaWoxw.png)

![](https://cdn-images-1.medium.com/max/1024/1*NaWqhDqSgcJQkCw8UvPhlQ.png)<figcaption>ตัวอย่างการนับ</figcaption>

ถ้าจะให้นับต่อใน session ต่อๆ ไปก็ให้เก็บไว้ localStorage ก็ได้หรือจะส่งกลับไปเก็บไว้ใน server ก็แล้วแต่

จริงๆ มีอะไรให้เล่นเยอะเหมือนกันแต่คงขอจบเท่านี้ก่อนน่าจะมีข้อผิดพลาดอะไรหลายๆ อย่าง ต้องขอคำชี้แนะจากผู้รู้ท่านอื่นๆ ด้วยครับ เพิ่งจะแงะๆ หัดๆ