Mặc dù công nghệ frontend thay đổi rất nhanh chóng với các IDE và công cụ liên tục được cập nhật, nhưng chúng ta vẫn cần hiểu rõ tư duy cơ bản trong việc xây dựng chương trình. Những môi trường và công cụ này đều nhằm mục đích giúp chúng ta phát hành ứng dụng nhanh hơn. Tôi nhớ lại thời điểm trước đây khi viết mã frontend chỉ sử dụng trình soạn thảo văn bản đơn giản, sau đó làm mới trình duyệt là xong. Đối với các dự án frontend thuần túy, cách này thực sự khá tiện lợi. Tuy nhiên, khi gặp phải vấn đề truy cập tài nguyên file sẽ trở nên phức tạp do giới hạn bảo mật của trình duyệt không cho phép truy cập tài nguyên ngoài miền. Bạn sẽ cần triển khai lên máy chủ web, điều này đồng nghĩa với việc phải khởi động một server. Ngoài ra, quá trình gỡ lỗi cũng yêu cầu làm mới trang mỗi lần; việc quản lý thư viện bên thứ ba cũng là vấn đề cần tự xử lý. Vì vậy, các công cụ phát triển và xây dựng frontend như Vite đã xuất hiện để tự động hóa các bước trên, tăng hiệu suất lập trình frontend. Dưới đây tôi sẽ tổng hợp cách tạo dự án frontend trang web động bằng Vite.
Trước tiên, cài đặt Node.js và npm. Node.js là môi trường chạy JavaScript, npm là công cụ quản lý gói và chạy tác vụ, quá trình cài đặt khá đơn giản nên không trình bày chi tiết ở đây.
Tiếp theo, chọn một thư mục và chạy lệnh sau trong terminal để tạo dự án:
npm create vite@latest my-frontend-project
Lúc này, terminal sẽ yêu cầu bạn chọn một framework:
> npx
> create-vite my-frontend-project
|
* Select a framework:
| > Vanilla
| Vue
| React
| Preact
| Lit
| Svelte
| Solid
| Qwik
| Angular
| Marko
| Others
—
Tôi chọn Vanilla, biểu thị mẫu gốc không sử dụng bất kỳ framework nào. Sau đó, terminal sẽ hỏi bạn muốn dùng TypeScript hay JavaScript:
> npx
> create-vite my-frontend-project
|
o Select a framework:
| Vanilla
|
* Select a variant:
| > TypeScript
| JavaScript
—
Tôi chọn JavaScript. Sau một lúc chờ đợi, dự án frontend đã được tạo thành công như sau:
> npx
> create-vite my-frontend-project
|
o Select a framework:
| Vanilla
|
o Select a variant:
| JavaScript
|
o Scaffolding project in C:\Work\js\my-frontend-project...
|
— Done. Now run:
cd my-frontend-project
npm install
npm run dev
Mặc dù có thể tiếp tục dùng terminal, nhưng lúc này có thể chuyển sang VS Code để quản lý dự án. Mở thư mục my-frontend-project bằng VS Code và khởi động terminal như hình dưới:
Thực thi lệnh trong terminal:
npm install
Bước này dùng để cài đặt các thư viện phụ thuộc bên thứ ba. Nói chung, nếu bạn bắt đầu một dự án mới, bước này là bắt buộc. Tất nhiên sau khi cài đặt xong các thư viện phụ thuộc, nếu sau này không có thay đổi gì về thư viện thì không cần thực hiện lại bước này.
Cấu trúc tổ chức file của dự án lúc này như sau:
my-frontend-project
├── public
│ └── vite.svg
├── src
│ ├── counter-module.js
│ ├── javascript.svg
│ ├── app-main.js
│ └── styles.css
├── index.html
└── package.json
File package.json là file cấu hình lõi của npm, như sau:
{
"name": "my-frontend-project",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"devDependencies": {
"vite": "^6.3.5"
}
}
Hai vai trò chính như sau:
- Quản lý phụ thuộc. Các trường dependencies và devDependencies, trong đó trường dependencies là các gói thư viện cần thiết cho dự án, devDependencies là các gói thư viện cần thiết để xây dựng dự án. Việc thực thi `npm install` là để tự động cài đặt các gói phụ thuộc tương ứng dựa trên giá trị trong hai trường này.
- Thực thi script tác vụ. Trường scripts, thông qua các lệnh tùy chỉnh để thực hiện các nhiệm vụ liên quan đến xây dựng, các lệnh dev, build và preview ở đây là ba lệnh cơ bản và thường dùng nhất.
dev là thực thi lệnh:
npm run dev
Biểu thị khởi động server trong môi trường phát triển, terminal thường hiển thị như sau:
> my-frontend-project@0.0.0 dev
> vite
VITE v6.3.5 ready in 500 ms
➜ Local: http://localhost:5173/
➜ Network: use --host to expose
➜ press h + enter to show help
Truy cập địa chỉ trong trình duyệt: http://localhost:5173/, bạn có thể thấy trang hiển thị một ví dụ HTML + JS cơ bản như sau:
Hai lệnh còn lại chủ yếu dùng cho quá trình triển khai thực tế:
- `npm run build` xây dựng mã nguồn dự án, ví dụ như nén, nối, làm rối, v.v.
- `npm run preview` triển khai dự án mã nguồn sau khi xây dựng xong.
Dự án JS mẫu này không chỉ là trang chào mừng mà thậm chí còn là trang động: có thể đếm số lần click chuột. Chúng ta hãy phân tích một chút mã nguồn. Trước tiên là index.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My App</title>
</head>
<body>
<div id="root-container"></div>
<script type="module" src="/src/app-main.js"></script>
</body>
</html>
Có thể thấy trang HTML này không hiển thị phần tử giao diện nào vì các phần tử đều được tải động qua JS. Ngoài ra, lưu ý rằng dòng này:
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
Dùng để tương thích màn hình độ phân giải cao, chi tiết có thể tham khảo bài viết của tôi "Cài đặt màn hình độ phân giải cao cho trang HTML". Ngay cả ví dụ đơn giản nhất cũng mang theo thẻ meta này vì hiện nay thiết bị dùng màn hình độ phân giải cao đã rất phổ biến.
Chúng ta cùng xem app-main.js:
import './styles.css'
import jsIcon from './javascript.svg'
import viteIcon from '/vite.svg'
import { initializeCounter } from './counter-module.js'
document.querySelector('#root-container').innerHTML = `
<div>
<a href="https://vite.dev" target="_blank">
<img src="${viteIcon}" class="logo" alt="Vite logo" />
</a>
<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript" target="_blank">
<img src="${jsIcon}" class="logo vanilla" alt="JavaScript logo" />
</a>
<h1>Hello World!</h1>
<div class="card">
<button id="click-counter" type="button"></button>
</div>
<p class="read-the-docs">
Click on the logos to learn more
</p>
</div>
`
initializeCounter(document.querySelector('#click-counter'))
Nội dung chính của đoạn mã này như đã nói ở trên, tìm kiếm phần tử #root-container và điền chuỗi HTML, tức là trang này trước tiên hiển thị HTML, sau đó tải phần tử vào trang qua js một cách động.
Một điểm thú vị khác là các import ở đây:
import './styles.css'
import jsIcon from './javascript.svg'
import viteIcon from '/vite.svg'
Thực tế không phải hành vi JS gốc mà là do Vite cung cấp. Điều này cũng thể hiện một tư tưởng, đối với ba thành phần HTML, CSS và JavaScript, JavaScript mới là chính, các kiểu dáng css và trang HTML đều có thể được tạo ra thông qua JavaScript.
Cùng xem counter-module.js:
export function initializeCounter(targetElement) {
let clickCount = 0
const updateCount = (value) => {
clickCount = value
targetElement.innerHTML = `clicked: ${clickCount}`
}
targetElement.addEventListener('click', () => updateCount(clickCount + 1))
updateCount(0)
}
Cài đặt hàm rất đơn giản, chỉ là chức năng đếm cơ bản. Tuy nhiên cần lưu ý rằng ở đây `export function initializeCounter(targetElement)` sử dụng cú pháp export module trong JavaScript ES6 (ECMAScript 2015), biểu thị export hàm initializeCounter này. Trong app-main.js thì thực hiện import:
import { initializeCounter } from './counter-module.js'
initializeCounter(document.querySelector('#click-counter'))
Lý do chọn sử dụng dự án JS gốc mà không dùng framework là vì tôi muốn nghiên cứu cài đặt tầng thấp hơn và trải nghiệm so sánh tư duy thiết kế của một số framework. Tất nhiên không nên tự tạo lại bánh xe, nhưng cũng không nên rời khỏi những bánh xe này mà không biết làm gì, hiểu rõ những thứ sâu sắc và nền tảng hơn sẽ giúp chúng ta cập nhật đổi mới, sử dụng những bánh xe tốt hơn.