Next.js 介紹
Next.js 是一個基於 React 的網站(全端)開發框架。它提供了許多內建元件和方法,幫助你優化圖片、動態設定 metadata、實現 lazy loading 以及生成效能報告等。不僅如此,Next.js 還提供了非常方便的開發環境,支持 Server Components 和 Client Components 的整合。另外,我個人也非常喜歡 Next.js 框架下的 Middleware 功能。它可以讓你在請求完成之前先運行程式碼。所以你可以根據 request 來修改請求內容、重新導轉或修改 header。這在做權限管理的時候非常好用。並且如果你是部署在 Vercel 上,Middleware 是會直接運行在 Edge Runtime。它提供網站使用者非常低延遲的運行環境,來執行 Web APIs (做權限管理非常好用)。但如果是用其他平台的部署服務就要自己設定了。
那讓我們正式開始介紹 Next.js 提供的服務吧!。:.゚ヽ(*´∀`)ノ゚.:。
Client-side navigation
Client-side navigation 代表頁面的轉換是透過 JavaScript 來實現的,而不是 HTML 的 <a>
Tag。 而使用 Next.js 提供的 <Link>
component,可以輕易實現這一點。這有以下幾個好處:
- 網站的狀態可以被保留:因為 user 並沒有真的透過 url 去再請求一次網站內容(整個 HTML)
- 使用者體驗好:不會有 page reload 的閃爍,使用者會感覺換頁更加絲滑快速
讓我們來驗證一下唄~ 這是我跟著官方教學做的一個 Next.js 網站: 可以用底下帳號登入:
Email: user@nextmail.com
Password: 123456
-
使用瀏覽器的開發者工具將
<html>
的背景 CSS 屬性變更為黃色。- 如果你是 Mac 的使用者,在 Chrome 中,按下
command + option + i
打開開發者工具,然後在Elements
頁籤中找到<html>
元素,然後點一下它,之後在下方面板的頁籤中點選Styles
,並新增background
為yellow
的 CSS 屬性。 - 如果你是 Windows 的使用者,可以自己 Google 一下怎麼打開開發者工具。👍 (應該是 F12 啦…)
- 如果你是 Mac 的使用者,在 Chrome 中,按下
-
然後自己切換頁面試試看,你會發現即便你看到 url 不斷改變但背景色一直都是黃色。這表示你的頁面轉導是透過 JavaScript 來實現的,沒有重新跟 web server 要一個全新的 html 檔案。
Code splitting and prefetching
Next.js 會自動進行 code splitting。這代表你的網站首頁能夠更快速的載入。因爲你不用一次載入整個網站需要的資料。但更舒服的是他是自動的!你甚至不需要做任何設定來實現這個功能。而使用 code splitting 的策略也代表即便你的一個頁面發生 error,你其他頁面還是可以順利運作,不會整個網站 crash 掉。更誇張的是,在 production mode 下,如果你有用 <Link>
元件,Next.js 會自動在背景預先載入你這個頁面用 <Link>
實現連結的頁面資料。這讓使用者點擊其他頁面了連結時,可以幾乎不用等待。
React 官網就是用 Next.js 開發的,所以用它來當範例,偷偷觀察一下是否真的有實現 Code splitting 和 Prefetching。 執行步驟如下:
- 打開開發者工具
- 按下 network 頁籤
- 點擊左上方 🚫 (chrome 是灰色)來清除所有 network log。然後 hot reload (mac 是
command + shift + R
) 一下。你可能會問,那 windows 呢?你再自己 Google 一下,感恩 (☉д⊙)! - 找到 Thinking in React 這個頁面的頁面資料,然後點擊它,找到看起來像頁面內容的文字,然後複製它
- 換到 Thinking in React 這個頁面,按下
command + F
,並在 search bar 貼上剛剛那段文字
這時你會發現,這個頁面有包含這段文字。但這段文字,是我們在上一個頁面的 network log 中找到的。所以我們就可以知道 Next.js 有幫我們做到根據 page 分割資料和預先載入其它 page 的資料。
Image Component
如果你是有經驗的網站開發者一定知道,圖片在網站中的處理滿麻煩的。這裡歸納 4 個顯示圖片會遇到的開發難點:
- 圖片載入總是比其它內容慢,所以容易有 layout shift 的問題。但若發生 layout shift 是會影響 SEO 的排名,所以必須解決。
- 圖片檔案太大了,沒有進行壓縮或根據使用者的裝置或 viewpoint 進行圖片 size 的優化
- 圖片在 UI 上的顯示無法符合預期。例如
- 圖片無法用相同比例根據裝置大小進行縮放
- 圖片畫面扭曲
- 圖片載入通常較久,若不想造成 layout shift,需要加入圖片的 placeholder。但這在設計上也是一個麻煩的事情,你會需要額外處理或使用第三方付費工具
所以 Next.js 提供了一個非常方便的 built-in 元件 <Image>
。來幫助開發者解決以上的問題,網路上的各種強者(我也好想當強者 ಥ_ಥ)介紹 <Image>
的時候都讚不絕口。我曾經聽過一句話:好的工程師能提升用戶體驗(UX),但厲害的工程師,能夠提升開發者體驗(DX)。真的是完全認同啊!
我們同樣用開發者工具來觀察一下到底 Next.js 針對圖片的優化搞了啥吧~你也可以直接看官方的文件 => 真是一個好東西,極度推薦!(𓁹‿ 𓁹) ✧
- 這張圖片是用一般的 HTML
<img>
tag,來載入的
- 這張圖片是用 Next.js 的
<Image>
元件,來載入的
- 在這個網頁打開開發者工具,並點選 network 頁籤。然後點擊左上方 🚫 (chrome 是灰色)來清除所有 network log。然後 hot reload
<img>
tag 載入的圖片大小是 250kb,而用 Next.js 的 <Image>
元件載入的圖片大小是 7.1kb。但這裡有一個要注意的點!如果你想享有自動最佳化圖片的功能,你必須將網站部署在 Vercel 上。而 Vercel
就是維護 Next.js 開源專案
的公司。我愛我的公司,但能去 Vercel 看一下就好了。
- 如果來源圖片是 local image (會跟著專案一起 build 的圖片)。你可以透過
<Image>
的 blur 的 attribute 讓圖片在完全載入之前先顯示該圖片的模糊版本。這可以大大的優化使用者體驗
當然你也可以自己設計出這樣的效果,透過先準備模糊圖片(低解析度並帶有模糊效果的圖片),在圖片位置優先顯示,然後再透過 JavaScript 監聽圖片是否下載完全,一但下載完全就換上原圖片。累真的累!在 Next.js 卻只要一行,這種 DX 體驗簡直舒服到不行 (◍•ᴗ•◍)。
Pre-rendering
預設情況下,Next.js 預先渲染每個頁面。這意味著 Next.js 提前為每個頁面產生 HTML,而不是由客戶端(browser 裡)的 JavaScript 完成這一切。這種做法可以有效的提升 SEO 的排名。不過我們晚一點再解釋這件事。
我們先來了解一下,啊你說提前是什麼意思啊!?能不能講明確一點呢?是不是在唬我!
其實就是在 build 專案和使用者向 web server 請求頁面時。這分別對應了 Next.js 裡面的兩種渲染模式:SSG(Static Site Generation) 和 SSR(Server-side Rendering)。 但打個商量唄,已附上連結了,咱們就點到為止,自己看好唄~不然真的要寫一個禮拜了。 ༼ ༎ຶ ෴ ༎ຶ༽
我在 Next.js 官方文件中有看到這兩張圖,我覺得解釋的很清楚。
pre-rendering 的架構
在 pre-rendering 的架構下,每個產生的 HTML 都與該頁面所需的最少 JavaScript 程式碼一起送給瀏覽器。當瀏覽器載入頁面時,就會透過執行 JavaScript 程式碼讓頁面變得能夠互動。而這個過程稱為 Hydration。
No pre-rendering 的架構
在 no pre-rendering 的架構下,HTML 會是在瀏覽器才開始生成,所以使用者在進到頁面的當下,其實頁面會是空白的。所以在這種架構下要更注意,JavaScript 打包後的 bundle size。
套用我同事(?熱愛胡適的同事)一句常說的話,大膽假設小心求證。雖然我很想放過自己,但還是來求證一下吧! 這個網站是透過 Create React APP 所建構的專案,他是一個 no pre-rendering 的架構。 請根據以下步驟,來禁用此網站 JavaScript 的程式碼。然後讓我們來看看會發生什麼事。
- 打開開發者工具
- mac 的話,按下
command + shift + P
,windows 的話自己 google - 輸入
disable javascript
,然後按下enter
然後重新整理一下網站,你會發現,超酷的~整個網站畫面都是白的。只會看到 You need to enable JavaScript to run this app. 顯示在畫面上。 所以我們可以得證,no pre-rendering 的架構下,HTML 會是在瀏覽器(client 端)生成的,所以使用者在進到頁面的當下,其實頁面會是空白的。這會讓網路爬蟲找不到你的頁面資料,這樣會讓那些搜尋引擎覺得你的網站是個爛東西。SEO 排名自然就會低了
再來,我們來看 pre-rendering 架構下的網站。就是這個網站。對!你現在正在看的這個。 我們一樣來 disable JavaScript。恩…我等你各位一下
you see 雖然看起來沒有 css,這是因為這個網站有用 JavaScript 去動態改變樣式,但內容是有的,包含圖片、文章內容的訊息都有在 disable JavaScript 的情況下存在,這就是 pre-rendering 的架構下很大的優勢。在這個架構下,就不用擔心搜尋引擎的爬蟲爬不到了。舒服,咱們都求證完了。
Parallel Routes
再來,我們來點輕鬆的介紹。Parallel Routes 算是我近期看到最 cool 的應用,而且在 Next.js 的框架下,超好實現。這邊咱們直接看 use case 吧!絕對不是因為我懶,而是因為我想要讓你們看一下 use case。 這是 Vercel 產品 VP 的 X (twitter)。我們翻一翻,看看有沒有圖片。有的!你點開來圖片看看。並仔細觀察這個網頁結構。你會發現,你現在看到的東西,它自己就是一個頁面,因為 url 改變了。當你按下(X),雖然感覺上是關掉了這個視窗,但實際上,你可以看到 url 變回去了。而且原本在換頁前的狀態都有保留。這就是應用 Parallel Routes 強大的地方。讓你可以在同一個視窗下,顯示兩個或多個 route(頁面) 的內容。這還代表當你點擊圖片後,你可以透過 url,直接將特定貼文分享給別人。這樣別人可以直接看到這個貼文的頁面。這樣的設計模式讓使用者能夠更間單輕鬆的分享網站資訊。是真的牛批!
如果大家還是沒有感受太強烈的話,我這還有個例子。這是一個跟 AI 有關的翻譯的網站。但因為還沒正式上線,所以就不分享給大家。我用錄影的方式,給大家看一下 Parallel Routes 強大的地方。
Conclusion
各位有發現嗎?不是說全端框架嗎?介紹到這裡怎麼感覺跟後端好像沒半毛錢關係!?對啊!我都沒講。
因為呢~我累了~
但其實 Next.js 最強大的地方就在於它的架構讓網站開發者可以很輕鬆的在同一個專案下進行前後端的開發。但 server 端的操作用 workshop 的形式比較適合,所以下次吧!
謝謝大家,happy coding。(*´д`)