Trong bài viết này, chúng ta sẽ tìm hiểu cách tối ưu hóa ứng dụng Next.js ( liên kết đến ứng dụng ) bằng cách giảm 43% kích thước gói và tăng điểm số lên 73 từ 36 trong Thông tin chi tiết về tốc độ trang của Google .
Hãy bắt đầu với việc phân tích bản dựng sản xuất của Next.js. Khi chúng tôi thực thi npm run build , Next.js cung cấp cho chúng tôi thống kê về bản dựng sản xuất. Nó chỉ định kích thước của các trang và khối sẽ được gửi tới trình duyệt.
Next.js tạo các tệp phổ biến và sẽ được chia sẻ trên các trang. Các tệp này được gọi là JS tải đầu tiên. Các tệp JS tải đầu tiên chứa mã khung và mã được nhiều trang sử dụng.
Nếu thành phần này sử dụng lại hơn 50% số tệp, thì Next.js sẽ bao gồm thành phần đó trong JS tải đầu tiên. Chúng tôi không thể thay đổi hành vi này, nhưng chúng tôi có thể tối ưu hóa mã của mình.
Sau đây là đầu ra của lệnh npm run build và điểm Google PageSpeed Insights. Như bạn có thể thấy, kích thước của các tệp có màu đỏ và vàng. Mục tiêu của chúng tôi là làm cho chúng có màu xanh.
Đi nào.
Mục lục
Chúng tôi bắt đầu bằng cách phân tích và xác định các gói có trong First Load JS. Để tìm thấy điều đó, chúng ta cần cài đặt các phụ thuộc dev sau.
npm install –save-dev @next/bundle-analyzer cross-env |
Sau khi cài đặt, hãy thêm đoạn mã sau vào package.json bên dưới scripts .
"scripts" : { "analyze" : "cross-env ANALYZE=true next build" , "analyze:server" : "cross-env BUNDLE_ANALYZE=server next build" , "analyze:browser" : "cross-env BUNDLE_ANALYZE=browser bản dựng tiếp theo" },
Thêm đoạn mã sau vào next.config.js. Nếu bạn không có tệp này, thì hãy tạo nó trong thư mục gốc của dự án của bạn.
const withBundleAnalyzer = yêu cầu ( '@next/bundle-analyzer' )({ enable : process . env . ANALYZE === 'true' }) mô-đun . export = withBundleAnalyzer ({ env : { NEXT_PUBLIC_ENV : 'PRODUCTION' , //cấu hình tiếp theo của bạn ở đây }, })
Tiếp theo, thực hiện lệnh này npm run analytics , lệnh này sẽ mở hai tab mới trong trình duyệt của bạn bằng các biểu đồ. Tập trung vào biểu đồ client.html .
Sau đó, thay thế các thư viện lớn hơn bằng các thư viện nhỏ hơn, tương đương và xóa các thư viện không liên quan. Để thay thế bất kỳ thư viện nào, hãy truy cập https://bundlephobia.com/ , xem kích thước thư viện của bạn và kiểm tra xem bạn có bất kỳ lựa chọn thay thế nào với kích thước nhỏ hơn không. Nếu không, hãy thử viết mã tùy chỉnh của riêng bạn. Trong bản trình diễn này:
xuất chức năng không đồng bộ getServerSideProps ( ngữ cảnh ) { const moment = ( đang chờ nhập ( 'khoảnh khắc' )). mặc định (); // phương pháp mặc định là truy cập xuất khẩu mặc định return { date : moment . định dạng ( 'dddd D MMMM YYYY' ), } }
Bây giờ ngày này sẽ được gửi dưới dạng chỗ dựa cho thành phần, có thể được sử dụng (getServerSideProps chỉ có thể được sử dụng trong các trang không nằm trong thành phần) . Bây giờ, momentjs sẽ không được gửi tới trình duyệt.
Các thành phần không hiển thị trong lần tải đầu tiên của trang và các thành phần được hiển thị dựa trên các điều kiện nhất định phải được nhập động thay vì thông thường. Điều này đảm bảo rằng các thành phần này chỉ được gửi đến trình duyệt khi cần thiết. Tham khảo ví dụ mã sau đây.
nhập động từ 'tiếp theo/động' const Modal = dynamic (() => import ( '../components/header' )); xuất hàm mặc định Home () { return ( { showModal && < Modal />} ) }
Mở tab Mạng. Khi điều kiện được đáp ứng, bạn sẽ thấy một yêu cầu mạng mới được thực hiện để tìm nạp thành phần động (nhấp vào nút để mở phương thức).
Next.js có một thành phần tích hợp có tên next/image . Nó chỉ tải hình ảnh khi chúng ở trong chế độ xem.
nhập Hình ảnh từ "tiếp theo/hình ảnh" ; const Index = () => { return ( <> <p> Tên miền bên ngoài phải được định cấu hình trong < Code > next . config . js </ Code > bằng thuộc tính < Code > tên miền </ Code > . < / p > < Hình ảnh alt = "Logo Next.js" src = "https://assets.vercel.com/image/upload/v1538361091/repositories/next-js/next-js-bg.png" width ={ 1200 } height ={ 400 } /> </> ); };
Tập lệnh Google Ads thường chặn chuỗi chính, vì vậy chúng tôi sẽ tải tập lệnh tám giây sau khi tải trang. Ban đầu, chúng tôi sử dụng gói react-gpt để tải tập lệnh Google Ads. Chúng tôi sẽ thay thế điều đó bằng mã tùy chỉnh được tối ưu hóa của chúng tôi.
Đối với điều này, chúng tôi đã tạo một hook tùy chỉnh để chèn bất kỳ tập lệnh nào. Nó sẽ trả về trạng thái tùy thuộc vào trạng thái tiêm khi tập lệnh Google Ads được đưa vào. Khi nó sẵn sàng trở lại , chúng tôi sẽ chạy mã Quảng cáo.
nhập Phản ứng từ "phản ứng" ; const useScript = ( src , delay = null ) => { const [ status , setStatus ] = React . useState ( src ? "đang tải" : "nhàn rỗi" ); Phản ứng . useEffect (() => { if (! src ) { setStatus ( "idle" ); return "idle" ; } hãy để tập lệnh = tài liệu . querySelector ( `script[src="${src}"]` ); để hết thời gian = null ; if (! script ) { if ( delay ) { timeout = setTimeout (() => { injectScript (); // Thêm trình xử lý sự kiện sau khi script được thêm script . addEventListener ( "load" , setStateStatus ); script . addEventListener ( " lỗi" , setStateStatus ); }, chậm trễ ); } khác { tiêmScript (); } } other { setStatus ( script . getAttribute ( "data-status" )); } const setStateStatus = ( event ) => { setStatus ( event . type === "load" ? "ready" : "error" ); }; // mã để tiêm script function injectScript () { script = document . createElement ( "tập lệnh" ); kịch bản . src = src ; kịch bản . không đồng bộ = đúng ; kịch bản . setAttribute ( "trạng thái dữ liệu" , "đang tải" ); tài liệu . cơ thể . appendChild ( tập lệnh ); const setDataStatus = ( sự kiện ) => { tập lệnh . setAttribute ( "data-status" , event . type === "load" ? "ready" : "error" ); }; kịch bản . addEventListener ( "tải" , setDataStatus ); kịch bản . addEventListener ( "lỗi" , setDataStatus ); } if ( script ) { //script sẽ không được xác định có sẵn khi nó bị trì hoãn do đó hãy kiểm tra nó trước khi thêm tập lệnh nghe . addEventListener ( "tải" , setStateStatus ); kịch bản . addEventListener ( "lỗi" , setStateStatus ); } return () => { if ( script ) { script . removeEventListener ( "tải" , setStateStatus ); kịch bản . removeEventListener ( "lỗi" , setStateStatus ); } nếu ( hết thời gian ) { clearTimeout ( hết thời gian ); } }; }, [ src ]); trả lại trạng thái ; }; xuất useScript mặc định ;
Sử dụng hook này trong pages/index.js .
const MyApp = () => { const status = useScript ( script , 8000 ); trả về ( <> <p> Trạng thái chính : { trạng thái }</ p > { trạng thái === ' nhàn rỗi ' && < Quảng cáo />} </> ); };
Nếu bạn muốn tạo một thành phần quảng cáo tùy chỉnh như thế này thì hãy làm theo bài viết này .
Bạn cũng có thể lười tải các tập lệnh khác như tập lệnh Google Analytics.
Nếu bạn đang sử dụng các thư viện như lodash và date-fn , chúng ta có thể dễ dàng giảm kích thước gói bằng cách chỉ nhập các chức năng cụ thể thay vì nhập đầy đủ, như thế này.
// Nhập cũ _get từ ' lodash ' // Nhập mới _get từ ' lodash / get '
Chúng tôi có thể tối ưu hóa việc sử dụng nhiều thư viện khác. Để biết thêm chi tiết, hãy xem bài viết này . Đừng quên xóa các mục nhập không sử dụng khỏi dự án.
Nếu bạn đang sử dụng next/link trong dự án của mình, hãy thêm chỗ dựa tìm nạp trước vào nó và đặt thành false. Next.js theo mặc định tìm nạp trước các trang có liên kết trong chế độ xem. Giả sử bạn có một tiêu đề với hai liên kết ‘/home’ và ‘/about’ . Ngay cả khi người dùng đang ở trên trang chủ, nội dung của trang giới thiệu cũng sẽ được tải vì liên kết giới thiệu có thể được nhìn thấy trong chế độ xem.
Khi tìm nạp trước được đặt thành false , quá trình tìm nạp trước sẽ vẫn diễn ra nhưng chỉ khi liên kết được di chuột qua.
<li> <Link href = "/about" prefetch = {false} > <a> Giới thiệu về chúng tôi </a> </Link> </li> <li> <Link href = "/blog/hello-world" prefetch = {false} > > <a> Bài đăng blog </a> </Link> </li>
Khi chúng tôi sử dụng các thư viện biểu tượng như font-awesome , chúng tôi chỉ sử dụng tối đa 15 biểu tượng nhưng toàn bộ thư viện đã được tải. Vấn đề là nó là tài nguyên chặn hiển thị. Vì vậy, thay vì tải toàn bộ thư viện, bạn chỉ cần tải xuống các biểu tượng cần thiết dưới dạng tệp SVG và sử dụng chúng. Bạn cũng có thể lười tải những hình ảnh SVG này.
Bạn cũng có thể sử dụng font-display: swap; cho phông chữ của bạn vì nó không chặn kết xuất. Thay vào đó, mặt phông chữ được cung cấp một khoảng thời gian hoán đổi vô hạn và một khoảng thời gian khối tối thiểu.
@ phông chữ - mặt { phông chữ - gia đình : Ví dụFont ; src : url ( /path/ đến / fonts / examplefont . woff ) định dạng ( 'woff' ), url ( /path/ đến / fonts / examplefont . eot ) định dạng ( 'eot' ); phông chữ - trọng lượng : 400 ; kiểu chữ _ : bình thường ; phông chữ - hiển thị : trao đổi ; }
Nếu bạn đang sử dụng Google Fonts trực tiếp từ liên kết, thì hãy tải xuống phông chữ và tự lưu trữ chúng.
Chúng tôi cũng chỉ có thể tải một thành phần khi nó ở trong chế độ xem bằng cách sử dụng thư viện react-lazyload , thư viện này cũng hỗ trợ SSR. Chúng tôi cũng có thể cung cấp phần bù, vì vậy người dùng sẽ không biết về hành vi tải chậm này.
nhập LazyLoad từ 'Reac-lazyload' ; < LazyLoad offset ={ 100 }> < Footer /> </ LazyLoad >
Như tôi đã thảo luận trước đó, các thư viện được thêm vào First Load JS. Trong dự án của chúng tôi, chúng tôi đang sử dụng thư viện Biểu đồ đồng bộ hóa trên nhiều trang, do đó, thư viện biểu đồ đồng bộ hóa được gộp vào lần tải đầu tiên.
Các trang không sử dụng biểu đồ Đồng bộ hóa cũng đang tải thư viện biểu đồ Đồng bộ hóa , vì nó đã được thêm vào First Load JS hoặc gói chính. Để tối ưu hóa nó, chúng tôi đã theo dõi bài viết tuyệt vời này của Robert S về cách loại trừ các thư viện lớn .
Nguồn: https://www.syncfusion.com/blogs/post/optimize-next-js-app-bundle-improve-its-performance.aspx
Những tiến bộ nhanh chóng trong công nghệ đã tác động đáng kể đến xu hướng thiết kế trang web […]
Trong thế giới thương mại điện tử không ngừng phát triển, việc đi trước đón đầu là rất quan trọng. […]
Công ty công nghệ BEIT là một trong những doanh nghiệp tiên phong trong lĩnh vực công nghệ thông tin […]
Đối với người dùng không chuyên, việc tạo hình ảnh bắt mắt từng là một thách thức. Giờ đây, các […]
Cách cải thiện SEO cho trang web của bạn, tăng thứ hạng tìm kiếm và tăng mức độ tương tác […]
Mục lục1 1. Khám phá các tùy chọn Elementor1.1 Cài đặt phần tử1.2 Những Widget nào được bao gồm?2 2. […]