Tách mã bằng tính năng nhập động trong Next.js

Cách tăng tốc ứng dụng Next.js bằng chiến lược chia tách mã và tải thông minh.

Bạn sẽ học được gì?

Bài đăng này giải thích các loại và cách sử dụng nhập động để tăng tốc ứng dụng Next.js của bạn.

Phân tách mã dựa trên tuyến và phân tách mã dựa trên thành phần

Theo mặc định, Next.js chia JavaScript của bạn thành các phần riêng biệt cho mỗi tuyến. Khi người dùng tải ứng dụng của bạn, Next.js chỉ gửi mã cần thiết cho tuyến đường ban đầu của bạn. Khi người dùng di chuyển trong ứng dụng, họ sẽ tìm nạp các phần dữ liệu được liên kết với các tuyến khác. Việc phân tách mã dựa trên tuyến đường sẽ giảm thiểu tập lệnh cần được phân tích cú pháp và biên dịch cùng một lúc, dẫn đến việc giúp rút ngắn thời gian tải trang.

Mặc dù tách mã dựa trên tuyến là chế độ mặc định tốt, nhưng bạn có thể tối ưu hoá hơn nữa quá trình tải với tính năng chia tách mã ở cấp thành phần. Nếu bạn có số tài khoản trong ứng dụng, bạn nên chia chúng thành các phần riêng biệt. Bằng cách đó, mọi thành phần lớn không quan trọng hoặc chỉ hiển thị trên lượt tương tác của người dùng (như việc nhấp vào một nút) có thể được tải từng phần.

Next.js hỗ trợ import() động, cho phép bạn nhập các mô-đun JavaScript (bao gồm cả các thành phần React) một cách linh động và tải mỗi lần nhập dưới dạng một phân đoạn riêng biệt. Điều này mang lại cho bạn tách mã cấp thành phần và cho phép bạn kiểm soát việc tải tài nguyên để rằng người dùng chỉ tải mã họ cần xuống cho phần trang web mà họ đang xem. Trong Next.js, các thành phần này được hiển thị phía máy chủ (SSR) theo mặc định.

Tính năng nhập linh động trong thực tế

Bài đăng này bao gồm một số phiên bản của ứng dụng mẫu có một có một nút. Khi nhấp vào nút, bạn sẽ thấy một chú cún dễ thương. Như khi di chuyển qua từng phiên bản ứng dụng, bạn sẽ thấy tính năng nhập động khác với trạng thái tĩnh dữ liệu nhập và cách làm việc với chúng.

Trong phiên bản đầu tiên của ứng dụng, chú chó con sống trong components/Puppy.js. Người nhận hiển thị chú chó con trên trang, ứng dụng này sẽ nhập thành phần Puppy trong index.js với câu lệnh nhập tĩnh:

import Puppy from "../components/Puppy";

Để xem cách Next.js gói ứng dụng, hãy kiểm tra dấu vết mạng trong Công cụ cho nhà phát triển:

  1. Để xem trước trang web, hãy nhấn vào Xem ứng dụng. Sau đó nhấn Toàn màn hình toàn màn hình.

  2. Nhấn tổ hợp phím "Control + Shift + J" (hoặc "Command+Option+J" trên máy Mac) để mở Công cụ cho nhà phát triển.

  3. Nhấp vào thẻ Mạng.

  4. Chọn hộp kiểm Tắt bộ nhớ đệm.

  5. Tải lại trang.

Khi bạn tải trang, tất cả các mã cần thiết, bao gồm cả Puppy.js thành phần, được nhóm trong index.js:

Thẻ Mạng Công cụ cho nhà phát triển cho thấy 6 tệp JavaScript: index.js, app.js, webpack.js, main.js, 0.js và tệp dll (thư viện đường liên kết động).

Khi bạn nhấn nút Nhấp vào tôi, chỉ yêu cầu về tệp JPEG của cún con mới được đã thêm vào thẻ Mạng:

Thẻ Mạng Công cụ cho nhà phát triển sau khi nhấp vào nút, cho thấy 6 tệp JavaScript giống nhau và một hình ảnh.

