Tăng Tốc Docusaurus Với MSW: Giả Lập API Cho Tài Liệu Tương Tác
Khi bạn xây dựng tài liệu cho một API hoặc sản phẩm phụ thuộc vào dữ liệu từ backend, bạn sẽ đối mặt với một thách thức quen thuộc: làm thế nào để làm cho các ví dụ của bạn cảm thấy thực tế mà không phụ thuộc vào một môi trường staging dễ bị tổn thương hoặc phơi bày các điểm cuối sản xuất?
Bài viết này không chỉ là một tập hợp các đoạn mã — nó là một hướng dẫn chi tiết và sâu sắc về cách sử dụng 🛠 Mock Service Worker (MSW) với 📚 Docusaurus. Cuối bài, bạn sẽ biết không chỉ cách thiết lập nó mà còn nhiều điều khác.
💡 Tại Sao Tài Liệu Cần Phản Hồi API Thực Tế
Bạn đã bao giờ theo dõi một hướng dẫn API, nhấn “Chạy” và ngay lập tức gặp lỗi? ❌ Có thể máy chủ staging đã ngừng hoạt động. Có thể bạn không có mã thông báo xác thực đúng. Có thể dữ liệu trông… nhàm chán.
Người đọc của bạn cũng cảm thấy điều này.
Bằng cách giả lập API của bạn, bạn:
- ✨ Đảm Bảo Tính Nhất Quán: Dữ liệu trong các ví dụ của bạn luôn khớp với tài liệu.
- 🧪 Cung Cấp Một Sandbox An Toàn: Người đọc có thể thử nghiệm với các mẫu mã mà không làm hỏng bất cứ điều gì.
- ⚡ Giảm Rào Cản Gia Nhập: Không cần mã xác thực, VPN hay bước thiết lập nào — chỉ cần chạy
npm start
. - ✈️ Cho Phép Làm Việc Ngoại Tuyến: Các cộng tác viên có thể làm việc từ máy bay, tàu hỏa hoặc bất kỳ đâu mà không cần internet.
MSW chặn các yêu cầu ở lớp mạng (Service Worker), có nghĩa là frontend của bạn không biết sự khác biệt giữa API thực và giả — hoàn hảo cho tài liệu tương tác.
🏗 Bước 1: Cài Đặt MSW — Nền Tảng
Đầu tiên, bạn cần cài đặt MSW như một phụ thuộc phát triển:
npm install msw --save-dev
Điều này thêm công cụ cốt lõi mà bạn cần để khởi động một Service Worker trong môi trường phát triển.
🗂 Bước 2: Thiết Kế Kiến Trúc Giả Lập
Trước khi viết mã, hãy suy nghĩ về kiến trúc:
- Handlers: Định nghĩa từng điểm cuối bạn muốn giả lập.
- Browser Worker: Khởi động MSW trong trình duyệt.
- Node Server (Tùy Chọn): Cho phép bạn tái sử dụng cùng một bộ giả lập trong các bài kiểm tra.
Tạo một cấu trúc thư mục như sau:
my-docusaurus-app/
├── src/
│ ├── mocks/
│ │ ├── handlers.js ← định nghĩa điểm cuối
│ │ └── browser.js ← khởi động MSW
│ └── theme/
│ └── Root.js ← khởi động MSW trong chế độ phát triển
Cấu trúc này làm rõ cho các cộng tác viên tương lai nơi mà logic giả lập sống.
✍️ Bước 3: Viết Handler Đầu Tiên
Hãy nghĩ về một handler như là một hợp đồng API thu nhỏ — nó chỉ định phương thức HTTP nào, điểm cuối nào và phản hồi nào sẽ được trả về.
javascript
// src/mocks/handlers.js
import { rest } from 'msw';
export const handlers = [
rest.get('/api/info', (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json({
message: 'Xin chào từ MSW! Đây là một phản hồi ổn định, có thể dự đoán.'
})
);
}),
rest.post('/api/login', async (req, res, ctx) => {
const { username } = await req.json();
return res(
ctx.status(200),
ctx.json({ token: `fake-jwt-token-for-${username}` })
);
})
];
Điều này giúp cho việc tái tạo các luồng đăng nhập hoặc các yêu cầu fetch mà không cần một backend đang hoạt động trở nên dễ dàng.
🌐 Bước 4: Khởi Động MSW Trong Trình Duyệt
Tạo src/mocks/browser.js
:
javascript
import { setupWorker } from 'msw';
import { handlers } from './handlers';
export const worker = setupWorker(...handlers);
Tệp này kết nối tất cả các handlers và tạo một điểm vào duy nhất cho Service Worker.
🏃 Bước 5: Khởi Động Worker Trong Docusaurus
Chúng ta muốn MSW chạy tự động khi tài liệu được tải trong chế độ phát triển. Docusaurus cung cấp một cách để bọc toàn bộ ứng dụng qua Root.js
.
javascript
// src/theme/Root.js
import React, { useEffect } from 'react';
export default function Root({ children }) {
useEffect(() => {
if (process.env.NODE_ENV === 'development') {
import('../mocks/browser').then(({ worker }) => {
worker.start({ onUnhandledRequest: 'bypass' });
});
}
}, []);
return <>{children}</>;
}
Tại sao lại là onUnhandledRequest: 'bypass'
? Điều này đảm bảo rằng các yêu cầu chưa được giả lập vẫn đến API thực, điều này hữu ích nếu bạn chỉ đang giả lập một phần của backend.
🎨 Bước 6: Làm Cho Tài Liệu Tương Tác
Dưới đây là một ví dụ về thành phần React mà lấy dữ liệu từ điểm cuối giả lập của chúng ta:
javascript
import React, { useEffect, useState } from 'react';
export default function ExampleComponent() {
const [data, setData] = useState(null);
useEffect(() => {
fetch('/api/info')
.then((res) => res.json())
.then(setData);
}, []);
return (
<div style={{ background: '#f8f8f8', padding: '1rem', borderRadius: '8px' }}>
<h4>Phản Hồi API Giả Lập</h4>
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
);
}
Điều này tạo ra một thành phần sống động ngay trong tài liệu của bạn, để người đọc có thể thấy các phản hồi thực tế như chúng sẽ xuất hiện trong một ứng dụng thực sự.
🏗 Xử Lý Triển Khai Trên GitLab Pages (URL Động)
Một thách thức mà tôi đã gặp phải sau khi tích hợp MSW là triển khai tài liệu trên GitLab Pages. Mỗi lần chạy pipeline tạo ra một URL động như:
https://myproject.gitlab.io/-/jobs/235345/artifacts/public/index.html
Theo mặc định, MSW tìm kiếm mockServiceWorker.js
tại gốc (/mockServiceWorker.js
). Trên GitLab Pages với các URL động, điều này đã bị hỏng vì Service Worker nằm ở:
https://myproject.gitlab.io/-/jobs/235345/artifacts/mockServiceWorker.js
Giải Pháp
Khi gọi worker.start()
, bạn có thể truyền một tùy chọn serviceWorker.url
để cho MSW biết chính xác nơi tìm tệp:
javascript
worker.start({
serviceWorker: {
url: `${window.location.pathname.replace(/\/index\.html$/, '')}/mockServiceWorker.js`
}
});
Điều này tính toán động URL chính xác dựa trên đường dẫn của trang hiện tại, đảm bảo MSW luôn được tìm thấy bất kể lần chạy pipeline.
Sửa đổi nhỏ này đã làm cho việc triển khai GitLab Pages trở nên đáng tin cậy và bền vững, vì mỗi lần pipeline tạo ra một trang tài liệu tương tác hoàn toàn chức năng.
Bước 7: Những Cạm Bẫy Thường Gặp Và Cách Tránh Chúng
- Lỗi CORS: Đảm bảo rằng URL giả lập của bạn khớp chính xác với những gì
fetch
đang yêu cầu (bao gồm cả miền). - Worker Không Khởi Động: Quên import
browser.js
trongRoot.js
có nghĩa là MSW không bao giờ chạy. - Xây Dựng Sản Xuất Bị Hỏng: Bảo vệ khởi động MSW với
NODE_ENV
để nó chỉ chạy cục bộ. - Đường Dẫn Động Trên CI/CD: Sử dụng
serviceWorker.url
để chỉ định MSW đến vị trí chính xác trong các triển khai CI/CD.
Phía Sau Phát Triển: Sử Dụng MSW Trong Các Bài Kiểm Tra
Một trong những siêu năng lực của MSW là bạn có thể tái sử dụng những mock này trong các bài kiểm tra tích hợp:
javascript
import { setupServer } from 'msw/node';
import { handlers } from './handlers';
const server = setupServer(...handlers);
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
Bây giờ, các bài kiểm tra của bạn, môi trường phát triển cục bộ và tài liệu của bạn đều nói cùng một ngôn ngữ.
Kết Luận
Giả lập APIs trong trang Docusaurus của bạn không chỉ là một thủ thuật, nó là một yếu tố chuyên nghiệp giúp tài liệu tuyệt vời trở nên nổi bật. Bằng cách sử dụng MSW, bạn nhận được phản hồi giống như sản xuất mà không gặp phải những đau đầu giống như sản xuất. Người dùng của bạn học nhanh hơn và nhóm của bạn dành ít thời gian hơn cho việc xử lý tài liệu.
Các Thực Hành Tốt Nhất
- Giữ cho các mock của bạn đơn giản và rõ ràng.
- Thường xuyên kiểm tra để đảm bảo các phản hồi giả lập khớp với API thực tế.
Câu Hỏi Thường Gặp (FAQ)
1. MSW có tương thích với tất cả các framework không?
Có, MSW có thể được sử dụng với hầu hết các framework frontend.
2. Tôi có thể sử dụng MSW trong môi trường sản xuất không?
Không nên. MSW chủ yếu được thiết kế cho môi trường phát triển và kiểm tra.