Next.js 9.3 版本後,官方释出了两个新的 API 分别为 getStaticProps
与 getServerSideProps
,这两个 API 可以被使用在 SSG 与 SSR 两种不同的策略上,如果不熟 SSG 与 SSR 可以参考之前写过的文章。
官方文件中也写道,如果使用的是 Next.js 9.3 版本之後,推荐使用上述的两个 API,而不要使用 getInitialProps
。
今天,我们要来了解,为什麽官方不推荐使用 getInitialProps
,使用 getInitialProps
会早成什麽问题。
在 Next.js 9.0 版本後释出了 Automatic Static Optimization 这个功能,这项功能对於工程师来说是一大福音,如同这项功能的名字,在不加上 getServerSideProps
或 getInitialProps
的 component 中,Next.js 会自动分析该 component 成为 SSG 的一员,也就是说 component 可以走 SSG 生成静态的 HTML 档案。
但是,如果加上了 getInitialProps
就会失去 SSG 的优势。
getInitialProps
将会使整个专案失去 Automatic Static Optimization在一般的情况下 getInitialProps
可以帮我们得到 SSR 的各种好处,让服务器可以事先执行呼叫 API 获得资料的流程,然後回传已经渲染完资料的 HTML 给用户端。
但是有一个情况要注意的是在 _app.js
中可以设定 getInitialProps
为全域的 component 获得 SSR 的好处,但同时也会让整个专案失去 Automatic Static Optimization 的功能,如果这不是期望的行为,则不要在 _app.js
中使用 getInitialProps
。
getInitialProps
可能会造成更大的 bundle sizegetInitialProps
与 getServerSideProps
乍看之下很相似,都是让一个页面拥有 SSR 的功能,而它们不一样的地方在於 getInitialProps
会把程序码带到用户端,在服务器端与用户端都会执行 getInitialProps
的程序码;而 getServerSideProps
仅会在服务器端执行,因此在打包时也会让 bundle size 更小一些。
在官方文件中也特别提到一段使用 getInitialProps
要注意的事项:「If you are using server-side only modules inside getInitialProps, make sure to import them properly, otherwise it'll slow down your app」,看起来有点妙,究竟是什麽样的问题会让 Next.js 的速度变慢。
以上是在「SSR and Server Only Modules」这篇文章中引用的一张图,这篇 twitter 贴文提到 50 行的 JS 程序码却造成 1.2MB 的 bundle size,听起来超级不合理。
我们要知道的事情是 getInitialProps
会在用户端跟服务器端执行,在 next build
时会把 getInitialProps
中的程序码也会一起被打包进去。
所以尽管在 getInitialProps
中撰写 if-else
判断有些只在服务器端执行的程序码,但是最後仍然会打包近 bundle 中。
接着,我们来看一个范例简单的范例,在一个新建立的专案中修改 pages/index.tsx
的程序码。
以下的 getInitialProps
用 if (req)
判断要在服务器端还是在用户端执行,我们预期在服务器端才会用到 faker
这个 module,所以在 if
里面才用 require
的方式引入这个 module,尽管 faker
只会在服务器端用到,但实际上 faker
仍然会被打包到 bundle 中。
import { NextPageContext } from "next";
import Link from "next/link";
interface HomeProps {
name: string;
}
export default function Home({ name }: HomeProps) {
return (
<div>
<h1>Home Page</h1>
<p>Welcome, {name}</p>
<div>
<Link href="/about">
<a>About Page</a>
</Link>
</div>
</div>
);
}
Home.getInitialProps = async ({ req }: NextPageContext) => {
if (req) {
// 只在服务器端执行
const faker = require("faker");
const name = faker.name.findName();
return { name };
}
// 只在用户端执行
return { name: "Lawrence" };
};
在 next build
时我们可以看到打包後的 bundle size,很奇怪的是 /
这个页面对应的是 pages/index.tsx
也就上方的范例程序,虽然只有 30 行左右,但是档案大小却高达 541KB,让人怀疑 next build
是不是没有写好。
在 pages/index.tsx
比较奇怪的点是 require('faker')
这段程序码,但是口说无凭,我们用 webpack bundle analyzer 确认这个问题发生在哪里。
参考官方 GitHub 范例 analyze-bundles
从以下的图中可以知道尽管 faker
只在服务器端执行,但是最後仍然会被 webpack 打包,这样的情况不是我们想要的。
此外,再从 Chrome 的 Network 中看到,只有几个字的页面,却需要 1.1MB 的网路传输量。
因此可以得知,在使用 getInitialProps
的同时,还必须注意使用 require
的方式引入 module 会导致 bundle size 变大,让网页的载入速度变慢,进而让使用者体验不好。
在这篇文章中,我们了解使用 getInitialProps
可能会遇到的三个问题,包含会失去 Automatic Static Optimization 的优势,以及可能会让 bundle size 变大的问题。
但是如果想要让全域的 component 共用 SSR 的程序码,那麽唯一的方法是使用较为古老的 getInitialProps
,因为目前在 _app.js
中不支援 getStaticProps
与 getServerSIdeProps
,但是如果用了 getInitialProps
会有一个很大的缺点会让整个专案失去 Automatic Static Optimization,所以现阶段就看怎麽取舍了。
<<: 【心得】我就是要跟别人不一样!!List 清单样式变变变~
前言 有了资料後,就要进行分析,因此需要做出图表比较适合观察,所以我们现在来做图罗! 本日程序码使用...
Redis.config EVENT NOTIFICATION notify-keyspace-ev...
我开始怀疑观看人数了,我觉得我猜得好不准ㄛ。我觉得会比较少人看得竟然会蛮多人看得@@ 太扯了太扯 我...
今天要把上一篇讲的hash map写成code! struct type Node struct {...
上一篇我们的基因体时代-AI, Data和生物资讯 Day02- 机器学习在生物资讯中之应用介绍了机...