Trong bài viết này, chúng ta sẽ tìm hiểu cách tối ưu hóa và xây dựng ứng dụng Next.js hiệu suất cao bằng Nx và các tính năng phong phú của nó. Chúng ta sẽ tìm hiểu cách thiết lập máy chủ Nx, cách thêm plugin vào máy chủ hiện có và khái niệm về monorepo với hình ảnh trực quan thực tế.
Nếu bạn là nhà phát triển đang tìm cách tối ưu hóa ứng dụng và tạo các thành phần có thể tái sử dụng trên nhiều ứng dụng một cách hiệu quả, bài viết này sẽ chỉ cho bạn cách mở rộng quy mô ứng dụng nhanh chóng và cách làm việc với Nx. Để theo dõi, bạn sẽ cần có kiến thức cơ bản về khuôn khổ Next.js và TypeScript.
Trong bài viết này, chúng tôi sẽ tập trung vào cách Nx hoạt động với các ứng dụng Next.js. Nx cung cấp các công cụ tiêu chuẩn để thử nghiệm và tạo kiểu trong các ứng dụng Next.js của bạn, chẳng hạn như Cypress, Storybook và styled-components. Nx tạo điều kiện cho một monorepo cho các ứng dụng của bạn, tạo ra một không gian làm việc có thể chứa mã nguồn và thư viện của nhiều ứng dụng, cho phép bạn chia sẻ tài nguyên giữa các ứng dụng.
Có nhiều lợi thế khi sử dụng Nx và chúng tôi sẽ hướng dẫn một số lợi thế trong số đó trong phần này.
Nx cung cấp cho bạn tùy chọn tạo không gian làm việc mới với Next.js làm cài đặt trước hoặc thêm Next.js vào không gian làm việc hiện có.
Để tạo không gian làm việc mới với Next.js làm cài đặt trước, bạn có thể sử dụng lệnh sau:
Lệnh này sẽ tạo một không gian làm việc Nx mới với ứng dụng Next.js có tên là "todo" và với
Sau đó, chúng ta có thể thêm ứng dụng Next.js vào không gian làm việc Nx hiện có bằng lệnh sau:
Khối mã ở trên sẽ tạo một không gian làm việc Nx mới và ứng dụng Next.js. Chúng ta sẽ nhận được lời nhắc sử dụng Nx Cloud. Đối với hướng dẫn này, chúng ta sẽ chọn "No", sau đó đợi các dependency của chúng ta được cài đặt. Sau khi hoàn tất, chúng ta sẽ có một cây tệp tương tự như thế này:
Trong thư mục
Để chạy ứng dụng của chúng ta, hãy sử dụng lệnh

Sau khi hoàn tất, chúng ta đã sẵn sàng thiết lập ứng dụng Express trong không gian làm việc được cung cấp. Để tạo ứng dụng Express, hãy chạy lệnh bên dưới:
Lệnh
Thư mục
Chúng ta sẽ tạo các tuyến đường bên trong ứng dụng này. Để bắt đầu, chúng ta sẽ khởi tạo một mảng các đối tượng với hai cặp khóa-giá trị,
Tiếp theo, chúng ta sẽ thiết lập tuyến đường để lấy tất cả danh sách việc cần làm trong
Khối mã ở trên sẽ trả về giá trị hiện tại của
Để tạo một mục việc cần làm mới, tất cả những gì chúng ta cần là giá trị của mục mới dưới dạng chuỗi. Chúng ta sẽ tạo ID bằng cách tăng ID của phần tử cuối cùng trong mảng trên máy chủ. Để cập nhật một mục hiện có, chúng ta sẽ truyền giá trị mới cho mục đó và ID của đối tượng mục cần cập nhật; trên máy chủ, chúng ta sẽ lặp qua từng mục bằng phương thức
Lưu ý: Nếu bạn nhìn vào thư mục ứng dụng Next.js, bạn sẽ thấy tệp
Điều này tạo ra một proxy, cho phép tất cả các lệnh gọi API đến các tuyến khớp với
Khi chạy lệnh này, chúng ta sẽ nhận được lời nhắc chọn thư viện tạo kiểu mà chúng ta muốn sử dụng cho trang; đối với bài viết này, chúng ta sẽ chọn
Đối với chức năng cập nhật, chúng ta có một đầu vào bị vô hiệu hóa khi trạng thái
Trong thành phần trang
Trong khối mã ở trên, chúng ta có
Để hiển thị mục việc cần làm, chúng ta ánh xạ qua trạng thái
Máy chủ và giao diện người dùng của chúng tôi hiện đã được thiết lập. Chúng tôi có thể phục vụ ứng dụng API bằng cách chạy

