Vue 3 + Vite + TypeScript

Supphachoke Suntiwichaya
NECTEC
Published in
5 min readAug 9, 2020

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

**UPDATE**

เนื่องจากบนความนี้เขียนขึ้นเมื่อปี 2020 รูปแบบต่าง ๆ ในปัจจุบันมีการเปลี่ยนแปลงไปค่อนข้างเยอะดังนั้นเนื้อหาในบทความนี้อาจจะเก่าไปมากสำหรับการอ้างอิง ไว้ผมจะทำการ update เนื้อหาให้ทันสมัยกว่านี้ @02/09/2022

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

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

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

Create App

yarn create vite-app vue3-typescript-ex1

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

cd vue3-typescript-ex1yarn

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

Vue 3 + Vite Project

Dev

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

yarn dev
yran dev output

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

http://localhost:3000/
Vue 3 app

ตอนนี้เราสามารถแก้ไข 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 เสร็จหน้าเว็บก็จะกลับมา

เปลี่ยนนามสกุลเป็น .ts

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

src/shims-vue.d.ts

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

Warning

ตรงนี้เราต้องตั้งค่า 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

src/views/About.vue

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 />
App.vue เดิม
ใช้ <router-view>

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

http://localhost:3000/about
ผลลัพธ์จาก About.vue

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

<div>  <router-link :to="{ name: 'Home' }">Home</router-link> |  <router-link :to="{ name: 'About' }">About</router-link></div>
เพิ่ม Nav Bar
ตัวอย่าง <router-link>

Composition API

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

defineComponent

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

defineComponent

setup()

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

setup()

ref() and reactive()

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

template
script
web output

v-model

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

Template
Script
รอรับข้อมูล
หลังจาก input

computed()

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

template
script
กรอกแค่ name
เมื่อกรอกทั้งคู่

State

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

สร้าง src/state.ts

state.ts

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

ปรับ src/views/About.vue

template
script

counter

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

  1. router
  2. App.vue

src/router.ts

ผมดักตรง

beforeEach

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

src/App.vue

template
script

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

ตัวอย่างการนับ

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

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

--

--