ทำไมถึงต้องใช้ Nuxt ทั้งๆที่มี Vue อยู่แล้ว ?

/ 4 min read

Share on social media

nuxt-vs-vue สามารถดู video ของหัวข้อนี้ก่อนได้ ดู video

(บทความยังไม่เสร็จดี กำลังอยู่ในระหว่างการเรียบเรียงใหม่ สามารถฟังฉบับเนื้อหาได้ก่อนผ่านคลิปนะครับ 🙏)

Nuxt คืออะไร ?

Web: https://nuxt.com/

Nuxt คือ open source ที่สร้างขึ้นสำหรับ full stack web app โดยเฉพาะ ที่ห่อหุ่มอยู่บน Vue.js อีกที

Nuxt มีไอเดียว่า เราจะทำการเตรียมของที่จำเป็นที่ต้องการในการสร้างเว็บด้วย Vue.js framework เอาไว้ และเพ่ิมความสามารถในการทำ server side render เป็น default เพื่อให้ครอบคลุมทุก use case ของการ production ไว้ด้วย

แตกต่างกับ Vue ยังไงบ้าง ?

Nuxt.js
Initialize
Auto Route
SSR
Configuration
Use Vue
Nuxt_Init
Automatic_Routing
Server_Side_Rendering
Config_based
Vue
Initialize
Use Router
Use Vuex
Vue_Core
Vue_Router
Vuex

State ที่ Nuxt เพิ่มเติมมาจาก Vue

  1. Server-side rendering (หรือ SSR) = สามารถทำ SSR ได้และสามารถทำ Hybrid mode ในแต่ละหน้าได้ https://nuxt.com/docs/guide/concepts/rendering

  2. SEO and Meta = ด้วยความสามารถ SSR ทำให้สามารถกำหนด meta tag สำหรับ share social จากการ render server ได้

  3. Auto import = ไม่ต้องคอย import คำสั่งนับล้านเข้า เช่น Vue

<script setup>
import { ref, computed } from "vue";
import { useRoute } from "vue-router";
const route = useRoute();
const firstName = ref("");
const lastName = ref("");
const fullName = computed(() => {
return `${firstName.value} ${lastName.value}`;
});
</script>
<template>
Fullname {{ fullName }}
<input v-model="firstName" />
<input v-model="lastName" />
</template>

เทียบกับ Nuxt

<script setup>
const route = useRoute();
const firstName = ref("");
const lastName = ref("");
const fullName = computed(() => {
return `${firstName.value} ${lastName.value}`;
});
</script>
<template>
Fullname {{ fullName }}
<input v-model="firstName" />
<input v-model="lastName" />
</template>
  1. Data-fetching utilities = มีคำสั่ง useFetch ในการ call API (โดยไม่ต้อง import คำสั่งมาใหม่)

  2. Code splitting = แยกส่วนทำให้ build file แต่ละ file ขนาดเล็กลง

ในเมื่อ Nuxt ทำเว็บได้เหมือน Vue เลย ใช้ Vue หรือ Nuxt อะไรจะง่ายกว่า ?

  • มันมี feature ที่เหมือนกับ vue เลย (เพราะมันห่อหุ้ม Vue เอาไว้)
  • ความแข็งแกร่งของ Nuxt = เหมือน vue แต่เตรียม feature ไว้ให้พร้อมแล้ว
    • Routing ก็มี
    • Fetch ก็มี (แถม async, await ไม่ต้องประกาศ function ก่อนด้วย)
    • state management ก็มี (ซึ่งจริงๆจะใช้ Pinia ก็ได้)

มันเหมาะสำหรับใครก็ตามที่

  • ขี้เกียจวาง structure เอง (มีคนเตรียม pattern เอาไว้ให้แล้ว)
  • ต้องการความสามารถ server side render

= คุณเหมาะกับ Nuxt มากกว่า

แต่ถ้าใครซีเรียสเรื่อง

  • การวาง Strucuture เป็นแบบฉบับตัวเอง
  • ต้องการเอาเว็บ deploy แค่ฝั่ง Client site (เพื่อให้สามารถขึ้นเว็บง่ายๆ อย่าง github page, firebase hosting)

= คุณเหมาะกับ Vue มากกว่า

มาลองทำ Nuxt กัน

เราจะทำเป็น static site 2 หน้าคือหน้ารวม Todo และหน้าแสดง Todo แบบง่าย ๆ

  • ใช้รูปแบบ project เหมือน Vue todo (ที่เคยยิงเข้า Mock API มา)

เราใช้คำสั่ง nuxt ในการ render web ออกมาเลย

