Nuxt – The Intuitive Web Framework

Nuxt – The Intuitive Web Framework

Giới thiệu

Nuxt là một framework JavaScript mã nguồn mở dựa trên Vue.js. Phiên bản mới nhất hiện tại là Nuxt 3. Nuxt 3 là bản nâng cấp lại từ framework Nuxt dựa trên Vite, Vue 3 và Nitro với sự hỗ trợ từ Typescript.

Nuxt giúp đơn giản hóa việc phát triển các ứng dụng web theo phương pháp Server Side Rendering (SSR) và Static Site Generation (SSG), ngoài ra còn có các phương pháp khác như CSR, ISR, ESR và SWR. Nuxt cung cấp một cách tiếp cận có cấu trúc và dựa trên quy ước để xây dựng các ứng dụng Vue.js, cho phép các lập trình viên tập trung vào việc phát triển các tính năng thay vì xử lý cấu hình phức tạp.

 

Tại sao lại sử dụng Nuxt?

Server Side Rendering (SSR): Nuxt tận dụng server side rendering, có nghĩa là các component Vue.js được render trước trên server trước khi được gửi tới client. Điều này cải thiện hiệu suất tải trang ban đầu và cho phép tối ưu hóa công cụ tìm kiếm (SEO) tốt hơn, vì các công cụ tìm kiếm có thể lập chỉ mục nội dung được hiển thị đầy đủ.

Static Site Generation (SSG): Nuxt có thể tạo các file static HTML khi build time, có thể được cung cấp trực tiếp từ CDN hoặc dịch vụ static hosting. Cách tiếp cận này loại bỏ nhu cầu server side rendering trên mỗi request, giúp tải trang nhanh hơn và khả năng mở rộng được cải thiện.

Rendering nhanh hơn: Vue Virtual DOM (VDOM) đã được viết lại từ đầu và cho phép hiệu suất render tốt hơn. Ngoài ra, khi làm việc với các Single-File Components đã biên dịch, trình biên dịch Vue có thể tối ưu hóa chúng hơn nữa tại build time bằng cách tách biệt static và dynamic markup. Điều này dẫn đến render đầu tiên (tạo component) và cập nhật nhanh hơn, đồng thời sử dụng ít bộ nhớ hơn. Trong Nuxt 3, nó cũng cho phép server side rendering nhanh hơn.

Bundle size nhỏ hơn: Với Vue 3 và Nuxt 3, tập trung vào việc giảm tải bundle size. Bằng cách triển khai kỹ thuật tree-shaking, ứng dụng môi trường production khi bundle sẽ không bao gồm các chức năng của Vue như template directives và các component nếu không sử dụng, điều này có thể giúp giảm kích thước file, tải xuống nhanh hơn và cải thiện thời gian tải cho các ứng dụng. Bằng cách này, một ứng dụng Vue 3 tối thiểu có thể được giảm xuống còn 12 kb được nén bằng gzip.

Ecosystem rộng lớn: Nuxt có một hệ sinh thái phát triển đa dạng được đóng góp từ cộng đồng. Bạn có thể tận dụng các plugin, module và công cụ của cộng đồng để mở rộng và tùy chỉnh ứng dụng của mình.

Hỗ trợ Typescript: Mặc dù Nuxt 2 đã hỗ trợ Typescript, với Nuxt 3 đã hỗ trợ Typescript cải thiện hơn, bạn có thể sử dụng tính năng Type-checking và các công cụ khác mà Nuxt cung cấp dựa trên Typescript.

Phát triển đơn giản hóa: Với Convention Over Configuration, Nuxt giảm tải các mã soạn sẵn và đơn giản hóa quy trình phát triển. Nó đi kèm với các tính năng tích hợp sẵn như routing, code splitting, và state management, cho phép bạn tập trung vào việc xây dựng logic ứng dụng của mình thay vì lo lắng về thiết lập và cấu hình.

Trải nghiệm tốt hơn đối với lập trình viên: Nuxt cung cấp một môi trường phát triển mạnh mẽ với các tính năng như hot module replacement, automatic reloading, error handling, và công cụ cải tiến hơn như debugging, testing, devtools và các công cụ khác. Các tính năng này hợp lý hóa quy trình phát triển, cho phép lặp lại nhanh hơn và khả năng sửa lỗi tốt hơn.

