我們?yōu)殚_源的Next.js感到非常自豪鳞骤,它是一個(gè)服務(wù)器渲染的通用JavaScript webapps的小型框架阅羹,建立在React,Webpack和Babel的基礎(chǔ)之上愉舔。
要開始使用它艺配,在一個(gè)新的目錄中運(yùn)行: package.json
$ npm install next --save
$ mkdir pages
填充pages/index.js:
import React from 'react'
export default () => <div>Hello world!</div>
package.json像這樣添加一個(gè)腳本:
{
"scripts": {
"dev": "next"
}
}
并運(yùn)行:
$ npm run dev
這篇博客文章將涉及項(xiàng)目的理念和設(shè)計(jì)決策察郁。
要學(xué)習(xí)如何使用Next.js衍慎,請(qǐng)參閱自述文件,您可以在幾分鐘內(nèi)了解該工具的全部功能绳锅。
首先我們將深入到項(xiàng)目的背景西饵,然后描述6個(gè)基本原則:
- 零設(shè)置。使用文件系統(tǒng)作為API
- 只有JavaScript鳞芙。一切都是一個(gè)功能
- 自動(dòng)服務(wù)器呈現(xiàn)和代碼分割
- 數(shù)據(jù)獲取取決于開發(fā)者
- 預(yù)期是表現(xiàn)的關(guān)鍵
- 簡單部署
背景
多年來眷柔,我們一直在追求通用JavaScript應(yīng)用程序的愿景。
Node.js引導(dǎo)了客戶端和服務(wù)器之間的代碼共享原朝,拓寬了世界各地許多開發(fā)者的貢獻(xiàn)面驯嘱。
許多嘗試都是為了在Node上開發(fā)應(yīng)用程序和網(wǎng)站而設(shè)計(jì)的。許多模板語言和框架出現(xiàn)了......但是前端和后端之間的技術(shù)鴻溝依然存在喳坠。
例如鞠评,如果你選擇了Express和Jade,一些HTML將被服務(wù)器渲染壕鹉,然后一個(gè)不同的代碼庫 (由jQuery或類似的庫支持)將接管剃幌。
這種情況實(shí)際上并不比PHP的好。在許多方面晾浴,PHP實(shí)際上更適合于“服務(wù)器呈現(xiàn)HTML”作業(yè)负乡。在異步/等待之前,很難在JS中查詢數(shù)據(jù)服務(wù)脊凰。將錯(cuò)誤限制在請(qǐng)求/響應(yīng)的范圍之內(nèi)也是非常困難的抖棘。
然而,從那以后狸涌,顯著的概念上的變化使我們能夠縮小這個(gè)差距切省。其中最重要的是引入了純渲染函數(shù),該函數(shù)根據(jù)當(dāng)時(shí)的可用數(shù)據(jù)返回UI的表示形式帕胆。
這個(gè)模型(被React普及)是非常重要的朝捆,但是這與大多數(shù)模板系統(tǒng)的工作原理沒有什么不同。另一個(gè)關(guān)鍵概念是組件生命周期懒豹。
生命周期鉤子允許我們處理源自服務(wù)器的一些渲染的延續(xù)右蹦。例如,您可以從數(shù)據(jù)的靜態(tài)表示開始歼捐,訂閱來自服務(wù)器的實(shí)時(shí)更新,并隨時(shí)間變化晨汹”ⅲ或者也許它保持不變。
Next.js是我們?nèi)绾瓮苿?dòng)這一愿景的淘这。
零設(shè)置剥扣。使用文件系統(tǒng)作為API
工具對(duì)文件系統(tǒng)中的項(xiàng)目結(jié)構(gòu)做了一些假設(shè)巩剖。
例如,我們通常通過創(chuàng)建一個(gè)新的目錄钠怯,放置一個(gè)package.json內(nèi)部佳魔,然后安裝模塊來啟動(dòng)一個(gè)Node.js項(xiàng)目./node_modules。
Next.js通過引入pages 頂級(jí)組件所在的子目錄來擴(kuò)展該結(jié)構(gòu)晦炊。
例如鞠鲜,您可以使用以下命令來填充pages/index.js路線的哪些地圖/:
import React from 'react'
export default () => <marquee>Hello world</marquee>
然后pages/about.js映射到: /about
import React from 'react'
export default () => <h1>About us</h1>
我們相信這是一個(gè)很好的默認(rèn)開始,并允許一個(gè)項(xiàng)目的快速探索断国。當(dāng)需要更高級(jí)的路由時(shí)贤姆,我們將允許開發(fā)人員攔截請(qǐng)求并采取控制。
所有需要開始工作的項(xiàng)目是運(yùn)行:
$ next
沒有配置稳衬,除非需要霞捡。自動(dòng)熱碼重新加載,錯(cuò)誤報(bào)告薄疚,源地圖碧信,舊版瀏覽器的轉(zhuǎn)換。
只有JavaScript街夭。一切都是一個(gè)功能
Next.js中的每個(gè)路由只是一個(gè)ES6模塊砰碴,用于導(dǎo)出一個(gè)擴(kuò)展的函數(shù)或類React.Component。
這種方法與類似模型相比的優(yōu)點(diǎn)是整個(gè)系統(tǒng)仍然是高度可組合和可測(cè)試的莱坎。例如衣式,一個(gè)組件可以被直接渲染,或者被另一個(gè)頂層組件導(dǎo)入和渲染檐什。
組件也可以引入對(duì)頁面的更改: <head>
import React from 'react'
import Head from 'next/head'
export default () => (
<div>
<Head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
</Head>
<h1>Hi. I'm mobile-ready!</h1>
</div>
)
此外碴卧,不需要包裝或轉(zhuǎn)換,使這個(gè)系統(tǒng)完全可測(cè)試乃正。您的測(cè)試套件可以簡單地導(dǎo)入和淺顯渲染您的路線住册。
我們也決定采用CSS-in-JS。我們使用優(yōu)秀的glamor庫瓮具,給我們完全不受限制的CSS的權(quán)力荧飞,而不需要CSS解析和編譯:
import React from 'react'
import css from 'next/css'
export default () => <p className={style}>Hi there!</p>
const style = css({
color: 'red',
':hover': {
color: 'blue'
},
'@media (max-width: 500px)': {
color: 'rebeccapurple'
}
})
我們認(rèn)為這個(gè)模型提供了卓越的性能,可組合性和與服務(wù)器渲染流水線的集成名党。
自動(dòng)服務(wù)器呈現(xiàn)和代碼分割
迄今為止叹阔,兩項(xiàng)任務(wù)同時(shí)非常困難和非常可却谩:
服務(wù)器渲染
- 將應(yīng)用程序的構(gòu)建分割成更小的包
- 使用Next.js耳幢,每個(gè)內(nèi)部組件pages/都會(huì)自動(dòng)獲取服務(wù)器并且內(nèi)聯(lián)腳本。
當(dāng)通過或路由器動(dòng)態(tài)加載組件時(shí),我們獲取一個(gè)基于JSON的頁面表示睛藻,同樣包含它的腳本启上。 <Link prefetch />
這意味著某個(gè)頁面可能有一個(gè)廣泛的導(dǎo)入列表:
import React from 'react'
import d3 from 'd3'
import jQuery from 'jquery'
...不影響其他頁面的性能。
這個(gè)細(xì)節(jié)對(duì)于那些在技術(shù)和業(yè)務(wù)需求截然不同的組件上進(jìn)行協(xié)作的大型團(tuán)隊(duì)來說特別有用店印。團(tuán)隊(duì)或個(gè)人的表現(xiàn)處罰不會(huì)影響組織的其余部分冈在。
數(shù)據(jù)獲取取決于開發(fā)者
靜態(tài)JSX的服務(wù)器渲染是一個(gè)重要的成就,但真實(shí)世界的應(yīng)用程序處理來自不同的API調(diào)用和網(wǎng)絡(luò)請(qǐng)求的動(dòng)態(tài)數(shù)據(jù)按摘。
Next.js對(duì)React組件合同做了非常重要的擴(kuò)展:getInitialProps包券。
提取一些數(shù)據(jù)的頁面如下所示:
import React from 'react'
import 'isomorphic-fetch'
export default class extends React.Component {
static async getInitialProps () {
const res = await fetch('https://api.company.com/user/123')
const data = await res.json()
return { username: data.profile.username }
}
}
我們對(duì)于什么樣的功能(像異步/等待)的立場(chǎng)可以概括為:我們的目標(biāo)是V8的功能。由于我們的目標(biāo)是在服務(wù)器和客戶端之間進(jìn)行代碼共享院峡,所以在執(zhí)行Node上的代碼以及在Chrome或Brave上開發(fā)時(shí)兴使,這給我們帶來了很好的性能。
正如你所看到的那樣照激,契約是非常簡單而且不可選擇的:必須返回一個(gè)解析成JavaScript的對(duì)象发魄,然后填充組件。 getInitialPropsPromise props
這使得Next.js在REST API俩垃,GraphQL甚至是全局狀態(tài)管理庫Redux上都能很好地發(fā)揮作用励幼,在我們的wiki上你可以找到它的一個(gè)例子。
同樣的方法允許加載不同的數(shù)據(jù)口柳,這取決于組件是通過服務(wù)器呈現(xiàn)的還是通過客戶端路由動(dòng)態(tài)呈現(xiàn)的:
static async getInitialProps ({ res }) {
return res
? { userAgent: res.headers['user-agent'] }
: { userAgent: navigator.userAgent }
}