Bây giờ chúng ta có một ứng dụng Next.js và Express hoạt động cùng nhau trong một không gian làm việc.
Nx có một công cụ CLI khác cho phép chúng ta xem biểu đồ phụ thuộc của ứng dụng trong terminal run. Chạy

Bạn sẽ tìm thấy mã nguồn đầy đủ trong kho lưu trữ GitHub. Để biết thêm thông tin về Nx, hãy xem tài liệu hoặc tài liệu Nx cho Next.js.
Nếu bạn là nhà phát triển đang tìm cách tối ưu hóa ứng dụng và tạo các thành phần có thể tái sử dụng trên nhiều ứng dụng một cách hiệu quả, bài viết này sẽ chỉ cho bạn cách mở rộng quy mô ứng dụng nhanh chóng và cách làm việc với Nx. Để theo dõi, bạn sẽ cần có kiến thức cơ bản về khuôn khổ Next.js và TypeScript.
Nx là gì?
Nx là một khuôn khổ xây dựng mã nguồn mở giúp bạn thiết kế, thử nghiệm và xây dựng ở mọi quy mô — tích hợp liền mạch với các công nghệ và thư viện hiện đại, đồng thời cung cấp giao diện dòng lệnh (CLI), bộ nhớ đệm và quản lý phụ thuộc mạnh mẽ. Nx cung cấp cho các nhà phát triển các công cụ CLI và plugin tiên tiến cho các khuôn khổ, thử nghiệm và công cụ hiện đại.Trong bài viết này, chúng tôi sẽ tập trung vào cách Nx hoạt động với các ứng dụng Next.js. Nx cung cấp các công cụ tiêu chuẩn để thử nghiệm và tạo kiểu trong các ứng dụng Next.js của bạn, chẳng hạn như Cypress, Storybook và styled-components. Nx tạo điều kiện cho một monorepo cho các ứng dụng của bạn, tạo ra một không gian làm việc có thể chứa mã nguồn và thư viện của nhiều ứng dụng, cho phép bạn chia sẻ tài nguyên giữa các ứng dụng.
Tại sao nên sử dụng Nx?
Nx cung cấp cho các nhà phát triển một lượng chức năng hợp lý ngay khi cài đặt, bao gồm các mẫu để thử nghiệm đầu cuối (E2E) cho ứng dụng của bạn, một thư viện định kiểu và một monorepo.Có nhiều lợi thế khi sử dụng Nx và chúng tôi sẽ hướng dẫn một số lợi thế trong số đó trong phần này.
- Thực thi tác vụ dựa trên đồ thị
Nx sử dụng thực thi tác vụ dựa trên đồ thị phân tán và bộ nhớ đệm tính toán để tăng tốc các tác vụ. Hệ thống sẽ lên lịch các tác vụ và lệnh bằng hệ thống đồ thị để xác định nút nào (tức là ứng dụng) sẽ thực thi từng tác vụ. Điều này xử lý việc thực thi các ứng dụng và tối ưu hóa thời gian thực thi một cách hiệu quả. - Kiểm thử
Nx cung cấp các công cụ kiểm thử được cấu hình sẵn để kiểm thử đơn vị và kiểm thử E2E. - Lưu trữ đệm
Nx cũng lưu trữ biểu đồ dự án được lưu trong bộ nhớ đệm. Điều này cho phép nó chỉ phân tích lại các tệp đã cập nhật. Nx theo dõi các tệp đã thay đổi kể từ lần xác nhận cuối cùng và cho phép bạn kiểm tra, xây dựng và thực hiện các hành động chỉ trên các tệp đó; điều này cho phép tối ưu hóa phù hợp khi bạn làm việc với cơ sở mã lớn. - Biểu đồ phụ thuộc
Biểu đồ phụ thuộc trực quan cho phép bạn kiểm tra cách các thành phần tương tác với nhau. - Lưu trữ đám mây
Nx cũng cung cấp lưu trữ đám mây và tích hợp GitHub, để bạn có thể chia sẻ liên kết với các thành viên trong nhóm để xem lại nhật ký dự án. - Chia sẻ mã
Việc tạo một thư viện dùng chung mới cho mọi dự án có thể khá tốn kém. Nx loại bỏ sự phức tạp này, giúp bạn tập trung vào chức năng cốt lõi của ứng dụng. Với Nx, bạn có thể chia sẻ thư viện và thành phần trên nhiều ứng dụng. Bạn thậm chí có thể chia sẻ mã có thể tái sử dụng giữa các ứng dụng front-end và back-end của mình. - Hỗ trợ monorepos
Nx cung cấp một không gian làm việc cho nhiều ứng dụng. Với thiết lập này, một kho lưu trữ GitHub có thể chứa nguồn mã cho nhiều ứng dụng khác nhau trong không gian làm việc của bạn.
Nx For Publishable Libraries
Nx cho phép bạn tạo các thư viện có thể xuất bản. Điều này rất cần thiết khi bạn có các thư viện mà bạn sẽ sử dụng bên ngoài monorepo. Trong bất kỳ trường hợp nào bạn đang phát triển các thành phần UI tổ chức với tích hợp Nx Storybook, Nx sẽ tạo các thành phần có thể xuất bản cùng với các câu chuyện của bạn. Các thành phần có thể xuất bản có thể biên dịch các thành phần này để tạo một gói thư viện mà bạn có thể triển khai vào một sổ đăng ký bên ngoài. Bạn sẽ sử dụng tùy chọn--publishable
khi tạo thư viện, không giống như --buildable
, được sử dụng để tạo các thư viện chỉ được sử dụng trong monorepo. Nx không tự động triển khai các thư viện có thể xuất bản; bạn có thể gọi bản dựng thông qua lệnh như nx build mylib
(trong đó mylib
là tên của thư viện), sau đó sẽ tạo ra một gói được tối ưu hóa trong thư mục dist
/mylib
có thể được triển khai vào sổ đăng ký bên ngoài.Nx cung cấp cho bạn tùy chọn tạo không gian làm việc mới với Next.js làm cài đặt trước hoặc thêm Next.js vào không gian làm việc hiện có.
Để tạo không gian làm việc mới với Next.js làm cài đặt trước, bạn có thể sử dụng lệnh sau:
Mã:
npx create-nx-workspace happynrwl \--preset=next \--style=styled-components \--appName=todo
styled-components
làm thư viện tạo kiểu.Sau đó, chúng ta có thể thêm ứng dụng Next.js vào không gian làm việc Nx hiện có bằng lệnh sau:
Mã:
npx nx g @nrwl/next:app
Xây dựng ứng dụng Next.js và Nx
Plugin Nx cho Next.js bao gồm các công cụ và trình thực thi để chạy và tối ưu hóa ứng dụng Next.js. Để bắt đầu, chúng ta cần tạo một không gian làm việc Nx mới vớinext
làm cài đặt trước:
Mã:
npx create-nx-workspace happynrwl \--preset=next \--style=styled-components \--appName=todo
Mã:
📦happynrwl ┣ 📂apps ┃ ┣ 📂todo ┃ ┣ 📂todo-e2e ┃ ┗ 📜.gitkeep ┣ 📂libs ┣ 📂node_modules ┣ 📂tools ┣ 📜.editorconfig ┣ 📜.eslintrc.json ┣ 📜.gitignore ┣ 📜.prettierignore ┣ 📜.prettierrc ┣ 📜README.md ┣ 📜babel.config.json ┣ 📜jest.config.js ┣ 📜jest.preset.js ┣ 📜nx.json ┣ 📜package-lock.json ┣ 📜package.json ┣ 📜tsconfig.base.json ┗ 📜workspace.json
📂apps
, chúng ta sẽ có ứng dụng Next.js "todo" của mình, với bài kiểm tra E2E được cấu hình sẵn cho ứng dụng to-do. Tất cả những điều này được tự động tạo bằng công cụ Nx CLI mạnh mẽ.Để chạy ứng dụng của chúng ta, hãy sử dụng lệnh
npx nx serve todo
. Sau khi bạn hoàn tất việc phục vụ ứng dụng, bạn sẽ thấy màn hình bên dưới:
Xây dựng API
Tại thời điểm này, chúng tôi đã thiết lập không gian làm việc. Tiếp theo là xây dựng API CRUD mà chúng tôi sẽ sử dụng trên ứng dụng Next.js. Để thực hiện việc này, chúng tôi sẽ sử dụng Express; để chứng minh hỗ trợ monorepo, chúng tôi sẽ xây dựng máy chủ của mình dưới dạng ứng dụng trong không gian làm việc. Trước tiên, chúng ta phải cài đặt plugin Express cho Nx bằng cách chạy lệnh này:
Mã:
npm install --save-dev @nrwl/express
Mã:
npx nx g @nrwl/express:application --name=todo-api --frontendProject=todo
nx g @nrwl/express:application
sẽ tạo ứng dụng Express mà chúng ta có thể truyền các tham số đặc tả bổ sung; để chỉ định tên ứng dụng, hãy sử dụng cờ --name
; để chỉ ra ứng dụng front-end sẽ sử dụng ứng dụng Express, hãy truyền tên ứng dụng trong không gian làm việc của chúng ta tới --frontendProject
. Một số tùy chọn khác khả dụng cho ứng dụng Express. Khi hoàn tất, chúng ta sẽ có cấu trúc tệp được cập nhật trong thư mục apps
với thư mục 📂todo-api
được thêm vào.
Mã:
📦happynrwl ┣ 📂apps ┃ ┣ 📂todo ┃ ┣ 📂todo-api ┃ ┣ 📂todo-e2e ┃ ┗ 📜.gitkeep …
todo-api
là một mẫu Express có tệp mục nhập main.ts
.
Mã:
/** * Đây chưa phải là máy chủ sản xuất! * Đây chỉ là phần back-end tối thiểu để bắt đầu. */import * as express from 'express';import {v4 as uuidV4} from 'uuid';const app = express();app.use(express.json()); // được sử dụng thay cho body-parserapp.get('/api', (req, res) => { res.send({ message: 'Welcome to todo-api!' });});const port = process.env.port || 3333;const server = app.listen(port, () => { console.log(`Listening at http://localhost:${port}/api`);});server.on('error', console.error);
item
và id
, ngay bên dưới khai báo ứng dụng.
Mã:
/** * Đây chưa phải là máy chủ sản xuất! * Đây chỉ là phần cuối tối thiểu để bắt đầu. */import * as express from 'express';import {v4 as uuidV4} from 'uuid';const app = express();app.use(express.json()); // được sử dụng thay cho body-parserlet todoArray: Array = [ { item: 'default todo', id: uuidV4() },];…
app.get()
:
Mã:
…app.get('/api', (req, res) => { res.status(200).json({ data: todoArray, });});…
todoArray
. Sau đó, chúng ta sẽ có các tuyến đường để tạo, cập nhật và xóa các mục việc cần làm khỏi mảng.
Mã:
…app.post('/api', (req, res) => { const item: string = req.body.item; // Tăng ID của mục dựa trên ID của mục cuối cùng trong mảng. let id: string = uuidV4(); // Thêm đối tượng mới vào mảng todoArray.push({ item, id }); res.status(200).json({ message: 'item added successfully', });});app.patch('/api', (req, res) => { // Giá trị của mục được cập nhật const updatedItem: string = req.body.updatedItem; // ID của vị trí cần cập nhật const id: string = req.body.id; // Tìm chỉ mục của ID const arrayIndex = todoArray.findIndex((obj) => obj.id === id); // Cập nhật mục khớp với chỉ mục todoArray[arrayIndex].item = updatedItem res.status(200).json({ message: 'item updated successfully', });});app.delete('/api', (req, res) => { // ID của vị trí cần xóa const id: string = req.body.id; // Cập nhật mảng và xóa đối tượng khớp với ID todoArray = todoArray.filter((val) => val.id !== id); res.status(200).json({ message: 'item removed successfully', });});…
forEach
và cập nhật mục tại vị trí mà ID khớp với ID được gửi cùng với yêu cầu. Cuối cùng, để xóa một mục khỏi mảng, chúng ta sẽ gửi ID của mục cần xóa cùng với yêu cầu; sau đó, chúng tôi lọc qua mảng và trả về một mảng mới gồm tất cả các mục không khớp với ID được gửi cùng với yêu cầu, gán mảng mới cho biến todoArray
.Lưu ý: Nếu bạn nhìn vào thư mục ứng dụng Next.js, bạn sẽ thấy tệp
proxy.conf.json
có cấu hình bên dưới:
Mã:
{ "/api": { "target": "http://localhost:3333", "secure": false }}
/api
để nhắm mục tiêu đến máy chủ todo-api
.Tạo các trang Next.js bằng Nx
Trong ứng dụng Next.js của chúng tôi, chúng tôi sẽ tạo một trang mới,home
và một thành phần item. Nx cung cấp cho chúng ta một công cụ CLI để dễ dàng tạo một trang:
Mã:
npx nx g @nrwl/next:page home
styled-components
. Voilà! Trang của chúng ta đã được tạo. Để tạo một thành phần, hãy chạy npx nx g @nrwl/next:component todo-item
; thao tác này sẽ tạo một thư mục compontion
có thành phần todo-item
.Tiêu thụ API trong ứng dụng Next.js
Trong mỗi mục việc cần làm, chúng ta sẽ có hai nút để chỉnh sửa và xóa mục việc cần làm. Các hàm không đồng bộ thực hiện các hành động này được truyền dưới dạng props từ trang chủ.
Mã:
…export interface TodoItemProps { updateItem(id: string, updatedItem: string): Promise; deleteItem(id: string): Promise; fetchItems(): Promise; item: string; id: string;}export const FlexWrapper = styled.div` width: 100%; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #ccc; padding-bottom: 10px; margin-top: 20px; @media all and (max-width: 470px) { flex-direction: column; input { width: 100%; } button { width: 100%; } }`;hàm xuất TodoItem(props: TodoItemProps) { const [isEditingItem, setIsEditingItem] = useState(false); const [item, setNewItem] = useState(null); trả về ( setNewItem(target.value)} /> {!isEditingItem && setIsEditingItem(true)} > Chỉnh sửa } {isEditingItem && { await props.updateItem(props.id, item); //lấy các mục đã cập nhật await props.fetchItems(); setIsEditingItem(false) }}> Cập nhật } { await props.deleteItem(props.id); //fetch updated items await await props.fetchItems(); }} > Delete );}
isEditingItem
là false
. Khi nhấp vào nút "Edit", nó sẽ chuyển trạng thái isEditingItem
thành true
và hiển thị nút "Update". Tại đây, thành phần đầu vào được bật và người dùng có thể nhập giá trị mới; khi nút “Cập nhật” được nhấp, nó sẽ gọi hàm updateItem
với các tham số được truyền vào và chuyển đổi isEditingItem
trở lại false
.Trong thành phần trang
home
, chúng ta có các hàm không đồng bộ thực hiện thao tác CRUD.
Mã:
… const [items, setItems] = useState([]); const [newItem, setNewItem] = useState(''); const fetchItems = async () => { try { const data = await fetch('/api/fetch'); const res = await data.json(); setItems(res.data); } catch (error) { console.log(error); } }; const createItem = async (item: chuỗi) => { thử { const data = await fetch('/api', { phương thức: 'POST', nội dung: JSON.stringify({ mục }), tiêu đề: { 'Kiểu nội dung': 'application/json', }, }); } bắt (lỗi) { console.log(lỗi); } }; const deleteItem = async (id: chuỗi) => { thử { const data = await fetch('/api', { phương thức: 'XÓA', nội dung: JSON.stringify({ id }), tiêu đề: { 'Kiểu nội dung': 'application/json', }, }); const res = await data.json(); cảnh báo(res.message); } bắt (lỗi) { console.log(lỗi); } }; const updateItem = async (id: chuỗi, updatedItem: chuỗi) => { try { const data = await fetch('/api', { method: 'PATCH', body: JSON.stringify({ id, updatedItem }), headers: { 'Content-Type': 'application/json', }, }); const res = await data.json(); alert(res.message); } catch (error) { console.log(error); } }; useEffect(() => { fetchItems(); }, []);…
fetchItems
, trả về todoArray
từ máy chủ. Sau đó, chúng ta có hàm createItem
, lấy một chuỗi; tham số là giá trị của mục việc cần làm mới. Hàm updateItem
lấy hai tham số, ID của mục cần cập nhật và giá trị updatedItem
. Và hàm deleteItem
xóa mục khớp với ID được truyền vào.Để hiển thị mục việc cần làm, chúng ta ánh xạ qua trạng thái
items
:
Mã:
…return ( [HEADING=1]Welcome to Home![/HEADING] {items.length > 0 && items.map((val) => ( ))} { e.preventDefault(); await createItem(newItem); //Dọn dẹp mục mới setNewItem(''); await fetchItems(); }} > setNewItem(target.value)} placeholder="Thêm mục mới…" /> Thêm + );…
npx nx serve todo-api
và đối với ứng dụng Next.js, chúng tôi chạy npx nx serve todo
. Nhấp vào nút “Tiếp tục” và bạn sẽ thấy một trang hiển thị mục việc cần làm mặc định.
Bây giờ chúng ta có một ứng dụng Next.js và Express hoạt động cùng nhau trong một không gian làm việc.
Nx có một công cụ CLI khác cho phép chúng ta xem biểu đồ phụ thuộc của ứng dụng trong terminal run. Chạy
npx nx dep-graph
, và chúng ta sẽ thấy một màn hình tương tự như hình ảnh bên dưới, mô tả biểu đồ phụ thuộc của ứng dụng.
Các lệnh CLI khác cho Nx
-
nx list
Liệt kê các plugin Nx hiện đang được cài đặt. -
nx migrate latest
Cập nhật các gói trongpackage.json
lên phiên bản mới nhất. -
nx affected
Chỉ thực hiện hành động trên các plugin bị ảnh hưởng hoặc đã sửa đổi apps. -
nx run-many --target serve --projects todo-api,todo
Chạy lệnh target trên tất cả các dự án được liệt kê.
Kết luận
Là tổng quan chung về Nx, bài viết này đã đề cập đến những gì Nx cung cấp và cách nó giúp chúng ta làm việc dễ dàng hơn. Chúng tôi cũng đã hướng dẫn thiết lập ứng dụng Next.js trong không gian làm việc Nx, thêm plugin Express vào không gian làm việc hiện có và sử dụng tính năng monorepo để chứa nhiều ứng dụng hơn trong không gian làm việc của chúng tôi.Bạn sẽ tìm thấy mã nguồn đầy đủ trong kho lưu trữ GitHub. Để biết thêm thông tin về Nx, hãy xem tài liệu hoặc tài liệu Nx cho Next.js.
Đọc thêm
- Cách an toàn nhất để ẩn khóa API của bạn khi sử dụng React
- Kết hợp ứng dụng web và ứng dụng gốc với 4 API JavaScript không xác định
- Nhu cầu ngày càng tăng về quản lý mật khẩu hiệu quả
- Các API React hữu ích để xây dựng các thành phần linh hoạt với TypeScript