1. H5项目首屏加载痛点
A. 打包项目文件过大,加载项目时间长,用户等待时间长;
B. 首屏加载白屏,用户体验差;
2. 首屏白屏Next.js解决方案预渲染
预先为每个页面生成 HTML 文件,而不是由客户端 JavaScript 来完成。预渲染可以带来更好的性能和 SEO 效果。
预渲染的两种方式:
1. 静态生成(Static Generation)HTML 在 构建时 生成,并在每次页面请求(request)时重用;
2. 服务器端渲染(Server-side Rendering)在 每次页面请求(request)时 重新生成 HTML;
这两种方式的不同之处在于为 page(页面)生成 HTML 页面的 时机;
Next.js 允许你为每个页面 选择 预渲染的方式。你可以创建一个 “混合渲染” 的 Next.js 应用程序:对大多数页面使用“静态生成”,同时对其它页面使用“服务器端渲染”。
出于性能考虑,相对服务器端渲染,更 推荐 使用 静态生成 。 CDN 可以在没有额外配置的情况下缓存静态生成的页面以提高性能。但是,在某些情况下,服务器端渲染可能是唯一的选择。
你还可以将 客户端渲染 与静态生成或服务器端渲染一起使用。这意味着页面的某些部分可以完全由客户端 JavaScript 呈现。
2.1 静态生成(Static Generation)
什么是静态生成?
如果一个页面使用了 静态生成,在 构建时(build time) 将生成此页面对应的 HTML 文件 。这意味着在生产环境中,运行 build 时将生成该页面对应的 HTML 文件。然后,此 HTML 文件将在每个页面请求时被重用,还可以被 CDN 缓存。
什么时候应该使用静态生成?
在考虑预渲染方案前,请先考虑一个问题 我的项目可以在用户请求之前预先渲染此页面吗? 如果答案是肯定的,则应选择 静态生成;
静态生成可能导致的问题:
目前已有的一些预渲染方案,在生成HTML并在加载过程中,已经可以解决首屏白屏的问题,但因打包输出的html文件只有index.html,并且在打包的时候渲染的只是静态节点,因此在访问其他路由或在数据回流后,可能会导致闪屏的情况;
Next.js 静态生成:
前文已介绍 Next.js 的特殊性在于允许在同一个项目,不同页面不同路由下选择不同的预加载方案或者多种预加载方案混合使用;
在 Next.js 中,你可以静态生成 带有或不带有数据 的页面。接下来我们分别看看这两种情况。
2.1.1 生成不带数据的静态页面
此方案只适合于某些不依赖外部数据的页面,如:营销页面、博客文章、帮助和文档等;
如果你的页面需要显示频繁更新的数据,并且页面内容会随着每个请求而变化,那此方案不适合你;
2.1.2 需要获取数据的静态生成
某些页面需要获取外部数据以进行预渲染。有两种情况,一种或两种都可能适用;
1. 页面 内容 取决于外部数据:使用 getStaticProps ;
2. 页面 paths(路径) 取决于外部数据:使用 getStaticPaths (通常还要同时使用 getStaticProps)。
getStaticProps
Next.js 允许你从同一文件 export(导出)一个名为 getStaticProps 的async(异步)函数。该函数在构建时被调用,并允许你在预渲染时将获取的数据作为props 参数传递给页面。
getStaticProps 将在呈现页面所需的数据在用户请求之前的构建时间调用,即在打包时就已调用 getStaticProps 并将数据打包至html,因此在用户请求页面时不用等待数据,直接加载html即可;
当然单纯的使用 getStaticProps 只能在极少的场景下使用,后续还会详细介绍结合 swr 等适合多种场景使用的方式;
getStaticPaths
注意与上文 getStaticProps 的区别,Next.js 允许你创建具有 动态路由 的页面。例如,你可以创建一个名为 pages/posts/[id].js 的文件用以展示以 id 标识的单篇博客文章。当你访问 posts/1 路径时将展示 id: 1 的博客文章。
getStaticPaths 需导出 paths、fallback,该 paths 键确定哪些路径将被预呈现。例如,假设您有一个使用名为 的动态路由的页面 pages/posts/[id].js
然后 Next.js 将静态生成 posts/1 并 posts/2 在构建时使用 pages/posts/[id].js
请注意,每个值 params 必须与页面名称中使用的参数匹配:
1. 如果页面名称是 pages/posts/[postId]/[commentId],params 则应包含 postId 和 commentId。
-
如果页面名称使用包罗万象的路由,例如 pages/[...slug],params 则应包含 slugwhich 是一个数组。例如,如果此数组为 ['foo', 'bar'],则 Next.js 将静态生成位于 的页面 /foo/bar。
-
如果页面使用可选的包罗万象的路由,则供应 null、[]、undefined 或 false 来呈现最根的路由。例如,如果您提供slug: falsefor pages/[[...slug]],Next.js 将静态生成页面/。
fallback: false
如果 fallback 是 false,则任何未返回的路径 getStaticPaths 都将导致404 页面。如果要预渲染的路径数量很少,则可以执行此操作 - 因此它们都是在构建时静态生成的。当不经常添加新页面时,它也很有用。如果向数据源添加更多项并需要呈现新页面,则需要再次运行构建。
fallback: true
如果 fallback 是 true,您的应用程序有大量依赖数据的静态页面(想想:一个非常大的电子商务网站),这很有用。您想要预渲染所有产品页面,但是您的构建将花费很长时间,则可使用此种方案。
当有人请求尚未生成的页面时,用户将看到带有加载指示器的页面。不久之后,getStaticProps 完成,页面将使用请求的数据呈现。从现在开始,每个请求相同页面的人都将获得静态预渲染的页面。
fallback: blocking
如果 fallback 是 blocking ,则未返回的新路径 getStaticPaths 将等待生成 HTML,与 SSR 相同(因此为什么阻塞),然后缓存以备将来的请求使用,因此每个路径只发生一次。
2.2 服务器端渲染(Server-side Rendering)
如果 page(页面) 使用的是 服务器端渲染,则会在 每次页面请求时 重新生成页面的 HTML 。
要对 page(页面) 使用服务器端渲染,你需要 export 一个名为 getServerSideProps 的 async 函数。服务器将在每次页面请求时调用此函数。
getServerSideProps 类似于 getStaticProps,但两者的区别在于 getServerSideProps 在每次页面请求时都会运行,而在构建时不运行。
由于服务器端渲染会导致性能比“静态生成”慢,因此仅在绝对必要时才使用此功能。
getServerSideProps 仅当您需要预呈现必须在请求时获取其数据的页面时才应使用。
当你直接请求这个页面时,getServerSideProps 在请求的时候运行,这个页面会用返回的 props 进行预渲染。
左侧为服务器代码,右侧为客户端代码
2.3 SWR 用于数据请求的 React Hooks 库
Next.js 背后的团队创建了一个名为 SWR 的用于数据获取的 React 钩子。如果您在客户端获取数据,我们强烈推荐它。它处理缓存、重新验证、焦点跟踪、间隔重新获取等。你可以像这样使用它:
3. 渲染机制介绍
客户端渲染 BSR (Broswer Side Render)
客户端渲染,顾名思义就是只在浏览器上执行的渲染,通过Vue 和 React 构建的单页面应用SPA 都是采用这种方式渲染
缺点:只在浏览器上运行,缺点 SEO 不友好,白屏
静态页面生成 SSG (Static Site Generation)
优点:解决白屏问题、SEO 问题
缺点:无法生成和用户相关的内容 (所有用户请求的结果都一样)
服务端渲染 SSR (Server Side Render)
优点:解决白屏问题、SEO问题、可以生成用户相关的内容