Khả năng mở rộng và hiệu suất: Nuxt tối ưu hóa hiệu suất ứng dụng của bạn thông qua các tính năng như automatic code splitting, lazy loading, và pre-rendering. Nó đảm bảo rằng chỉ có JavaScript cần thiết được tải cho mỗi trang, dẫn đến thời gian tải nhanh hơn và trải nghiệm người dùng tốt hơn. Ngoài ra, kiến trúc kiểu mô-đun của Nuxt cho phép khả năng mở rộng dễ dàng khi ứng dụng của bạn nâng cấp các version về sau.

 

Một số công nghệ được hỗ trợ tích hợp sẵn

  1. Webpack 5
  2. Vite
  3. Nitro
  4. Vue 3
  5. Router 4
  6. Typescript

 

So sánh các tính năng

Trong bảng dưới đây là bảng so sánh nhanh giữa 3 phiên bản Nuxt:

 

Cấu trúc thư mục

.nuxt: Nuxt sử dụng thư mục “.nuxt/” trong quá trình phát triển để tạo ứng dụng Vue của bạn.

.output: Nuxt tạo thư mục “.output/” khi xây dựng ứng dụng của bạn ở môi trường production.

assets: Thư mục “assets/” được sử dụng để thêm tất cả nội dung của trang web mà công cụ xây dựng (webpack hoặc Vite) sẽ xử lý. Thư mục thường chứa các loại file sau: Stylesheets (CSS, SASS, v/v.), Fonts, hình ảnh sẽ không được phục vụ từ thư mục “public/”.

components: Thư mục “components/” là nơi bạn đặt tất cả các Vue components của mình, sau đó có thể import vào bên trong các trang của bạn hoặc các components khác.

composables: Nuxt 3 sử dụng thư mục “composables/” để tự động import các Vue composables của bạn vào ứng dụng của bạn bằng cách sử dụng tính năng auto-imports.

content: Hỗ trợ các file định dạng .md, .yml, .csv để tạo một CMS cho ứng dụng của bạn.

layouts: Được sử dụng để thay đổi giao diện ứng dụng của bạn. Một ứng dụng có thể có nhiều layouts ví dụ: admin layout, guest layout và registered clients layout. Các bố cục này sẽ được sử dụng lại trong các trang khác nhau để xử lý giao diện của chúng (sidebar, menu, footer, v.v.). Trong khi cài đặt, Nuxt CLI cung cấp mặc định layouts/default.vue layout và được sử dụng trong tất cả các trang.

middleware: Được sử dụng để xử lý các yêu cầu trước khi trang được hiển thị cho người dùng. Middleware cho phép bạn thực hiện các tác vụ như xác thực, kiểm tra quyền truy cập, ghi lại hoạt động và các xử lý tùy chỉnh khác trước khi trang được hiển thị.

modules: Nuxt quét thư mục “modules/” và tải chúng trước khi bắt đầu. Đó là một nơi tốt để đặt bất kỳ modules cục bộ nào mà bạn phát triển trong khi xây dựng ứng dụng của mình.

node_modules: Trình quản lý package (npm hoặc yarn hoặc pnpm) tạo thư mục “node_modules/” để lưu trữ dependencies của dự án của bạn.

pages: Nuxt cung cấp routing dựa trên file để tạo các routes trong ứng dụng web của bạn bằng Vue Router.

plugins: Nuxt tự động đọc các file trong thư mục “plugins/” của bạn và tải chúng khi tạo ứng dụng Vue. Bạn có thể sử dụng hậu tố .server hoặc .client trong tên file để chỉ tải plugin ở server hoặc client.

public: Thư mục “public/” chứa các file tĩnh và cung cấp tài nguyên cho các request HTTP một cách trực tiếp không qua xử lý logic bổ sung. Ví dụ, có thể đặt các tệp tin hình ảnh, font chữ, robot.txt , favicon.ico hoặc các tệp tin tĩnh khác.

server: Nuxt tự động quét các file bên trong các thư mục như “~/server/api”, “~/server/routes”, “~/server/middleware” để đăng ký trình xử lý API và server với sự hỗ trợ của HMR

utils: Nuxt 3 sử dụng thư mục “utils/” để tự động import helper functions và các tiện ích khác trong ứng dụng của bạn bằng cách sử dụng auto-imports.

