經過足足70個canary版本之後,Next.js 9終於正式發佈了!

經過足足70個canary版本之後,Next.js 9正式版終於發佈了。新版的主要特性包括:

  • 內置零配置TypeScript支持:開發者可以藉助自動化TypeScript支持和集成的類型檢查更方便地構建應用。

  • 基於文件系統的動態路由:無需自定義服務器即可通過文件系統表達複雜的應用路由需求。

  • 自動靜態優化:利用默認的服務端渲染和靜態預渲染提升網站速度,同時不犧牲功能。

  • API路由:利用熱重載和統一的構建管道快速構建後端應用程序端點。

  • 更多生產優化:通過視口內預取等優化提升應用的響應能力。

  • 提升開發體驗:一系列細微、易用的改進,改善開發工作體驗。

這些優勢都會儘可能向後兼容。大多數Next.js應用只需運行下列代碼即可升級到新版:

npm i next@latest react@latest react-dom@latest

應用代碼庫需要改動的情況很少。詳細信息可參閱升級指南

基於Next.js的網站案例很多,包括IGN、Bang&Olufsen、Intercom、Buffer和Ferrari等等。更多案例可參見:https://nextjs.org/showcase

內置零配置TypeScript支持

一年前的Next.js 6通過名爲@zeit/next-typescript的插件引入了TypeScript的基礎支持。用戶還必須自定義他們的.babelrc並在next.config.js中啓用它。

這個插件配置好後允許Next.js構建.ts和.tsx文件。但它沒有集成類型檢查,也沒有Next.js核心提供的類型。於是開發者必須在DefinitelyTyped中單獨維護社區包,可能沒法及時更新內容。

據調研,大多數新老用戶都對使用TypeScript非常感興趣。他們需要一種更可靠、更標準化的解決方案,從而將TypeScript輕鬆集成到現有或新的代碼庫中。

所以Next.js核心開始集成TypeScript支持,改善了開發人員的體驗,並加快了相關流程。

自動安裝

在Next.js中使用TypeScript非常簡單:將任何文件、頁面或組件從.js重命名爲.tsx,然後運行next dev即可。

隨後Next.js就會知道項目中正在使用TypeScript了。Next.js CLI將指導開發者爲React和Node.js安裝必要的類型。

Next.js還將創建一個默認的tsconfig.json,其中包含一些默認值(如果尚未存在)。此文件可以用來在Visual Studio Code等編輯器中進行集成類型檢查。

Next.js 9自動TypeScript設置

集成類型檢查

Next.js會在開發者開發和生產構建時處理類型檢查。

在開發過程中,Next.js會在保存文件後顯示類型錯誤。類型檢查在後臺執行,應用更新會立即反映在瀏覽器中。類型錯誤一旦可用就會傳到瀏覽器中。

Next.js 9開發時類型檢查

如果存在類型錯誤,Next.js會自動讓生產構建失敗(例如下圖中的“next build”)。這樣錯誤的代碼就不會進入生產版本。

Next.js 9生產類型檢查

用TypeScript編寫的Next.js核心

現在Next.js的大部分代碼庫已經遷移到TypeScript上,不僅增強了Next.js的代碼質量,而且現在所有核心模塊都提供了類型。

例如,當導入next/link時,支持TypeScript的編輯器將顯示允許的屬性以及它們接受的值。

Next.js核心類型

動態路由

動態路由(也稱爲URL Slugs或Pretty/Clean URL)是兩年半前Next.js發佈後,GitHub上的第一批功能請求之一。

Next.js 2.0引入了自定義服務器API,開發者能以編程方式使用Next.js,“解決”了這個需求。Next.js可以作爲呈現引擎,啓用傳入URL的抽象和映射以呈現某些頁面。

據官方調研,許多應用都使用了自定義服務器。自定義服務器最常見的用途是動態路由。

但是自定義服務器也有自己的缺陷:路由在服務器級而不是代理級處理,它作爲整體部署和擴展,並且容易出現性能問題。

由於自定義服務器要求整個應用程序跑在一個實例上,通常很難把它部署到無服務器環境來解決上述問題。無服務器請求是在代理層路由的,並獨立擴展/執行以消除性能瓶頸。

開發者創建一個名爲pages/blog.js的文件後就能在/blog下面有一個可訪問頁面了,然後就進入了Next.js的魔法世界。那麼爲什麼用戶需要創建自己的服務器,還要學習Next.js的可編程API才能支持像/blog/my-first-post (/blog/:id)這樣的路由呢?官方開始探索新的路由映射方案,新的解決方案從pages/目錄入手。

