
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,以创建一种语言,以为您的代码的性能至关重要方面,以为您提供定义关键渲染路径的工具。