.env: Nuxt CLI có hỗ trợ dotenv tích hợp trong chế độ development và khi chạy lệnh nuxi buildnuxi generate. Ngoài bất kỳ biến môi trường nào của quy trình, nếu bạn có file .env trong thư mục gốc của dự án, file này sẽ tự động được tải khi build, khi dev, và khi generate, và mọi biến môi trường được đặt ở đó sẽ có thể truy cập được trong file nuxt.config của bạn và các modules.

.gitignore: Sẽ liệt kê tên những file, folder trong project mà bạn không muốn bị parse mỗi khi thao tác với git.

.nuxtignore: File .nuxtigore cho phép Nuxt bỏ qua layouts, pages, components, composables và middleware trong thư mục gốc của dự án (rootDir) trong quá trình build. File .nuxtigore tuân theo cùng thông số kỹ thuật như file .gitignore và .eslintigore, trong đó mỗi dòng là một mẫu hình cầu cho biết file nào sẽ bị bỏ qua.

app.config.ts: Được sử dụng để cấu hình và tùy chỉnh ứng dụng Nuxt.

app.vue: Component chính trong các ứng dụng Nuxt 3.

nuxt.config.ts: File nuxt.config.ts chứa cấu hình tùy chỉnh Nuxt của bạn và cho phép bạn cấu hình ứng dụng của mình, những cấu hình này bao gồm head title và associated styles và scripts, middlewares, plugins, authentication, modules và thậm chí cả các API.

package.json: Chứa tất cả các dependencies và scripts cho ứng dụng của bạn.

tsconfig.json: Nuxt tự động tạo file .nuxt/tsconfig.json với các giá trị mặc định hợp lý khác. Bạn chỉ cần việc tạo 1 file tsconfig.json bên ngoài root và import từ file Nuxt đã khởi tạo.

 

Tính năng

Auto-imports

Auto import là một tính năng mới được Nuxt 3 phát triển nó khá là tiện. Tất cả các file trong components, composables, utils đều được tự động nhận diện và chỉ cần gọi tên component, composables, v/v, mà không cần phải import lại nữa. Auto import được bật mặc định nhưng cũng có thể tắt đi trong file nuxt.config.ts như sau:

export default defineNuxtConfig({
  imports: {
    autoImport: false
  }
})

 

Rendering Modes

Nuxt hỗ trợ các chế độ rendering khác nhau, universal rendering, client side rendering nhưng cũng cung cấp hybrid rendering và khả năng render ứng dụng của bạn trên CDN Edge Servers.

 

Server Engine

Nuxt 3 được cung cấp bởi một server engine mới, Nitro.

  1. Hỗ trợ đa nền tảng cho Node.js, trình duyệt, service-workers, v/v.
  2. Serverless hỗ trợ out-of-the-box.
  3. Hỗ trợ API routes.
  4. Tự động hóa code-splitting và async-loaded chunks.
  5. Chế độ kết hợp cho các trang static + serverless.
  6. Server phát triển với cơ chế hot module reloading.

 

Bắt đầu với Nuxt

Điều kiện tiên quyết: Nodejs version 16.0.0 hoặc mới hơn.

Thiết lập đơn giản với Nuxt CLI, sử dụng với lệnh nuxi sẽ giúp bạn cài đặt và quản lý tất cả các thành phần Nuxt. Với npx đã được cài đặt, bạn dễ dàng tạo project theo lệnh bên dưới:

> npx nuxi init project-name

Kết quả output bạn sẽ nhận được.

Nuxt project is created with v3 template. Next steps:
› cd project-name
› Install dependencies with npm install or yarn install or pnpm install
› Start development server with npm run dev or yarn dev or pnpm run dev

Cài đặt dependencies.

yarn install

Và đây là cấu trúc project mới.


Bây giờ bạn sẽ có thể khởi động ứng dụng Nuxt của mình ở chế độ development.

yarn dev -o