創建動態路由頁面

Next.js支持使用基本命名參數創建路由,這是一種由path-to-regexp(Express的庫)推廣的模式。

現在開發者可以在pages目錄中創建名爲:pages/post/[pid] .js的文件來創建與/post/:pid路由匹配的頁面了。

Next.js將自動匹配/post/1、/post/hello-nextjs等請求,並呈現pages/post/[pid] .js中定義的頁面。匹配的URL段將作爲查詢參數傳遞到你的頁面,其名稱在[方括號]之間指定。

例如:給定以下頁面和/post/hello-nextjs請求,查詢對象將是{pid:‘hello-nextjs’}:

static async getInitialProps({ query }) {
//pid = 'hello-nextjs'
  const { pid } = query

  const postContent = await fetch(
    `https://api.example.com/post/${encodeURIComponent(pid)}`
  ).then(r => r.text())

  return { postContent }
}

新版還支持多個動態URL段。

目錄名稱和文件名支持[param]語法,示例如下:

./pages/blog/[blogId]/comments/[commentId].js
./pages/posts/[pid]/index.js

更多信息可參考Next.js文檔Next.js學習部分

自動靜態優化

Next.js在大約兩年前發佈的v3版本中增加了對靜態網站生成的支持。

理由很簡單:靜態網站速度很快,它們不需要服務器端計算,數據可以立即從CDN服務器傳輸到最終用戶。

但是,之前的版本中服務端呈現或靜態生成的應用程序不可兼得,要麼選擇服務端呈現要麼是靜態生成,沒有中間答案。

實際上應用可以有不同的需求。這些需求需要不同的呈現策略和取捨。

例如,主頁和營銷頁面通常包含靜態內容,是靜態優化的理想場景。

另一方面,產品介紹頁可能更適合數據頻繁更新的服務端呈現。

於是官方開始探索更好的方案,試圖爲每個場景自動選擇最快的途徑,比如爲宣傳頁面靜態輸出,爲介紹頁面做動態服務端呈現。

從Next.js 9開始,用戶無需在完全服務器呈現或靜態導出其應用之間做二選一了。新版可以在不同頁面上使用不同的策略。

自動部分靜態導出

新版引入了一種啓發式方法來自動確定頁面是否可以預呈現爲靜態HTML。

程序使用getInitialProps判斷頁面是否有阻止數據的需求來作出選擇。

這樣一來,Next.js就可以創建同時包含服務器呈現和靜態生成頁面的混合應用

內置的Next.js服務器(next start)和編程API(app.getRequestHandler())都透明地支持這種構建輸出。無需配置或特殊處理。

靜態生成的頁面仍然是反應式的:Next.js將爲應用客戶端進行hydrate操作,使其具有完整的交互性。

此外,如果頁面依賴於URL中的查詢參數,Next.js將在hydrate操作後更新你的應用程序。

在開發期間靜態生成頁面時Next.js會彈出通知告知開發者。單擊通知即可隱藏。

Next.js靜態優化指標

靜態生成的頁面也將顯示在Next.js的構建輸出中:

Next.js構建輸出類型指示

API路由

許多情況下,開發者在構建React應用程序時需要某種後端,用來從數據庫檢索數據或處理用戶提供的數據(例如聯繫表單)。

官方調研發現許多需要後端的用戶使用自定義服務器構建了他們的API,結果遇到了很多問題。例如,Next.js不編譯自定義服務器代碼,這意味着開發者無法使用導入/導出或TypeScript。

因此許多用戶最後在自定義服務器之上實現了他們自己的自定義編譯管道。雖然這解決了他們的需求,但也容易出現許多陷阱:例如,樹抖動(tree shaking)配置不正確時會在整個應用程序中禁用。

現在Next.js 9引入了API路由,爲開發者構建後端帶來了最佳體驗。

要開始使用API​​路由,請在pages/目錄中創建名爲api/的目錄。

此目錄中的任何文件都將自動映射到/api/<你的路徑>,就像其他頁面文件映射到路由一樣。

例如,pages/api/contact.js將映射到/api/contact。

注意:API路由也支持動態路由。

pages/api/目錄中的所有文件都導出一個請求處理函數,而不是React組件:

export default function handle(req, res) {
  res.end('Hello World')
}
  • req指的是擴展http.IncomingMessage的NextApiRequest。

  • res指的是擴展http.ServerResponse的NextApiResponse。

通常來說,API端點接收一些傳入數據,例如查詢字符串、請求正文或cookie,並使用其他數據響應。

官方調研發現,許多情況下用戶沒有直接使用Node.js請求和響應對象。相反,他們使用了像Express這樣的服務器庫提供的​​抽象。