Nhược điểm của phương pháp này là ngay cả khi người dùng không nhấp vào nút để thấy chú chó con, họ phải tải thành phần Puppy vì nó có trong index.js Trong ví dụ nhỏ này, đó không phải là vấn đề lớn, nhưng trong thế giới thực thì việc chỉ tải các thành phần lớn thường là một cải tiến đáng kể khi nếu cần.

Bây giờ, hãy xem phiên bản thứ hai của ứng dụng, trong đó tính năng nhập tĩnh được thay thế bằng tính năng nhập động. Next.js bao gồm next/dynamic, giúp tệp này có thể sử dụng tính năng nhập động cho bất kỳ thành phần nào trong Next:

import Puppy from "../components/Puppy";
import dynamic from "next/dynamic";

// ...

const Puppy = dynamic(import("../components/Puppy"));

Làm theo các bước từ ví dụ đầu tiên để kiểm tra dấu vết mạng.

Khi bạn tải ứng dụng lần đầu tiên, chỉ index.js được tải xuống. Lần này Nhỏ hơn 0,5 KB (giảm từ 37,9 KB xuống còn 37,4 KB) vì kích thước này không bao gồm mã cho thành phần Puppy:

Mạng Công cụ cho nhà phát triển hiển thị 6 tệp JavaScript giống nhau, ngoại trừindex.js hiện có kích thước nhỏ hơn 0,5 KB.

Thành phần Puppy hiện nằm trong một phân đoạn riêng biệt, 1.js, chỉ được tải khi bạn nhấn nút:

Thẻ Mạng Công cụ cho nhà phát triển sau khi nhấp vào nút, cho thấy tệp 1.js bổ sung và hình ảnh được thêm vào cuối danh sách tệp.

Trong ứng dụng thực tế, các thành phần thường rất nhiều lớn hơn và tải từng phần các tệp đó có thể cắt bớt tải trọng JavaScript ban đầu của bạn xuống hàng trăm kilobyte.

Các lệnh nhập động với chỉ báo tải tuỳ chỉnh

Khi tải từng phần tài nguyên, bạn nên cung cấp một chỉ báo tải nếu có chậm trễ. Trong Next.js, bạn có thể làm điều đó bằng cách cung cấp một đối số bổ sung cho hàm dynamic():

const Puppy = dynamic(() => import("../components/Puppy"), {
  loading: () => <p>Loading...</p>
});

Để xem chỉ báo đang tải trong thực tế, hãy mô phỏng kết nối mạng chậm trong Công cụ cho nhà phát triển:

  1. Để xem trước trang web, hãy nhấn vào Xem ứng dụng. Sau đó nhấn Toàn màn hình toàn màn hình.

  2. Nhấn tổ hợp phím "Control + Shift + J" (hoặc "Command+Option+J" trên máy Mac) để mở Công cụ cho nhà phát triển.

  3. Nhấp vào thẻ Mạng.

  4. Chọn hộp kiểm Tắt bộ nhớ đệm.

  5. Trong danh sách thả xuống Điều tiết, chọn 3G nhanh.

  6. Nhấn vào nút Nhấp vào đây.

Bây giờ, khi bạn nhấp vào nút này, hệ thống sẽ mất chút thời gian để tải thành phần và ứng dụng hiển thị thông báo "Đang tải..." trong thời gian chờ đợi.

Màn hình tối có văn bản

Nhập động không có SSR

Nếu bạn chỉ cần hiển thị một thành phần ở phía máy khách (ví dụ: ) bạn có thể làm điều đó bằng cách đặt tuỳ chọn ssr thành false:

const Puppy = dynamic(() => import("../components/Puppy"), {
  ssr: false,
});

Kết luận

Với tính năng hỗ trợ nhập động, Next.js cung cấp cho bạn mã cấp thành phần chế độ này có thể giảm thiểu tải trọng JavaScript và cải thiện ứng dụng thời gian tải. Theo mặc định, tất cả các thành phần đều do máy chủ hiển thị và bạn có thể hãy tắt tuỳ chọn này bất cứ khi nào cần thiết.