Bài 28.1: Cài đặt Next.js với TypeScript

Bài 28.1: Cài đặt Next.js với TypeScript
Chào mừng các bạn quay trở lại với chuỗi bài viết về Lập trình Web Front-end! Sau khi đã tìm hiểu sâu về React và nắm vững sức mạnh của TypeScript trong việc quản lý kiểu dữ liệu, giờ là lúc chúng ta kết hợp chúng với một framework React mạnh mẽ: Next.js.
Next.js không chỉ là một framework, nó là một giải pháp toàn diện giúp chúng ta xây dựng các ứng dụng React có khả năng Server-Side Rendering (SSR), Static Site Generation (SSG), hỗ trợ định tuyến (routing) dễ dàng, tối ưu hóa hiệu suất và còn nhiều hơn thế nữa. Việc kết hợp Next.js với TypeScript sẽ mang lại một lớp bảo vệ vững chắc, giúp chúng ta phát hiện lỗi ngay trong quá trình phát triển, cải thiện khả năng bảo trì code và nâng cao trải nghiệm làm việc nhóm.
Trong bài viết này, chúng ta sẽ cùng nhau đi qua các bước cần thiết để cài đặt và khởi tạo một dự án Next.js hoàn chỉnh, được trang bị sức mạnh của TypeScript ngay từ đầu. Hãy sẵn sàng để xây dựng những ứng dụng web hiệu quả và đáng tin cậy hơn!
Chuẩn bị hành trang: Những gì bạn cần trước khi bắt đầu
Trước khi chúng ta bắt tay vào việc cài đặt, hãy đảm bảo rằng bạn đã có đầy đủ các công cụ cần thiết:
Node.js: Next.js được xây dựng trên Node.js. Hãy chắc chắn bạn đã cài đặt Node.js phiên bản mới nhất (khuyến nghị phiên bản >= 18.0). Bạn có thể kiểm tra phiên bản bằng cách mở Terminal hoặc Command Prompt và chạy lệnh sau:
node -v npm -v
- _Giải thích:_ Lệnh
node -v
hiển thị phiên bản Node.js, cònnpm -v
hiển thị phiên bản của trình quản lý gói npm (thường được cài đặt cùng với Node.js). Next.js có thể hoạt động với npm, yarn hoặc pnpm.
- _Giải thích:_ Lệnh
Kiến thức cơ bản về React và TypeScript: Vì Next.js là framework cho React và chúng ta sẽ dùng TypeScript, nên việc có nền tảng về hai công nghệ này là rất quan trọng.
Khi đã chắc chắn các yêu cầu trên được đáp ứng, chúng ta sẵn sàng để tạo dự án đầu tiên!
Bắt đầu cuộc hành trình: Cài đặt dự án Next.js với TypeScript
Cách đơn giản và được khuyến nghị nhất để tạo một dự án Next.js là sử dụng công cụ create-next-app
. Công cụ này sẽ giúp bạn thiết lập một dự án Next.js mới với cấu hình mặc định và các dependency cần thiết, bao gồm cả việc tích hợp TypeScript.
Mở Terminal hoặc Command Prompt của bạn, điều hướng đến thư mục mà bạn muốn tạo dự án, và chạy lệnh sau:
npx create-next-app@latest ten-du-an-cua-ban
- _Giải thích:_
npx
: Lệnh này cho phép bạn chạy các gói npm mà không cần cài đặt chúng toàn cục trên máy tính.create-next-app@latest
: Tải và chạy phiên bản mới nhất của công cụcreate-next-app
.ten-du-an-cua-ban
: Đây là tên thư mục sẽ được tạo cho dự án của bạn. Hãy thay thế nó bằng tên mà bạn muốn (ví dụ:my-next-ts-app
,blog-app
, v.v.).
Sau khi chạy lệnh này, create-next-app
sẽ hỏi bạn một vài câu hỏi để tùy chỉnh dự án. Đây là lúc quan trọng để chúng ta chọn tích hợp TypeScript:
✔ Would you like to use TypeScript? … No / Yes
Hãy chắc chắn rằng bạn chọn Yes
(nhấn phím Y
và Enter).
Các câu hỏi khác sẽ bao gồm:
- Would you like to use ESLint? (Nên chọn Yes)
- Would you like to use Tailwind CSS? (Tùy chọn, nếu bạn thích Tailwind)
- Would you like to use
src/
directory? (Tùy chọn, thường chọn Yes để tổ chức code) - Would you like to use App Router? (recommended) (Nên chọn Yes, đây là cách định tuyến mới của Next.js)
- Would you like to customize the default import alias (@/*)? (Tùy chọn, thường giữ mặc định)
Sau khi bạn trả lời các câu hỏi, create-next-app
sẽ tiến hành tải về các dependency cần thiết và cấu hình dự án cho bạn. Quá trình này có thể mất vài phút tùy thuộc vào tốc độ mạng của bạn.
Nếu bạn muốn nhanh chóng tạo dự án với TypeScript mà bỏ qua các câu hỏi tương tác (sử dụng cấu hình mặc định của Next.js cho TypeScript), bạn có thể thêm cờ --ts
ngay trong lệnh:
npx create-next-app@latest ten-du-an-cua-ban --ts --eslint --app
# Hoặc với Yarn:
# yarn create next-app ten-du-an-cua-ban --ts --eslint --app
# Hoặc với pnpm:
# pnpm create next-app ten-du-an-cua-ban --ts --eslint --app
- _Giải thích:_
--ts
: Bật hỗ trợ TypeScript.--eslint
: Bật hỗ trợ ESLint.--app
: Sử dụng App Router (định tuyến dựa trên thư mụcapp
).
Lệnh này sẽ tạo một dự án mới với tên ten-du-an-cua-ban
, đã được cấu hình sẵn TypeScript, ESLint và sử dụng App Router.
Khám phá cấu trúc dự án mới
Sau khi quá trình cài đặt hoàn tất, bạn sẽ thấy một thư mục mới được tạo với tên mà bạn đã chọn. Hãy di chuyển vào thư mục đó:
cd ten-du-an-cua-ban
Bây giờ, hãy nhìn vào cấu trúc thư mục và tập tin bên trong. Bạn sẽ thấy một số thư mục và tập tin quan trọng:
my-next-ts-app/
├── app/ # Chứa các Route Segment và UI Components (App Router)
│ ├── layout.tsx # Layout gốc (bao bọc toàn bộ ứng dụng)
│ └── page.tsx # Trang chủ (root page)
├── public/ # Chứa các tài nguyên tĩnh (ảnh, font, v.v.)
├── styles/ # Chứa các tệp CSS (ví dụ: global.css)
├── .eslintrc.json # Cấu hình ESLint
├── next.config.js # Cấu hình Next.js
├── package.json # Thông tin dự án, dependency và script
├── postcss.config.js # Cấu hình PostCSS (nếu dùng Tailwind)
├── tailwind.config.ts # Cấu hình Tailwind CSS (nếu dùng Tailwind)
└── **tsconfig.json** # **Cấu hình TypeScript**
- _Giải thích:_
app/
: Đây là thư mục chính chứa code ứng dụng của bạn khi sử dụng App Router. Mỗi thư mục con trongapp
định nghĩa một phân đoạn route. Các file.tsx
hoặc.jsx
nhưpage.tsx
(định nghĩa trang) vàlayout.tsx
(định nghĩa bố cục) là các React Components..tsx
extensions: Đây là dấu hiệu rõ ràng nhất cho thấy dự án của bạn đang sử dụng TypeScript với React (TSX - TypeScript XML). Thay vì.js
hoặc.jsx
, chúng ta dùng.tsx
để viết code React với cú pháp TypeScript.tsconfig.json
: Đây là tệp cấu hình quan trọng nhất đối với TypeScript. Nó chứa các tùy chọn cho trình biên dịch TypeScript (tsc), quy định cách TypeScript kiểm tra code của bạn, phiên bản JavaScript mục tiêu, các thư viện (libs) được bao gồm, và nhiều cài đặt khác. Next.js sẽ tự động tạo và quản lý tệp này cho bạn, đảm bảo nó tương thích với môi trường Next.js.
Chạy ứng dụng lần đầu tiên
Sau khi đã có cấu trúc dự án, chúng ta hãy khởi động máy chủ phát triển để xem ứng dụng mặc định trông như thế nào.
Trong Terminal, đảm bảo bạn đang ở trong thư mục gốc của dự án (ten-du-an-cua-ban
) và chạy lệnh sau:
npm run dev
# Hoặc nếu dùng Yarn:
# yarn dev
# Hoặc nếu dùng pnpm:
# pnpm dev
- _Giải thích:_
npm run dev
: Lệnh này chạy scriptdev
được định nghĩa trong tệppackage.json
. Script này thường chạy lệnhnext dev
, khởi động máy chủ phát triển của Next.js.
Máy chủ phát triển sẽ bắt đầu chạy và bạn sẽ thấy thông báo trong Terminal cho biết ứng dụng đang chạy tại một địa chỉ nhất định, thường là http://localhost:3000
.
Mở trình duyệt của bạn và truy cập vào địa chỉ đó. Bạn sẽ thấy trang chào mừng mặc định của Next.js! Điều này xác nhận rằng dự án của bạn đã được cài đặt thành công và đang chạy.
Máy chủ phát triển của Next.js hỗ trợ Hot Module Replacement (HMR), có nghĩa là khi bạn thay đổi code và lưu lại, trình duyệt sẽ tự động cập nhật mà không cần phải tải lại trang thủ công. Điều này giúp tăng tốc độ phát triển đáng kể.
TypeScript hoạt động như thế nào trong Next.js?
Khi bạn chọn sử dụng TypeScript trong quá trình cài đặt, Next.js sẽ tự động:
- Cài đặt các dependency liên quan đến TypeScript (như
typescript
,@types/react
,@types/node
). - Tạo tệp
tsconfig.json
với cấu hình phù hợp. - Cho phép bạn viết code với cú pháp
.ts
và.tsx
.
Khi bạn chạy npm run dev
(hoặc yarn dev
, pnpm dev
), Next.js sẽ sử dụng trình biên dịch TypeScript (tsc) để kiểm tra và biên dịch code .ts
/.tsx
của bạn thành JavaScript trước khi chạy hoặc đóng gói ứng dụng. Nếu có bất kỳ lỗi kiểu dữ liệu nào (type errors), quá trình biên dịch sẽ báo lỗi và bạn sẽ thấy thông báo lỗi ngay trong Terminal hoặc trình duyệt.
Hãy xem một ví dụ đơn giản trong file app/page.tsx
mặc định:
// app/page.tsx
import Image from 'next/image' // Import với type definition đi kèm
export default function Home() {
// Next.js và React Components viết bằng TypeScript (.tsx)
// Bạn có thể định nghĩa các kiểu dữ liệu ở đây
const pageTitle: string = "Trang chủ Next.js với TypeScript";
return (
<main className="...">
{/* Code JSX */}
<h1>{pageTitle}</h1>
{/* Image component của Next.js có sẵn type definition */}
<Image
src="/next.svg"
alt="Next.js Logo"
width={180}
height={37}
priority
/>
{/* ... content khác */}
</main>
)
}
- _Giải thích:_
- Chúng ta sử dụng cú pháp TypeScript để khai báo biến
pageTitle
với kiểu dữ liệu rõ ràng làstring
. - Import các module (như
Image
từnext/image
) sẽ được kiểm tra kiểu dữ liệu nếu thư viện đó cung cấp các tệp định nghĩa kiểu (.d.ts
). Hầu hết các thư viện phổ biến trong hệ sinh thái React/Next.js đều có sẵn các tệp này. - Bên trong hàm component
Home
, bạn có thể viết bất kỳ code TypeScript hợp lệ nào. TypeScript sẽ kiểm tra code của bạn trong quá trình biên dịch. Ví dụ, nếu bạn cố gắng gán một số vào biếnpageTitle
:const pageTitle: string = 123;
, TypeScript sẽ báo lỗi ngay lập tức trước khi bạn chạy ứng dụng.
- Chúng ta sử dụng cú pháp TypeScript để khai báo biến
Điều này mang lại lợi ích to lớn: phát hiện sớm lỗi. Thay vì gặp lỗi runtime trong trình duyệt, bạn sẽ biết về chúng ngay khi đang viết code hoặc khi chạy máy chủ phát triển.
Hãy thử tạo một component nhỏ với props được định kiểu để thấy rõ hơn sức mạnh của TypeScript:
Tạo một file mới, ví dụ app/components/Greeting.tsx
:
// app/components/Greeting.tsx
// Định nghĩa kiểu dữ liệu cho props
type GreetingProps = {
name: string;
message?: string; // Dấu '?' nghĩa là prop này là tùy chọn
};
// Khai báo component với props được định kiểu
const Greeting = ({ name, message = "Hello" }: GreetingProps) => {
return (
<div>
<h2>{message}, {name}!</h2>
</div>
);
};
export default Greeting;
- _Giải thích:_
- Chúng ta dùng từ khóa
type
để định nghĩa một đối tượng kiểuGreetingProps
, mô tả các props mà componentGreeting
nhận vào. name: string;
yêu cầu propname
phải là một chuỗi.message?: string;
yêu cầu propmessage
là một chuỗi nhưng là tùy chọn (?
). Chúng ta cũng cung cấp giá trị mặc định ("Hello"
) nếu prop này không được truyền vào.- Component
Greeting
được định nghĩa là một mũi tên hàm, và các props được destructure cùng với chú thích kiểu: GreetingProps
.
- Chúng ta dùng từ khóa
Bây giờ, bạn có thể sử dụng component này trong app/page.tsx
:
// app/page.tsx
import Image from 'next/image'
import Greeting from './components/Greeting'; // Import component vừa tạo
export default function Home() {
const pageTitle: string = "Trang chủ Next.js với TypeScript";
return (
<main className="...">
<h1>{pageTitle}</h1>
{/* Sử dụng component Greeting với props đúng kiểu */}
<Greeting name="Next.js Developer" message="Welcome" />
{/* Sử dụng component Greeting chỉ với prop bắt buộc */}
<Greeting name="FullhouseDev Reader" />
{/* !!! Nếu bạn thử truyền sai kiểu dữ liệu, TypeScript sẽ báo lỗi !!! */}
{/* <Greeting name={123} message="Hey" /> // Lỗi: Type 'number' is not assignable to type 'string' */}
{/* <Greeting name="Test" message={456} /> // Lỗi: Type 'number' is not assignable to type 'string | undefined' */}
<Image
src="/next.svg"
alt="Next.js Logo"
width={180}
height={37}
priority
/>
{/* ... content khác */}
</main>
)
}
- _Giải thích:_
- Chúng ta import component
Greeting
vàopage.tsx
. - Khi sử dụng
<Greeting>
, TypeScript sẽ kiểm tra xem bạn có truyền đúng các props cần thiết và đúng kiểu dữ liệu đã định nghĩa trongGreetingProps
hay không. - Các dòng code bị commented-out (
// !!! ... !!!
) là ví dụ về việc cố gắng truyền sai kiểu dữ liệu. Nếu bỏ comment, trình biên dịch TypeScript sẽ báo lỗi ngay lập tức, giúp bạn ngăn chặn lỗi trước khi nó xảy ra trong trình duyệt.
- Chúng ta import component
Sức mạnh của việc kết hợp Next.js và TypeScript nằm ở đây: bạn có được một framework mạnh mẽ với các tính năng tối ưu cho ứng dụng web, cùng với sự an toàn và hiệu quả mà hệ thống kiểu tĩnh của TypeScript mang lại.
Cấu hình TypeScript nâng cao (tsconfig.json
)
Mặc dù Next.js tự động tạo tệp tsconfig.json
phù hợp cho hầu hết các trường hợp, bạn vẫn có thể tùy chỉnh nó để phù hợp với nhu cầu dự án của mình. Tệp này chứa rất nhiều tùy chọn cho trình biên dịch TypeScript.
Dưới đây là một cái nhìn về tệp tsconfig.json
mặc định được tạo bởi Next.js (có thể hơi khác tùy phiên bản và lựa chọn cài đặt):
// tsconfig.json
{
"compilerOptions": {
"lib": ["dom", "dom.iterable", "esnext"], // Thêm các thư viện định nghĩa kiểu
"allowJs": true, // Cho phép include file .js
"skipLibCheck": true, // Bỏ qua kiểm tra kiểu cho các file trong node_modules
"strict": true, // Bật chế độ strict mode (khuyến nghị!)
"noEmit": true, // Không tạo file output .js (việc biên dịch do Next.js đảm nhận)
"esModuleInterop": true, // Tương thích tốt hơn với các module ES
"module": "esnext", // Sử dụng hệ thống module ES
"moduleResolution": "bundler", // Cách giải quyết các import (phù hợp với Next.js)
"resolveJsonModule": true, // Cho phép import file .json
"isolatedModules": true, // Đảm bảo mỗi file là một module riêng biệt
"jsx": "preserve", // Giữ nguyên cú pháp JSX để Next.js xử lý
"incremental": true, // Bật biên dịch tăng cường
"plugins": [
{
"name": "next" // Plugin dành riêng cho Next.js
}
],
"paths": {
"@/*": ["./*"] // Cấu hình alias import (nếu bạn chọn dùng @/*)
}
},
"include": [
"next-env.d.ts", // Tệp định nghĩa môi trường của Next.js
"**/*.ts", // Bao gồm tất cả các file .ts
"**/*.tsx", // Bao gồm tất cả các file .tsx
".next/types/**/*.ts" // Bao gồm các định nghĩa kiểu được tạo bởi Next.js
],
"exclude": [
"node_modules" // Loại trừ thư mục node_modules
]
}
- _Giải thích:_
compilerOptions
: Chứa tất cả các tùy chọn cho trình biên dịch."strict": true
: Đây là một tùy chọn rất quan trọng và nên được bật. Nó kích hoạt một loạt các cờ kiểm tra kiểu nghiêm ngặt, giúp bạn viết code an toàn và đáng tin cậy hơn nhiều."jsx": "preserve"
: Bảo TypeScript giữ nguyên cú pháp JSX, vì việc chuyển đổi JSX sang các lệnh gọiReact.createElement
sẽ do Next.js (cụ thể là Babel hoặc SWC) thực hiện."paths": {"@/*": ["./*"]}
: Tùy chọn này được cấu hình nếu bạn chọn sử dụng alias import@/*
trong quá trình cài đặt. Nó cho phép bạn import các module từ thư mục gốc của dự án bằng cách bắt đầu đường dẫn với@/
thay vì phải sử dụng các đường dẫn tương đối dài dòng (../../components/
). Ví dụ:import Greeting from '@/components/Greeting';
.include
vàexclude
: Quy định những tệp và thư mục nào sẽ được TypeScript kiểm tra và biên dịch.
Bạn có thể tìm hiểu thêm về các tùy chọn trong tsconfig.json
trên trang web chính thức của TypeScript. Tuy nhiên, đối với phần lớn các dự án Next.js, cấu hình mặc định được tạo bởi create-next-app
với cờ --ts
đã là một điểm khởi đầu rất tốt.
Việc cài đặt thành công Next.js với TypeScript là bước đệm vững chắc để bạn bắt đầu xây dựng các ứng dụng web hiện đại, có hiệu suất cao và dễ bảo trì. Chúng ta đã sẵn sàng để khám phá sâu hơn về cách xây dựng các trang (pages), các component, xử lý dữ liệu và nhiều tính năng mạnh mẽ khác mà Next.js cung cấp, tất cả đều với sự hỗ trợ đắc lực từ TypeScript.
Comments