這樣做的原因是,在許多情況下傳入數據是某種形式的文本,必須首先解析纔有用。因此用這些服務器庫後就不用手動解析數據了,最常見的方式是通過中間件。最常用的中間件提供了查詢字符串、正文和cookie解析的功能,但是它們仍然需要做一些設置才能用。

Next.js中的API路由將默認提供這些中間件,以便開發者快速高效地創建API端點:

export default function handle(req, res) {
  console.log(req.body)//The request body
  console.log(req.query)//The url querystring
  console.log(req.cookies)//The passed cookies
  res.end('Hello World')
}

除了使用傳入數據,API端點通常也會返回數據,通常返回的是JSON。默認情況下,Next.js提供res.json()以簡化發送操作:

export default function handle(req, res) {
  res.json({ title: 'Hello World' })
}

在開發中更改API端點時,代碼會自動重新加載,因此無需重新啓動服務器。

生產優化

預取視口內的<Link>

Next.js 9將自動預取出現在視口內(in viewport)的<Link>組件。

此功能可以加快跳轉到新頁面的速度,從而提高應用程序的響應速度。

Next.js使用Intersection Observer預取後臺必需的資源(https://www.w3.org/TR/resource-hints/#prefetch)。

這些請求優先級較低,並且產生fetch()或XHR請求。如果用戶啓用了數據保護,Next.js將避免自動預取。

在用戶很少訪問的頁面上將prefetch屬性設置爲false即可關閉此功能:

<Link href="/terms" prefetch={false}>
  <a>Terms of Service</a>
</Link>

默認的AMP優化

Next.js 9現在默認爲AMP(移動頁面加速)優先和混合AMP頁面呈現優化的AMP。

雖然AMP頁面是可選的,但Next.js會自動優化其輸出。這些優化可以使呈現速度提高50%。

這裏要感謝Sebastian Benz爲AMP Optimizer帶來的改進。

typeof window分支的無效代碼清理

Next.js 9在服務器和客戶端構建期間用適當的值(undefined或object)替換typeof window。此更改使Next.js可以自動從生產構建的應用程序中刪除無效代碼。

如果用戶在getInitialProps或應用程序的其他部分中寫了純服務端代碼,那麼就能注意到客戶端包變小了。

改善開發體驗

編譯指示器

在之前的版本中,開發者只能查看開發者控制檯才能知道熱代碼替換即將執行(並且Next.js編譯工具鏈正在工作)。

然而很多時候,人們正在查看生成的呈現,很難知道Next.js是否仍在編譯。例如,開發者可能正在對頁面上的樣式做些小改動,結果沒法第一時間知道它們是否已更新過。

官方爲此創建了一個RFC/“第一個好問題”的頁面,以探討這個問題的可行解決方案。

官方收到了許多設計師和工程師在RFC上的反饋。其中Rafael Almeida藉此機會與官方團隊合作,實現了一個全新的指標,並引入了Next.js 9。

現在每當Next.js執行編譯工作時,開發者會看到頁面右下角出現一個小三角形。

Next.js編譯指標

控制檯輸出

傳統上,開發者在開發中進行更改時,Next.js會顯示一個編譯指示器狀態,並在開發者作出更改時清屏。

這種行爲會導致一些問題。最值得注意的是,它會從應用程序代碼中清除控制檯輸出,例如,當你將console.log添加到組件時就會這樣。使用外部工具將日誌輸出拼接在一起時也會清除控制檯輸出,如Now CLI或docker-compose。

從Next.js 9開始日誌輸出跳躍變少,也不再清屏。這樣可以提供更好的體驗,因爲終端窗口將顯示更多相關信息,閃爍也更少了,同時Next.js能更好地與你正在使用的工具集成。

Next.js開發控制檯輸出

這裏特別感謝Justin Chase的貢獻。

構建輸出統計

使用next build構建生產應用時,它將爲你提供所有已構建頁面的詳細視圖。

每個頁面都會自動收到一些統計信息

最顯眼的是包大小。隨着應用程序的增長,你的JavaScript包也會變大,這個構建時指示可以告訴開發者生產包變大了多少。將來的版本中開發者還可以爲生產構建失敗的頁面設置性能預算

Next.js構建出的頁面大小

除了包大小,新版還展示了每個頁面中使用了多少個項目組件和node_modules組件,以幫助開發者瞭解頁面的複雜度。

Next.js頁面包計數

每個頁面還有一個指示,告訴開發者它是靜態優化還是服務端呈現,因爲每個頁面的行爲都可能不一樣。

Next.js構建頁面類型

每頁配置對象

現在每個頁面都可以導出配置對象。一開始這個配置允許你選擇啓用AMP,但將來你能配置更多頁面特定選項。

//pages/about.js
export const config = { amp: true }

export default function AboutPage(props) {
  return <h3>My AMP About Page!</h3>
}

要選擇混合AMP呈現,可以使用’hybrid’值:

//pages/about.js
import { useAmp } from 'next/amp'

export const config = { amp: 'hybrid' }

export default function AboutPage(props) {
  const isAmp = useAmp()
  return <h3>My About Page!{isAmp ? <> Powered by AMP!</> : ''}</h3>
}

新版刪除了withAmp高階組件,爲新配置讓路。

官方提供了一個codemod,可以自動將withAmp的用法轉換爲新的配置對象。更多信息可以參閱升級指南

代碼庫改進

新版對一些工具做了一些更改以提供更好的體驗。

如前所述,Next.js核心現在是用TypeScript編寫的,並且會自動爲Next.js應用程序生成類型。這對使用Next.js構建的應用程序很有用,此外它在處理核心代碼庫時也很有幫助。現在開發者可以自動獲得類型錯誤和自動完成時。

Next.js已經擁有了一個規模相當大的集成測試套件,包含50多個Next.js應用程序,每個應用程序都有針對自己運行的​​測試。通過這些測試,官方可以確保新版本發佈時用戶可以順利升級,因爲之前可用的功能是使用同一測試套件測試的。

大多數測試都是集成測試,可以復現“真正的”開發人員使用Next.js開發的過程。例如,一些測試可以復現對Next.js應用程序的更改,以查看熱模塊替換是否正常工作。

這些集成測試主要基於Selenium webdriver,它與chromedriver結合在一起測試無頭Chrome。但隨着時間的推移,其他瀏覽器,尤其是Internet Explorer 11等舊版瀏覽器會出現一些問題。

因爲官方使用了Selenium,所以能夠在多個瀏覽器上自動運行測試。

截至目前,官方正在Chrome、Firefox、Safari和Internet Explorer 11上運行這個測試套件。

谷歌Chrome協作

谷歌Chrome團隊一直在通過提交RFC和pull request來改進Next.js。

雙方合作的目標是大規模性能提升,重點是包大小、啓動和hydrate時間。

例如,這些更改將改善小型網站的體驗,也可以改善Hulu、Twitch和Deliveroo等大型應用程序的體驗。

模塊/Nomodule

合作的第一項重點任務是將新版JavaScript代碼發佈到支持新版JavaScript的瀏覽器上。

例如,當前Next.js必須爲async/await語法提供polyfill,因爲代碼可能在不支持async/await的瀏覽器中執行。

Next.js Module/Nomodule合作RFC

爲了在保持舊瀏覽器中正常運行應用的前提下向支持JS的瀏覽器發送新版JavaScript代碼,Next.js將使用module/nomodule模式。這個模式提供了一種可靠的機制,可以將新版JavaScript代碼提供給現代瀏覽器,同時仍允許舊版瀏覽器回退到polyfilled ES5。

此處有Next.js中的module/nomodule的RFC。

改進包拆分

Next.js中當前的包拆分策略使用基於比率的啓發式算法,用於在單個“公共”塊中包含模塊。由於只有一個包的時候粒度非常小,因此會下載不必要的代碼(因爲公共塊可能包含特定路由實際上不需要的代碼),或者代碼複製到了多個頁面包中。

Next.js Chunking Collaboration RFC

此處有改進包拆分的RFC。

其他改進

Chrome團隊還在對Next.js進行許多其他優化和更改。這些RFC將很快分享給開發者。

這些RFC和pull request標記爲“協作”,以便在Next.js問題跟蹤器中輕鬆找到它們。

社區

Next.js社區在繼續成長。此版本有超過65位pull request作者提供核心改進或示例。

現在官方提供了200多個關於如何將Next.js與不同庫和技術集成的示例,包括大多數css-in-js和數據獲取庫。

  • 已經有超過720名貢獻者提交了至少1次貢獻。

  • 在GitHub上,該項目已經得到了38,600星。

  • 自第一個版本發佈以來已提交了超過3,400個pull request,自上次主要版本發佈以來有超過800個。

  • 自上次主要版本發佈以來,Spectrum.chat/next-js上的Next.js社區註冊成員多了一倍,現在超過8,600人。

感謝社區以及幫助開發此版本的所有外部反饋和貢獻。

英文原文:https://nextjs.org/blog/next-9#built-in-zero-config-typescript-support

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章