Sau đó truy cập trình duyệt tại (http://localhost:3000/), để thấy được ứng dụng Nuxt vừa được tạo đang chạy.

Theo mặc định, file app.vue là core component đóng vai trò là entrypoint và render nội dung của nó cho mỗi route của ứng dụng. Là root component của ứng dụng Nuxt của bạn và đại diện cho layout và structure bao bọc tất cả các component khác. Nó thường chứa layout chính, navigation, và bất kỳ global components hoặc logic nào cần được chia sẻ trên nhiều trang.

Thay đổi một chút nội dung trong file app.vue và xem hiển thị.

> app.vue
<template>
  <div>
    <h1>Welcome to the homepage</h1>
  <div>
</template>

 

Các đặc trưng

Pages

Đây là nơi sẽ chứa các Application Views cũng như route của bạn. Theo mặc định, Nuxt sử dụng hệ thống routing dựa trên mỗi file, trong đó mỗi file .vue trong thư mục “pages/” tương ứng với một route.

Để sử dụng các page, hãy tạo file pages/index.vue và thêm component <NuxtPage /> vào app.vue (hoặc xóa app.vue khi muốn pages/index.vue làm mặc định). Pages là các Vue component và có thể có bất kỳ valid extension nào mà Nuxt hỗ trợ (theo mặc định là .vue, .js, .jsx, .mjs, .ts hoặc .tsx). Nuxt sẽ tự động tạo route cho mọi trang trong thư mục “~/pages/” của bạn.

> app.vue (Nếu dùng app.vue làm mặc định)
<template>
  <NuxtPage />
</template>

--- .vue ---
> pages/index.vue
<template>
  <p>Home Page</p>
</template>

> pages/about.vue
<template>
  <p>About Page</p>
</template>

--- .ts ---
> pages/index.ts
export default defineComponent({
  render () {
    return h('h1', 'Home page');
  }
});

--- .tsx ---
export default defineComponent({
  render () {
    return <h1>Home page</h1>;
  }
});

 

Layouts

Layout đóng một vai trò quan trọng trong việc xác định cấu trúc và thiết kế tổng thể của các trang trong ứng dụng của bạn. Layout trong Nuxt đại diện cho một template có thể tái sử dụng bao quanh các page component của bạn và cung cấp giao diện nhất quán trên nhiều page. Có thể tạo nhiều layout khác nhau như layout login hay layout homepage hoặc nhiều layout khác.

Nếu bạn chỉ có một layout duy nhất trong ứng dụng của mình, chúng tôi khuyên bạn nên sử dụng app.vue với thành phần <NuxtPage /> để thay thế.

Nếu không thiết lập gì, Nuxt sẽ chỉ định default.vue làm mặc định.

> app.vue
<template>
  <NuxtLayout>
    <NuxtPage />
  </NuxtLayout>
</template>

> layouts/default.vue
<template>
  <div>
    <h1>This our default layout</h1>
    <slot />
  </div>
</template>

> pages/index.vue
<template>
  <p>Home Page</p>
</template>

 

Bây giờ, hãy làm điều gì đó thú vị hơn, hãy tạo một layout tùy chỉnh và hiển thị trang /about của chúng ta bằng layout mới của chúng ta.

> layouts/custom.vue
<template>
  <div>
    <h1>This our custom layout</h1>
    <slot />
  </div>
</template>

> pages/about.vue
<template>
  <p>About Page</p>
</template>

<script setup>
definePageMeta({
  layout: 'custom',
});
</script>

 

Routing

Dynamic routes

Bây giờ, hãy xem xét các cách khác nhau mà chúng ta có thể tạo routes bằng cách sử dụng routing dựa trên các file trong Nuxt.

 

Trong ví dụ của chúng ta, hãy xem cấu trúc thư mục “pages/”. Có 2 loại page khác nhau: static page và dynamic page có nội dung thay đổi dựa trên route parameters.

  1. Static page
    • index.vue → /
    • about.vue → /about
    • category/index.vue → /category
  2. Dynamic page
    • category/[slug].vue → /category/language
    • user-[group]/[id].vue → /user-admin/123
> pages/category/[slug].vue
<template>
  <p>Category slug : {{ $route.params.slug  }}</p>
</template>

<script setup>
const route = useRoute();
useHead({
  title: `Category ${route.params.slug}`
});
</script>

 

> pages/user-[group]/[id].vue
<template>
  <p>Group : {{ $route.params.group }} - ID : {{ $route.params.id }}</p>
</template>

<script setup>
const route = useRoute();
useHead({
  title: `User group ${route.params.group} ID ${route.params.id}`
});
</script>

 

Nested Routes

Là một cấu trúc page hiển thị theo cấp bậc, nơi mà một parent route sẽ có các child routes hoặc sub-routes. Điều này hữu ích khi bạn có các page cần chia sẻ common layout hoặc khi bạn muốn sắp xếp các route trong ứng dụng của mình theo cách lồng nhau.
Có thể hiển thị các nested routes với <NuxtPage>.

 

Cây file này sẽ tạo các route sau:

[
  {
    path: '/user',
    component: '~/pages/user.vue',
    name: 'user',
    children: [
      {
        path: '/',
        component: '~/pages/user/index.vue',
        name: 'user-child'
      },
      {
        path: '/:id',
        component: '~/pages/user/[id].vue',
        name: 'user-id',
	children: [
	   {
	     path: '/profile',
	     component: '~/pages/user/[id]/profile.vue',
	     name: 'user-id-profile'
	   },
	   {
	     path: '/division',
	     component: '~/pages/user/[id]/division/index.vue',
	     name: 'user-id-division',
	     children: [
		{
		  path: '/:division/:divisionId',
		  component: '~/pages/user/[id]/division/[division]/[divisionId].vue',
		  name: 'user-id-division-id'
		}
	     ]
	   },
	 ]
      }
    ]
  }
]

Kết quả route user với child routes.

> pages/user.vue
<template>
  <p>User Page</p>
  <NuxtPage />
</template>

> pages/user/index.vue
<template>
  <p>User Child Page</p>
</template>

 

Kết quả route user profile với parameter user id.

> pages/user.vue (parent route)

> pages/user/[id]/profile
<template>
  <p>User Profile Page - User ID : {{ $route.params.id }}</p>
</template>

 

Kết quả route user division với parameter user id.

> pages/user.vue (parent route)

> pages/user/[id]/division/index.vue
<template>
  <p>User ID : {{ $route.params.id }}</p>
  <p>User division : {{ $route.params.division }}</p>
</template>

 

Kết quả route user division với parameter user id và division id.

> pages/user.vue (parent route)

> pages/user/[id]/division/[division]/[divisionId].vue
<template>
  <p>User ID : {{ $route.params.id }}</p>
  <p>User division : {{ $route.params.division }} - Division ID : {{ $route.params.divisionId }}</p>
</template>

 

Navigation

Là quá trình di chuyển giữa các page hoặc các route khác nhau trong ứng dụng của bạn. Nuxt sử dụng component <NuxtLink> để liên kết các page. Nó sẽ render một tag <a> với thuộc tính href để thiết lập route cho page.

> pages/index.vue
<template>
  <div>
    <p>Home Page</p>
    <nav>
      <ul>
        <li><NuxtLink to="/about">About</NuxtLink></li>
        <li><NuxtLink to="/category">Category</NuxtLink></li>
        <li><NuxtLink to="/user">User</NuxtLink></li>
      </ul>
    </nav>
  </div>
</template>

<style scoped>
a {
  text-decoration: none;
  line-height: 1.5em;
  color: #0e0d0d;
  font-weight: 600;
}
</style>

Khi nhấn vào từng link About, Category, User thì sẽ redirect đến page tương ứng.

 

Sử dụng component <NuxtLink> với parameter Props “to” có 2 đối tượng cần quan tâm:

  1. name: Tên của page cũng là route tương ứng.Ví dụ: pages/category/[slug].vue → /category/:slug⇒ Đặt tên tương ứng ngăn cách giữa các child folder là dấu “-”: category-slug.
  2. params: Parameter cần truyền khi sử dụng dynamic route.
> pages/category/index.vue
<template>
  <p>Category Page</p>
  <nav>
    <ul v-for="(cate, index) in categories" :key="index">
      <li>
        <NuxtLink :to="{ name: 'category-slug', params: { slug: cate } }">
          {{ cate }}
        </NuxtLink>
      </li>
    </ul>
  </nav>
</template>

<script setup>
const categories = ['language', 'reading', 'programming', 'art', 'other'];
</script>

<style scoped>
a {
  text-decoration: none;
  line-height: 1.5em;
  color: #0e0d0d;
  font-weight: 600;
}
</style>

 

Assets

  1. Nội dung thư mục “public/” được phục vụ tại server root.
  2. Thư mục “assets/” chứa mọi nội dung mà bạn muốn công cụ xây dựng (Vite hoặc webpack) xử lý.

Thư mục public

Ví dụ, liên quan đến file ảnh tại thư mục “public/img/”, có sẵn tại static URL /img/nuxt.png:

<template>
  <img src="/img/nuxt.png" alt="Discover Nuxt 3" />
</template>

Thư mục assets

Nuxt sẽ không cung cấp các file trong thư mục assets/ tại một static URL như /assets/my-file.png. Nếu bạn cần một static URL, hãy sử dụng thư mục public/.

Bạn có thể thiết lập các file stylesheet(CSS, SASS, v/v), fonts hoặc SVG. Để chèn các câu lệnh global vào các component Nuxt của bạn, bạn có thể sử dụng tùy chọn Vite tại file nuxt.config của mình.

Hãy xem ví dụ bên dưới:

> assets/css/styles.css
a {
  text-decoration: none;
  line-height: 1.5em;
  color: #0e0d0d;
  font-weight: 600;
}

> assets/sass/_colors.scss
$primary: #49240F;
$secondary: #E4A79D;

> assets/sass/app.scss
@import url("https://fonts.googleapis.com/css2?family=Nunito:ital,wght@0,200;0,300;0,400;0,600;0,700;0,800;0,900;1,200;1,300;1,400;1,600;1,700;1,800;1,900&display=swap");
body {
  font-family: 'Nunito',
}
.btn-bg-color {
  background-color: $primary;
}

> nuxt.config.ts
export default defineNuxtConfig({
  css: [
    '~/assets/css/styles.css',
    '~/assets/sass/app.scss',
  ],
  vite: {
    css: {
      preprocessorOptions: {
        scss: {
          additionalData: '@use "@/assets/sass/_colors.scss" as *;'
        }
      }
    }
  }
})

 

Components

Thư mục “components/” là nơi bạn đặt tất cả các component Vue mà sau đó có thể được nhập vào bên trong các page của bạn hoặc các component khác.
Nuxt tự động import bất kỳ component nào trong thư mục “components/” của bạn (cùng với các component được đăng ký bởi bất kỳ mô-đun nào bạn có thể đang sử dụng).

Ngoài ra Nuxt còn tích hợp sẵn các component như: <ClientOnly>, <NuxtPage>, <NuxtLayout>, <NuxtLink>, <Teleport>, v/v.

> components
--| BaseHeader.vue
--| BaseFooter.vue
--| base/
----| html/
------| Alert.vue

> layouts/default.vue
<template>
  <div>
    <BaseHeader />
    <BaseHtmlAlert />
    <slot />
    <BaseFooter />
  </div>
</template>

 

Composables

Nuxt cung cấp một số composables như useAppConfig, useAsyncData, useCookie, useError, useFetch, useHead, v/v. Ngoài ra Nuxt sẽ tự động import các file bên trong thư mục “composables” của bạn với tính năng auto-imports.

 

Plugins 

Nuxt tự động đọc các file trong thư mục “plugins” của bạn và tải chúng khi tạo ứng dụng Vue. Bạn có thể sử dụng hậu tố .server hoặc .client trong tên file để chỉ tải plugin ở phía server hoặc client.

Tất cả các plugin trong thư mục plugins/ của bạn đều được đăng ký tự động, vì vậy bạn không nên thêm riêng chúng vào nuxt.config của mình.

 

Modules

Nuxt cung cấp cho chúng ta một danh sách các modules từ cộng đồng. Cho bạn có nhiều sự lựa chọn để phát triển ứng dụng.

 

Cài đặt module cần thiết cho ứng dụng của bạn và cấu hình ở file nuxt.config.ts.

export default defineNuxtConfig({
  modules: [
    '@vueuse/nuxt',
    '@element-plus/nuxt',
    'nuxt-lodash',
    'nuxt-security',
  ]
})

Với những file custom thì Nuxt sẽ quét thư mục “modules/” và tải chúng trước khi bắt đầu. Đó là một nơi tốt để đặt bất kỳ mô-đun cục bộ nào mà bạn phát triển trong khi xây dựng ứng dụng của bạn.

modules/*/*.ts
modules/*.ts

 

Data Fetching

Với Nuxt 3 gần như đã hỗ trợ đầy đủ composables và các thư viện được tích hợp sẵn để thực hiện data-fetching từ môi trường browser hoặc server bao gồm: useFetch, useLazyFetch, useAsyncData, useLazyAsyncData và $fetch.

useFetch

useFetch được render ở server side (trong mode server side rendering của Nuxt) và được sử dụng để nạp dữ liệu vào trong ứng dụng Nuxt của bạn. useFetch có thể được sử dụng ở cả page, các component hay các plugin. Cách sử dụng của useFetch rất đơn giản như dưới đây:

<template>
  <div>
	Page visits: {{ count }}
  </div>
</template>

<script setup>
const { data: count } = await useFetch('/api/count');
</script>

Options:

  1. method: Phương thức của request.
  2. query: Thêm các query cho request.
  3. params: Alias cho query.
  4. body: Request body.
  5. headers: Request headers.
  6. baseURL: Base URL.
  7. key: Giá trị duy nhất, kiểm soát cách dữ liệu được lưu vào cache và cách các request được thực hiện.
  8. server: Có tìm nạp dữ liệu trên máy chủ hay không (mặc định là true).
  9. default: Thiết lập giá trị mặc định cho đối tượng.
  10. pick: Trích xuất thuộc tính cụ thể từ dữ liệu đối tượng.
  11. watch: Lắng nghe sự thay đổi của đối tượng nào đó để gọi lại useFetch.
  12. transform: Sử dụng để transform đầu ra.
  13. immediate: Khi được đặt thành false, sẽ ngăn yêu cầu kích hoạt useFetch ngay lập tức.

Retrun value:

  1. data: Dữ liệu mà useFetch gọi từ API.
  2. pending: Trạng thái useFetch có còn được gọi hay không (true/false).
  3. refresh/execute : Hàm refresh hoặc execute có thể được gọi bên ngoài useFetch sử dụng để fetch lại dữ liệu.
  4. error: Object error trong trường hợp gọi API bị lỗi.

Sau đây là một ví dụ nhỏ có sử dụng một vài options trên.

const { data, pending, error, refresh } = await useFetch('https://api.nuxtjs.dev/mountains',{
    pick: ['title'],
    query: { param1, param2: 'value2' }
})
const refreshData = () => refresh();

Cách sử dụng này sẽ trả ra title của các phần tử trong mảng trả về từ url là “https://api.nuxtjs.dev/mountains?param1=value1&param2=value2” và chúng ta có thể gọi lại useFetch thông qua hàm refreshData.

 

useAsyncData

Với useFetch, mỗi lần sử dụng truyền một URL dài vào useFetch và nếu URL này được sử dụng ở nhiều nơi thì khá khó quản lý. Thường sẽ tạo một thư mục API và viết các hàm gọi API vào các file trong đó, sau đó import vào component hoặc page. Với cách làm này thì không thể sử dụng được useFetch. Để thuận tiện thì với useAsyncData cách sử dụng cũng gần giống với useFetch.

<template>
  <div>
		Page visits: {{ data }}
	</div>
</template>

<script setup>
	const { data } = await useAsyncData('count', () => $fetch('/api/count'));
</script>

Giả sử có hàm:

export const getPosts = () => axios.get('/api/posts');

Để sử dụng trong useAsyncData thì chúng ta chỉ cần sửa thành:

const { data } = await useAsyncData('projectSearch', () => getPosts());

Các option và return value trong useAsyncData cũng giống như trong useFetch. Có một lưu ý nhỏ khi sử dụng useAsyncData hay useFetch là chúng ta hãy nhớ thêm key cho chúng và nhớ clearNuxtData nếu muốn useAsyncData hoặc useFetch được gọi lại khi chúng ta chuyển trang nhé. Ví dụ như thế này:

<script setup>
	await clearNuxtData('count');
	const { data } = await useAsyncData('count', () => $fetch('/api/count'));
</script>

 

useLazyFetch

Cách viết của useLazyFetch thì cũng giống useFetch vì cơ bản nó chính là useFetch với option lazy: true. Với lazy sẽ load data bất đồng bộ, Nuxt sẽ nạp dữ liệu song song với các đoạn mã ngay phía sau khác với useFetch thì sẽ thực hiện xong mới thực hiện tiếp tục các đoạn code đằng sau. Ngoài ra bạn có thể sử dụng thuộc tính pending để xác định xem data đã được load xong chưa (pending = true khi data chưa được load xong và ngược lại).

<template>
  <div>
      Page visits: {{ count }}
  </div>
</template>

<script setup>
    const { pending, data: count } = await useLazyFetch('/api/count');
</script>

 

useLazyAsyncData

useLazyAsyncData cũng tương tự như useAsyncData nhưng với option lazy: true. Cách triển khai thì cũng giống như useAsyncData:

const { pending, data: post } = await useLazyAsyncData('post', () => getPosts());

 

$fetch

Nuxt sử dụng ofetch để hiển thị global với helper $fetch để thực hiện các yêu cầu HTTP trong ứng dụng Vue hoặc các tuyến API của bạn.

Chúng ta nên sử dụng useFetch hoặc useAsyncData + $fetch để ngăn việc tìm nạp dữ liệu kép khi tìm nạp dữ liệu thành phần.

<script setup>
// Trong quá trình SSR, dữ liệu được tìm nạp hai lần, một lần trên server và một lần trên client.
const dataTwice = await $fetch('/api/item')
// Trong thời gian SSR, dữ liệu chỉ được tìm nạp ở phía server và được chuyển đến client.
const { data } = await useAsyncData('item', () => $fetch('/api/item'))
// Bạn cũng có thể sử useFetch làm lối tắt của useAsyncData + $fetch
const { data } = await useFetch('/api/item')
</script>

Bạn có thể sử dụng $fetch cho bất kỳ phương thức nào chỉ được thực thi ở client side.

<template>
  <button @click="contactForm">Contact</button>
</template>

<script setup>
function contactForm() {
  $fetch('/api/contact', {
    method: 'POST',
    body: { hello: 'world '}
  })
}
</script>

 

Server

Nuxt tự động quét các file bên trong các thư mục: “~/server/api”, “~/server/routes”, “~/server/middleware”, để đăng ký trình xử lý API và server có hỗ trợ HMR.

Ví dụ: tạo một route /api/hello với /server/api/hello.ts.

> server/api/hello.ts
export default defineEventHandler((event) => {
  return {
    hello: 'world'
  }
})

> pages/hello.vue
<template>
  <pre>{{ data }}</pre>
</template>

<script setup>
  const { data } = await useFetch('/api/hello');
</script>

Tên file xử lý có thể được thêm vào hậu tố .get, .post, .put, .delete, … để phù hợp với Phương thức HTTP của yêu cầu.

> server/api/test.get.ts
export default defineEventHandler(() => 'Test get handler')

> server/api/test.post.ts
export default defineEventHandler(() => 'Test post handler')

Handle request với Body:

> server/api/submit.post.ts
export default defineEventHandler(async (event) => {
    const body = await readBody(event)
    return { body }
})

Handle request với Query:

> server/api/search.ts
// Mẫu query: /api/search?param1=a&param2=b
export default defineEventHandler((event) => {
  const query = getQuery(event)
  return { a: query.param1, b: query.param2 }
})

 

Phần kết luận

Với phiên bản mới mà Nuxt mang lại thêm vào đó là một cộng đồng Vue.js đang dần phát triển và sự mạnh mẽ của các công nghệ lõi đã dần thu hút cộng đồng người sử dụng Vue.js nói chung và Nuxt nói riêng, đã giúp mang lại nguồn tài liệu phong phú và đa dạng.

Ưu điểm:

  1. Về mặt hiệu suất được cải tiến.
  2. Cải thiện hiệu suất ứng dụng mobile.
  3. Các kiến trúc mô-đun linh hoạt.
  4. Hỗ trợ Typescript, plugins và công cụ debugging tốt hơn.
  5. Tối ưu SEO.
  6. Tích hợp tốt với Vue 3.
  7. Hạn chế việc cấu hình phức tạp.

Nhược điểm:

  1. Đối với người mới thì phải bắt đầu có kiến thức nền tảng về Vue.js.
  2. Nuxt yêu cầu bạn tuân thủ cấu trúc folder chuẩn của nó. Điều này có thể gây khó khăn khi bạn cần tùy chỉnh cấu trúc folder hoặc tích hợp với các công cụ, thư viện bên ngoài có cấu trúc khác.
  3. Một số thư viện và plugin Vue.js có thể không tương thích hoặc cần một số cấu hình bổ sung khi sử dụng với Nuxt.
  4. Nuxt là một framework mạnh mẽ được thiết kế cho các ứng dụng phức tạp. Nếu bạn có một dự án đơn giản hoặc một ứng dụng một trang, việc sử dụng Nuxt có thể gây ra sự phức tạp và chi phí không cần thiết.
  5. Cộng đồng còn nhỏ và đang dần phát triển.

Thống kê giữa các rendering framework thịnh thành:

(https://npmtrends.com/)

 

(https://2022.stateofjs.com/)

 

Nguồn tham khảo:

https://nuxt.com/

https://npmtrends.com/

https://2022.stateofjs.com/