
Next.js的部分水合。
說明:在春季,我們正在為報紙創建網站,並且非常非常出色。
報紙主要是靜態頁面。現在,如果我們要創建一個單一頁應用程序,我們將創建一個大多數不必要的代碼的巨大捆綁包。
這不僅意味著用戶等待大文件下載,而且正如Addy Osmami指出的那樣,通過解析和執行代碼,性能成本巨大。作為一個模糊的經驗法則,我們可以說,您的捆綁包越大,您的性能就越好。
這就是為什麼我們僅通過在客戶端中實際需要的代碼來削減捆綁包的原因,然後將其餘的代碼留給服務器端渲染。
此存儲庫仍然是概念證明,我們將繼續致力於這一工作,並將我們的工作作為2個軟件包實施:
pool-attendant-preact一個庫,該庫用preaxct x實現了副本的水合xnext-super-performance a next.js插件,該插件使用pool-artendant-preacct來提高客戶端性能除了部分水合外,我們還將實施加載策略,包括critical CSS , critical JS , lazy loading , preloading ressources等。
目前,我們有一個部分水合POC。創建next.config.js並使用我們的插件時
const withSuperPerformance = require ( "next-super-performance" ) ;
module . exports = withSuperPerformance ( ) ;2件事將發生:
React將被Preact替換,因為它只有3KB這意味著您必須在應用程序的根文件夾中創建client.js ,該文件將充當發送給客戶端的JavaScript的入口點。我們這樣做是為了使您完全控制您希望用戶下載的內容,並且非常重要的是,選擇適合您的加載策略。
現在, pool-attendant-preact發揮作用。為您提供3個API:
withHydration一個事件,使您可以標記水合的成分hydrate以保濕客戶中標記的成分HydrationData為客戶寫序列化道具的組件,例如NEXT_DATA 
讓我們以身作則解釋。假設您有一個header , main部分和teaser片的應用程序(例如,可能是帶有文本和標題的圖像)。為了這個示例,讓我們嘗試使預告片2和3動態(只是在頁面上選擇一些項目),然後將其餘的靜態留下。
這是您將如何做的:
安裝下一步的績效
npm i next-super-performance --save創建next.config.js並使用插件
const withSuperPerformance = require ( "next-super-performance" ) ;
module . exports = withSuperPerformance ( ) ;修改您的package.json以正確使用profeact(這將使別名對preact react ,然後在不修改的情況下啟動原始下一個腳本):
"scripts" : {
"dev" : "next:performance dev" ,
"start" : "next:performance start" ,
"build" : "next:performance build"
} ,創建pages/index.js
import Header from "../components/header" ;
import Main from "../components/main" ;
import { HydrationData } from "next-super-performance" ;
export default function Home ( ) {
return (
< section >
< Header />
< Main />
< HydrationData />
</ section >
) ;
}這裡的重要部分是<HydrationData /> ,它將插入類似的內容:
< script type =" application/hydration-data " >
{ "1" : { "name" : "Teaser" , "props" : { "column" : 2 } } , "2" : { "name" : "Teaser" , "props" : { "column" : 3 } } }
</ script >這些是要水合的組件的名稱和道具。
告訴您的應用程序,特定的組件應withHydration水合使用。我們的main.js看起來像這樣:
import Teaser from "./teaser" ;
import { withHydration } from "next-super-performance" ;
const HydratedTeaser = withHydration ( Teaser ) ;
export default function Body ( ) {
return (
< main >
< Teaser column = { 1 } />
< HydratedTeaser column = { 2 } />
< HydratedTeaser column = { 3 } />
< Teaser column = { 1 } />
< Teaser column = { 2 } />
< Teaser column = { 3 } />
< Teaser column = { 1 } />
< Teaser column = { 2 } />
< Teaser column = { 3 } />
</ main >
) ;
}在第4行中,我們創建了一個將在客戶端中進行水合的組件,並在頁面上使用不同的道具使用了兩次。
withHydration將用標記預備您的組件,以便可以在服務器上渲染並在客戶端上的HTML中找到。所以<HydratedTeaser column={2} />將變成
< Fragment >
< script type = "application/hydration-marker" />
< Teaser column = { 2 } />
</ Fragment >最後也是最關鍵的部分是您的client.js ,它是將運送給用戶的代碼,以及您可以在其中補充組件的地方。對於單個組件( Teaser ),這可能很簡單。
import { hydrate } from "next-super-performance" ;
import Teaser from "./components/teaser" ;
hydrate ( [ Teaser ] ) ;哦, next-super-performance帶有pool-attendant-preact這就是為什麼您會從這裡導入所有內容,而不是從pool-attendant-preact導入所有內容的原因。為了方便起見,它只是withHydration , hydrate和HydrationData進口和出口。
hydrate將找到您使用withHydration標記的組件,並使用<HydrationData />的數據將其與已傳遞給它們的組件作為陣列進行水合。
這將需要您導入要在客戶端中使用的組件(並將其傳遞到hydrate功能)。因為client.js是所有客戶端代碼的入口點,所以這也意味著您將看到並確切地控制發送給用戶的代碼。除了預先反應,其他任何東西都不會發貨。
如果您的組件具有自己的依賴關係,那麼這些依賴項也將“納圖爾”發貨,因為client.js是您的條目,並且每個依賴性都將通過webpack解決。
此存儲庫是POC,我們將建立一些東西。要嘗試一下,請克隆此存儲庫,然後運行
# Init Preact Git Sumodule
git submodule init
git submodule update
# Install dependencies
yarn
# Build Preact
cd packages/preact
yarn build
# Build the pool-attendant-preact package
# └─ cd to the pool-attendant-preact dir
cd ...
cd packages/pool-attendant-preact
# └─ build the package
yarn build
# cd to the app dir
cd ...
cd packages/app
# run the app
yarn dev該POC似乎運行良好,我們可以大大降低捆綁包的尺寸。雖然還有很多事情要做。 Next.js仍然捆綁代碼,我們不想在客戶端(例如core-js )中看到。另外,我們旨在實施工具和API,以創建一種語言,以為您的代碼的性能至關重要方面,以為您提供定義關鍵渲染路徑的工具。