Terminal window
npx nuxi@latest init <project name>

หลังจากนั้นสร้าง structure มาประมาณนี้

  • เราจะทำการสร้างไฟล์ขึ้นมาที่ folder todos
├── README.md
├── app.vue
├── data
│ └── blogs.json
├── nuxt.config.ts
├── package-lock.json
├── package.json
├── pages
│ ├── index.vue
│ └── todos --> สร้าง folder นี้แทน
│ ├── [id].vue
│ └── index.vue
├── public
│ └── favicon.ico
├── server
│ └── tsconfig.json
└── tsconfig.json

แรกสุดเราจะเปลี่ยน app.vue เรียก NuxtPage เพื่อใช้ Router ของ Nuxt แทน

<template>
<div>
<!-- Markup shared across all pages, ex: NavBar -->
<NuxtPage />
</div>
</template>

ตัวอย่าง pages/todos/index.vue

  • เพิ่มสำหรับการ list todo ออกมา
  • ทำการเพิ่ม Router และการ edit ออกมา
<script setup>
const BASE_URL = 'https://<id จากเว็บ mockapi>.mockapi.io'
const statuses = ['Pending', 'Doing', 'Done']
const todoText = ref('')
const isLoading = ref(true)
const todos = ref([])
const loadTodo = async () => {
isLoading.value = true
const { data } = useFetch(`${BASE_URL}/todos`, {
lazy: true
})
console.log(data)
todos.value = data.value
isLoading.value = false
}
const addTodo = async () => {
try {
isLoading.value = true
const todoData = {
name: todoText.value,
status: 'Pending'
}
await useFetch(`${BASE_URL}/todos`, {
method: 'post',
body: todoData
})
await loadTodo()
} catch (error) {
console.log('error', error)
}
isLoading.value = false
}
const deleteTodo = async (id) => {
try {
isLoading.value = true
await useFetch(`${BASE_URL}/todos/${id}`, {
method: 'delete'
})
await loadTodo()
} catch (error) {
console.log('error', error)
}
isLoading.value = false
}
// load in state setup
await loadTodo()
</script>
<template>
<div>
<h1>Todo List</h1>
<div>
<input type="text" v-model="todoText" />
<button @click="addTodo">Add</button>
</div>
<ul v-if="!isLoading">
<li v-for="todo in todos" :key="todo.id">
{{ todo.name }} status :
<select v-model="todo.status">
<option v-for="status in statuses" :key="status" :value="status">{{ status }}</option>
</select>
<NuxtLink :to="`/todo/${todo.id}`">
<button>Edit</button>
</NuxtLink>
<button @click="deleteTodo(todo.id)">DELETE</button>
</li>
</ul>
<div v-else>Loading</div>
</div>
</template>

ตัวอย่าง pages/todos/[id].vue

<script setup>
const route = useRoute();
const todoId = route.params.id;
const BASE_URL = "https://<id จากเว็บ mock api>.mockapi.io";
const { pending, data: todo } = useFetch(`${BASE_URL}/todos/${todoId}`, {
lazy: true,
});
E;
</script>
<template>
<nuxt-link to="/">Back</nuxt-link>
<div v-if="pending">Loading</div>
<div v-else>
<div>Todo {{ todo.id }}</div>
<div>{{ todo.name }}</div>
</div>
</template>

การ deploy Nuxt

ด้วยความที่ Nuxt พื้นฐานเป็น SSR = ต้องการ backend server ในการ render website

  • Nuxt run อยู่บน Node.js https://nuxt.com/docs/getting-started/deployment
  • เช่น ถ้าจะ deploy Firebase hosting มันจะ require Firebase Cloud function (Node) ด้วยสำหรับการทำ SSR เพิ่มเข้ามา

มองในแง่การ deploy = Nuxt จะเปลือง resource มากกว่า เพราะต้องใช้การ render server ร่วมกันด้วย (ใช้มาก ใช้น้อย ขึ้นอยู่กับวิธี optimize เว็บ)

ตัวอย่าง deploy ลง Vercel

เราจะมาลอง deploy Nuxt ที่เราทำกันลง Vercel เลย https://vercel.com/

  • ต้อง push งานขึ้น git เพื่อทำการ deploy
  • เสร็จแล้วเลือก menu ผ่าน Vercel = deploy ได้เลย

ตอบคำถามอื่นๆจากทางบ้าน

(เดี๋ยวมีเพิ่มในบทความมา เบื้องต้นทุกคนสามารถฟังผ่านคลิปก่อนได้)

Related Post

Share on social media