Next.js 是一個(gè)輕量級的 React 服務(wù)端渲染應(yīng)用框架降瞳。
Next.js中文站點(diǎn) http://nextjs.frontendx.cn
Next.js中文站Github https://github.com/raoenhui/next-site-cn
當(dāng)前翻譯版本為 7.0.0-canary.8。
- 怎么使用
- 項(xiàng)目部署
- 瀏覽器支持
- 導(dǎo)出靜態(tài)頁面
- 多 zone
- 技巧
- FAQ
- 貢獻(xiàn)
- 作者
<a id="how-to-use"></a>
怎么使用
<a id="setup"></a>
安裝
安裝它:
npm install --save next react react-dom
將下面腳本添加到 package.json 中:
{
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
}
}
下面, 文件系統(tǒng)是主要的 API. 每個(gè).js
文件將變成一個(gè)路由贴谎,自動(dòng)處理和渲染坏逢。
新建 ./pages/index.js
到你的項(xiàng)目中:
export default () => <div>Welcome to next.js!</div>
運(yùn)行 npm run dev
命令并打開 http://localhost:3000
高诺。 如果你想使用其他端口踱讨,可運(yùn)行 npm run dev -- -p <設(shè)置端口號>
.
目前為止我們可以了解到:
- 自動(dòng)打包編譯 (使用 webpack 和 babel)
- 熱加載
- 以
./pages
作為服務(wù)端的渲染和索引 - Static file serving.
./static/
is mapped to/static/
(given you create a./static/
directory inside your project) - 靜態(tài)文件服務(wù).
./static/
映射到/static/
(可以 創(chuàng)建一個(gè)靜態(tài)目錄 在你的項(xiàng)目中)
這里有個(gè)簡單的案例,可以下載看看 sample app - nextgram
<a id="automatic-code-splitting"></a>
代碼自動(dòng)分割
每個(gè)頁面只會(huì)導(dǎo)入import
中綁定以及被用到的代碼. 也就是說并不會(huì)加載不需要的代碼!
import cowsay from 'cowsay-browser'
export default () =>
<pre>
{cowsay.say({ text: 'hi there!' })}
</pre>
<a id="css"></a>
CSS
<a id="built-in-css-support"></a>
支持嵌入樣式
<p><details>
<summary markdown="span"><b>Examples</b></summary>
<ul><li><a >Basic css</a></li></ul>
</details></p>
我們綁定 styled-jsx 來生成獨(dú)立作用域的 CSS. 目標(biāo)是支持 "shadow CSS",但是 不支持獨(dú)立模塊作用域的 JS.
export default () =>
<div>
Hello world
<p>scoped!</p>
<style jsx>{`
p {
color: blue;
}
div {
background: red;
}
@media (max-width: 600px) {
div {
background: blue;
}
}
`}</style>
<style global jsx>{`
body {
background: black;
}
`}</style>
</div>
想查看更多案例可以點(diǎn)擊 styled-jsx documentation查看.
<a id="css-in-js"></a>
內(nèi)嵌樣式
<p><details>
<summary markdown="span">
<b>Examples</b>
</summary>
<ul><li><a >Styled components</a></li><li><a >Styletron</a></li><li><a >Glamor</a></li><li><a >Glamorous</a></li><li><a >Cxs</a></li><li><a >Aphrodite</a></li><li><a >Fela</a></li></ul>
</details></p>
有些情況可以使用 CSS 內(nèi)嵌 JS 寫法持偏。如下所示:
export default () => <p style={{ color: 'red' }}>hi there</p>
更復(fù)雜的內(nèi)嵌樣式解決方案递沪,特別是服務(wù)端渲染的時(shí)樣式更改。我們可以通過包裹自定義 Document综液,來添加樣式款慨,案例如下:custom <Document>
<a id="importing-css--sass--less--stylus-files"></a>
使用 CSS / Sass / Less / Stylus files
支持用.css
, .scss
, .less
or .styl
,需要配置默認(rèn)文件 next.config.js谬莹,具體可查看下面鏈接
<a id="static-file-serving-eg-images"></a>
靜態(tài)文件服務(wù)(如圖像)
在根目錄下新建文件夾叫static
檩奠。代碼可以通過/static/
來引入相關(guān)的靜態(tài)資源。
export default () => <img src="/static/my-image.png" alt="my image" />
_注意:不要自定義靜態(tài)文件夾的名字附帽,只能叫static
埠戳,因?yàn)橹挥羞@個(gè)名字 Next.js 才會(huì)把它當(dāng)作靜態(tài)資源。
<a id="populating-head"></a>
生成<head>
<p><details>
<summary markdown="span"><b>Examples</b></summary>
<ul>
<li><a >Head elements</a></li>
<li><a >Layout component</a></li>
</ul>
</details></p>
我們設(shè)置一個(gè)內(nèi)置組件來裝載<head>
到頁面中蕉扮。
import Head from 'next/head'
export default () =>
<div>
<Head>
<title>My page title</title>
<meta name="viewport" content="initial-scale=1.0, width=device-width" />
</Head>
<p>Hello world!</p>
</div>
我們定義key
屬性來避免重復(fù)的<head>
標(biāo)簽整胃,保證<head>
只渲染一次,如下所示:
import Head from 'next/head'
export default () => (
<div>
<Head>
<title>My page title</title>
<meta name="viewport" content="initial-scale=1.0, width=device-width" key="viewport" />
</Head>
<Head>
<meta name="viewport" content="initial-scale=1.2, width=device-width" key="viewport" />
</Head>
<p>Hello world!</p>
</div>
)
只有第二個(gè)<meta name="viewport" />
才被渲染喳钟。
注意:在卸載組件時(shí)屁使,<head>
的內(nèi)容將被清除。請確保每個(gè)頁面都在其<head>
定義了所需要的內(nèi)容奔则,而不是假設(shè)其他頁面已經(jīng)加過了
<a id="fetching-data-and-component-lifecycle"></a>
獲取數(shù)據(jù)以及組件生命周期
<p><details>
<summary markdown="span"><b>Examples</b></summary>
<ul><li><a >Data fetch</a></li></ul>
</details></p>
如果你需要一個(gè)有狀態(tài)蛮寂、生命周期或有初始數(shù)據(jù)的 React 組件(而不是上面的無狀態(tài)函數(shù))日月,如下所示:
import React from 'react'
export default class extends React.Component {
static async getInitialProps({ req }) {
const userAgent = req ? req.headers['user-agent'] : navigator.userAgent
return { userAgent }
}
render() {
return (
<div>
Hello World {this.props.userAgent}
</div>
)
}
}
相信你注意到焕蹄,當(dāng)頁面渲染時(shí)加載數(shù)據(jù),我們使用了一個(gè)異步方法getInitialProps
左冬。它能異步獲取 JS 普通對象,并綁定在props
上
當(dāng)服務(wù)渲染時(shí)范抓,getInitialProps
將會(huì)把數(shù)據(jù)序列化骄恶,就像JSON.stringify
。所以確保getInitialProps
返回的是一個(gè)普通 JS 對象匕垫,而不是Date
, Map
或 Set
類型僧鲁。
當(dāng)頁面初次加載時(shí),getInitialProps
只會(huì)在服務(wù)端執(zhí)行一次年缎。getInitialProps
只有在路由切換的時(shí)候(如Link
組件跳轉(zhuǎn)或路由自定義跳轉(zhuǎn))時(shí)悔捶,客戶端的才會(huì)被執(zhí)行铃慷。
當(dāng)頁面初始化加載時(shí)单芜,getInitialProps
只會(huì)加載在服務(wù)端。只有當(dāng)路由跳轉(zhuǎn)(Link
組件跳轉(zhuǎn)或 API 方法跳轉(zhuǎn))時(shí)犁柜,客戶端才會(huì)執(zhí)行getInitialProps
洲鸠。
注意:getInitialProps
將不能使用在子組件中。只能使用在pages
頁面中馋缅。
只有服務(wù)端用到的模塊放在
getInitialProps
里扒腕,請確保正確的導(dǎo)入了它們,可參考import them properly萤悴。
否則會(huì)拖慢你的應(yīng)用速度瘾腰。
你也可以給無狀態(tài)組件定義getInitialProps
:
const Page = ({ stars }) =>
<div>
Next stars: {stars}
</div>
Page.getInitialProps = async ({ req }) => {
const res = await fetch('https://api.github.com/repos/zeit/next.js')
const json = await res.json()
return { stars: json.stargazers_count }
}
export default Page
getInitialProps
入?yún)ο蟮膶傩匀缦拢?/p>
-
pathname
- URL 的 path 部分 -
query
- URL 的 query 部分,并被解析成對象 -
asPath
- 顯示在瀏覽器中的實(shí)際路徑(包含查詢部分)覆履,為String
類型 -
req
- HTTP 請求對象 (只有服務(wù)器端有) -
res
- HTTP 返回對象 (只有服務(wù)器端有) -
jsonPageRes
- 獲取數(shù)據(jù)響應(yīng)對象 (只有客戶端有) -
err
- 渲染過程中的任何錯(cuò)誤
<a id="routing"></a>
路由
<a id="with-link"></a>
<Link>
用法
<p><details>
<summary markdown="span"><b>Examples</b></summary>
<ul>
<li><a >Hello World</a></li>
</ul>
</details></p>
可以用 <Link>
組件實(shí)現(xiàn)客戶端的路由切換蹋盆。
// pages/index.js
import Link from 'next/link'
export default () =>
<div>
Click{' '}
<Link href="/about">
<a>here</a>
</Link>{' '}
to read more
</div>
// pages/about.js
export default () => <p>Welcome to About!</p>
注意:可以使用<Link prefetch>
使鏈接和預(yù)加載在后臺(tái)同時(shí)進(jìn)行,來達(dá)到頁面的最佳性能硝全。
客戶端路由行為與瀏覽器很相似:
- 組件獲取
- 如果組件定義了
getInitialProps
栖雾,數(shù)據(jù)獲取了。如果有錯(cuò)誤情況將會(huì)渲染_error.js
伟众。 - 1和2都完成了析藕,
pushState
執(zhí)行,新組件被渲染凳厢。
如果需要注入pathname
, query
或 asPath
到你組件中账胧,你可以使用withRouter。
<a id="with-url-object"></a>
URL 對象
<p><details>
<summary markdown="span"><b>Examples</b></summary>
<ul>
<li><a >With URL Object Routing</a></li>
</ul>
</details></p>
組件<Link>
接收 URL 對象先紫,而且它會(huì)自動(dòng)格式化生成 URL 字符串
// pages/index.js
import Link from 'next/link'
export default () =>
<div>
Click{' '}
<Link href={{ pathname: '/about', query: { name: 'Zeit' }}}>
<a>here</a>
</Link>{' '}
to read more
</div>
將生成 URL 字符串/about?name=Zeit
找爱,你可以使用任何在Node.js URL module documentation定義過的屬性。
<a id="replace-instead-of-push-url"></a>
替換路由
<Link>
組件默認(rèn)將新 url 推入路由棧中泡孩。你可以使用replace
屬性來防止添加新輸入车摄。
// pages/index.js
import Link from 'next/link'
export default () =>
<div>
Click{' '}
<Link href="/about" replace>
<a>here</a>
</Link>{' '}
to read more
</div>
<a id="using-a-component-that-supports-onclick"></a>
組件支持點(diǎn)擊事件 onClick
<Link>
支持每個(gè)組件所支持的onClick
事件。如果你不提供<a>
標(biāo)簽,只會(huì)處理onClick
事件而href
將不起作用吮播。
// pages/index.js
import Link from 'next/link'
export default () =>
<div>
Click{' '}
<Link href="/about">
<img src="/static/image.png" alt="image" />
</Link>
</div>
<a id="forcing-the-link-to-expose-href-to-its-child"></a>
暴露 href
給子元素
如子元素是一個(gè)沒有 href 屬性的<a>
標(biāo)簽变屁,我們將會(huì)指定它以免用戶重復(fù)操作。然而有些時(shí)候意狠,我們需要里面有<a>
標(biāo)簽粟关,但是Link
組件不會(huì)被識(shí)別成超鏈接,結(jié)果不能將href
傳遞給子元素环戈。在這種場景下闷板,你可以定義一個(gè)Link
組件中的布爾屬性passHref
,強(qiáng)制將href
傳遞給子元素院塞。
注意: 使用a
之外的標(biāo)簽而且沒有通過passHref
的鏈接可能會(huì)使導(dǎo)航看上去正確遮晚,但是當(dāng)搜索引擎爬行檢測時(shí),將不會(huì)識(shí)別成鏈接(由于缺乏 href 屬性)拦止,這會(huì)對你網(wǎng)站的 SEO 產(chǎn)生負(fù)面影響县遣。
import Link from 'next/link'
import Unexpected_A from 'third-library'
export default ({ href, name }) =>
<Link href={href} passHref>
<Unexpected_A>
{name}
</Unexpected_A>
</Link>
<a id="disabling-the-scroll-changes-to-top-on-page"></a>
禁止?jié)L動(dòng)到頁面頂部
<Link>
的默認(rèn)行為就是滾到頁面頂部。當(dāng)有 hash 定義時(shí)(#)汹族,頁面將會(huì)滾動(dòng)到對應(yīng)的 id 上萧求,就像<a>
標(biāo)簽一樣。為了預(yù)防滾動(dòng)到頂部顶瞒,可以給<Link>
加
scroll={false}
屬性:
<Link scroll={false} href="/?counter=10"><a>Disables scrolling</a></Link>
<Link href="/?counter=10"><a>Changes with scrolling to top</a></Link>
<a id="imperatively"></a>
命令式
<p><details>
<summary markdown="span"><b>Examples</b></summary>
<ul>
<li><a >Basic routing</a></li>
<li><a >With a page loading indicator</a></li>
</ul>
</details></p>
你也可以用next/router
實(shí)現(xiàn)客戶端路由切換
import Router from 'next/router'
export default () =>
<div>
Click <span onClick={() => Router.push('/about')}>here</span> to read more
</div>
<a id="intercepting-popstate"></a>
攔截器 popstate
有些情況(比如使用custom router)夸政,你可能想監(jiān)聽popstate
,在路由跳轉(zhuǎn)前做一些動(dòng)作榴徐。
比如守问,你可以操作 request 或強(qiáng)制 SSR 刷新
import Router from 'next/router'
Router.beforePopState(({ url, as, options }) => {
// I only want to allow these two routes!
if (as !== "/" || as !== "/other") {
// Have SSR render bad routes as a 404.
window.location.href = as
return false
}
return true
});
如果你在beforePopState
中返回 false,Router
將不會(huì)執(zhí)行popstate
事件箕速。
例如Disabling File-System Routing酪碘。
以上Router
對象的 API 如下:
-
route
- 當(dāng)前路由的String
類型 -
pathname
- 不包含查詢內(nèi)容的當(dāng)前路徑,為String
類型 -
query
- 查詢內(nèi)容盐茎,被解析成Object
類型. 默認(rèn)為{}
-
asPath
- 展現(xiàn)在瀏覽器上的實(shí)際路徑兴垦,包含查詢內(nèi)容,為String
類型 -
push(url, as=url)
- 頁面渲染第一個(gè)參數(shù) url 的頁面字柠,瀏覽器欄顯示的是第二個(gè)參數(shù) url -
replace(url, as=url)
- performs areplaceState
call with the given url -
beforePopState(cb=function)
- 在路由器處理事件之前攔截.
push
和 replace
函數(shù)的第二個(gè)參數(shù)as
探越,是為了裝飾 URL 作用。如果你在服務(wù)器端設(shè)置了自定義路由將會(huì)起作用窑业。
<a id="with-url-object-1"></a>
URL 對象用法
push
或 replace
可接收的 URL 對象(<Link>
組件的 URL 對象一樣)來生成 URL钦幔。
import Router from 'next/router'
const handler = () =>
Router.push({
pathname: '/about',
query: { name: 'Zeit' }
})
export default () =>
<div>
Click <span onClick={handler}>here</span> to read more
</div>
也可以像<Link>
組件一樣添加額外的參數(shù)。
<a id="router-events"></a>
路由事件
你可以監(jiān)聽路由相關(guān)事件常柄。
下面是事件支持列表:
-
routeChangeStart(url)
- 路由開始切換時(shí)觸發(fā) -
routeChangeComplete(url)
- 完成路由切換時(shí)觸發(fā) -
routeChangeError(err, url)
- 路由切換報(bào)錯(cuò)時(shí)觸發(fā) -
beforeHistoryChange(url)
- 瀏覽器 history 模式開始切換時(shí)觸發(fā) -
hashChangeStart(url)
- 開始切換 hash 值但是沒有切換頁面路由時(shí)觸發(fā) -
hashChangeComplete(url)
- 完成切換 hash 值但是沒有切換頁面路由時(shí)觸發(fā)
這里的
url
是指顯示在瀏覽器中的 url鲤氢。如果你用了Router.push(url, as)
(或類似的方法)搀擂,那瀏覽器中的 url 將會(huì)顯示 as 的值。
下面是如何正確使用路由事件routeChangeStart
的例子:
const handleRouteChange = url => {
console.log('App is changing to: ', url)
}
Router.events.on('routeChangeStart', handleRouteChange)
如果你不想長期監(jiān)聽該事件卷玉,你可以用off
事件去取消監(jiān)聽:
Router.events.off('routeChangeStart', handleRouteChange)
如果路由加載被取消(比如快速連續(xù)雙擊鏈接)
Router.events.on('routeChangeError', (err, url) => {
if (err.cancelled) {
console.log(`Route to ${url} was cancelled!`)
}
})
<a id="shallow-routing"></a>
淺層路由
<p><details>
<summary markdown="span"><b>Examples</b></summary>
<ul>
<li><a >Shallow Routing</a></li>
</ul>
</details></p>
淺層路由允許你改變 URL 但是不執(zhí)行getInitialProps
生命周期哨颂。你可以加載相同頁面的 URL,得到更新后的路由屬性pathname
和query
相种,并不失去 state 狀態(tài)威恼。
你可以給Router.push
或 Router.replace
方法加shallow: true
參數(shù)。如下面的例子所示:
// Current URL is "/"
const href = '/?counter=10'
const as = href
Router.push(href, as, { shallow: true })
現(xiàn)在 URL 更新為/?counter=10
寝并。在組件里查看this.props.router.query
你將會(huì)看到更新的 URL箫措。
你可以在componentdidupdate
鉤子函數(shù)中監(jiān)聽 URL 的變化。
componentDidUpdate(prevProps) {
const { pathname, query } = this.props.router
// verify props have changed to avoid an infinite loop
if (query.id !== prevProps.router.query.id) {
// fetch data based on the new query
}
}
注意:
淺層路由只作用于相同 URL 的參數(shù)改變衬潦,比如我們假定有個(gè)其他路由
about
斤蔓,而你向下面代碼樣運(yùn)行:Router.push('/?counter=10', '/about?counter=10', { shallow: true })
那么這將會(huì)出現(xiàn)新頁面,即使我們加了淺層路由别渔,但是它還是會(huì)卸載當(dāng)前頁附迷,會(huì)加載新的頁面并觸發(fā)新頁面的
getInitialProps
惧互。
<a id="using-a-higher-order-component"></a>
高階組件
<p><details>
<summary markdown="span"><b>Examples</b></summary>
<ul>
<li><a >Using the withRouter
utility</a></li>
</ul>
</details></p>
如果你想應(yīng)用里每個(gè)組件都處理路由對象哎媚,你可以使用withRouter
高階組件。下面是如何使用它:
import { withRouter } from 'next/router'
const ActiveLink = ({ children, router, href }) => {
const style = {
marginRight: 10,
color: router.pathname === href? 'red' : 'black'
}
const handleClick = (e) => {
e.preventDefault()
router.push(href)
}
return (
<a href={href} onClick={handleClick} style={style}>
{children}
</a>
)
}
export default withRouter(ActiveLink)
上面路由對象的 API 可以參考next/router
.
<a id="prefetching-pages"></a>
預(yù)加載頁面
?? 只有生產(chǎn)環(huán)境才有此功能 ??
<p><details>
<summary markdown="span"><b>Examples</b></summary>
<ul><li><a >Prefetching</a></li></ul>
</details></p>
Next.js 有允許你預(yù)加載頁面的 API喊儡。
用 Next.js 服務(wù)端渲染你的頁面拨与,可以達(dá)到所有你應(yīng)用里所有未來會(huì)跳轉(zhuǎn)的路徑即時(shí)響應(yīng),有效的應(yīng)用 Next.js艾猜,可以通過預(yù)加載應(yīng)用程序的功能买喧,最大程度的初始化網(wǎng)站性能。查看更多.
Next.js 的預(yù)加載功能只預(yù)加載 JS 代碼匆赃。當(dāng)頁面渲染時(shí)淤毛,你可能需要等待數(shù)據(jù)請求。
<a id="with-link-1"></a>
<Link>
用法
你可以給<Link>添加 prefetch
屬性算柳,Next.js 將會(huì)在后臺(tái)預(yù)加載這些頁面低淡。
import Link from 'next/link'
// example header component
export default () =>
<nav>
<ul>
<li>
<Link prefetch href="/">
<a>Home</a>
</Link>
</li>
<li>
<Link prefetch href="/about">
<a>About</a>
</Link>
</li>
<li>
<Link prefetch href="/contact">
<a>Contact</a>
</Link>
</li>
</ul>
</nav>
<a id="imperatively-1"></a>
命令式 prefetch 寫法
大多數(shù)預(yù)加載是通過<Link />處理的,但是我們還提供了命令式 API 用于更復(fù)雜的場景瞬项。
import { withRouter } from 'next/router'
export default withRouter(({ router }) =>
<div>
<a onClick={() => setTimeout(() => router.push('/dynamic'), 100)}>
A route transition will happen after 100ms
</a>
{// but we can prefetch it!
router.prefetch('/dynamic')}
</div>
)
路由實(shí)例只允許在應(yīng)用程序的客戶端蔗蹋。以防服務(wù)端渲染發(fā)生錯(cuò)誤,建議 prefetch 事件寫在componentDidMount()
生命周期里囱淋。
import React from 'react'
import { withRouter } from 'next/router'
class MyLink extends React.Component {
componentDidMount() {
const { router } = this.props
router.prefetch('/dynamic')
}
render() {
const { router } = this.props
return (
<div>
<a onClick={() => setTimeout(() => router.push('/dynamic'), 100)}>
A route transition will happen after 100ms
</a>
</div>
)
}
}
export default withRouter(MyLink)
<a id="custom-server-and-routing"></a>
自定義服務(wù)端路由
<p><details>
<summary markdown="span"><b>Examples</b></summary>
<ul>
<li><a >Basic custom server</a></li>
<li><a >Express integration</a></li>
<li><a >Hapi integration</a></li>
<li><a >Koa integration</a></li>
<li><a >Parameterized routing</a></li>
<li><a >SSR caching</a></li>
</ul>
</details></p>
一般你使用next start
命令來啟動(dòng) next 服務(wù)猪杭,你還可以編寫代碼來自定義路由,如使用路由正則等妥衣。
當(dāng)使用自定義服務(wù)文件皂吮,如下面例子所示叫 server.js 時(shí)戒傻,確保你更新了 package.json 中的腳本。
{
"scripts": {
"dev": "node server.js",
"build": "next build",
"start": "NODE_ENV=production node server.js"
}
}
下面這個(gè)例子使 /a
路由解析為./pages/b
蜂筹,以及/b
路由解析為./pages/a
;
// This file doesn't go through babel or webpack transformation.
// Make sure the syntax and sources this file requires are compatible with the current node version you are running
// See https://github.com/zeit/next.js/issues/1245 for discussions on Universal Webpack or universal Babel
const { createServer } = require('http')
const { parse } = require('url')
const next = require('next')
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare().then(() => {
createServer((req, res) => {
// Be sure to pass `true` as the second argument to `url.parse`.
// This tells it to parse the query portion of the URL.
const parsedUrl = parse(req.url, true)
const { pathname, query } = parsedUrl
if (pathname === '/a') {
app.render(req, res, '/b', query)
} else if (pathname === '/b') {
app.render(req, res, '/a', query)
} else {
handle(req, res, parsedUrl)
}
}).listen(3000, err => {
if (err) throw err
console.log('> Ready on http://localhost:3000')
})
})
next
的 API 如下所示
next(opts: object)
opts 的屬性如下:
-
dev
(boolean
) 判斷 Next.js 應(yīng)用是否在開發(fā)環(huán)境 - 默認(rèn)false
-
dir
(string
) Next 項(xiàng)目路徑 - 默認(rèn)'.'
-
quiet
(boolean
) 是否隱藏包含服務(wù)端消息在內(nèi)的錯(cuò)誤信息 - 默認(rèn)false
-
conf
(object
) 與next.config.js
的對象相同 - 默認(rèn){}
生產(chǎn)環(huán)境的話稠鼻,可以更改 package.json 里的start
腳本為NODE_ENV=production node server.js
。
<a id="disabling-file-system-routing"></a>
禁止文件路由
默認(rèn)情況狂票,Next
將會(huì)把/pages
下的所有文件匹配路由(如/pages/some-file.js
渲染為 site.com/some-file
)
如果你的項(xiàng)目使用自定義路由候齿,那么有可能不同的路由會(huì)得到相同的內(nèi)容,可以優(yōu)化 SEO 和用戶體驗(yàn)闺属。
禁止路由鏈接到/pages
下的文件慌盯,只需設(shè)置next.config.js
文件如下所示:
// next.config.js
module.exports = {
useFileSystemPublicRoutes: false
}
注意useFileSystemPublicRoutes
只禁止服務(wù)端的文件路由;但是客戶端的還是禁止不了掂器。
你如果想配置客戶端路由不能跳轉(zhuǎn)文件路由亚皂,可以參考Intercepting popstate
。
<a id="dynamic-assetprefix"></a>
動(dòng)態(tài)前綴
有時(shí)你需要設(shè)置動(dòng)態(tài)前綴国瓮,可以在請求時(shí)設(shè)置assetPrefix
改變前綴灭必。
使用方法如下:
const next = require('next')
const micro = require('micro')
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handleNextRequests = app.getRequestHandler()
app.prepare().then(() => {
const server = micro((req, res) => {
// Add assetPrefix support based on the hostname
if (req.headers.host === 'my-app.com') {
app.setAssetPrefix('http://cdn.com/myapp')
} else {
app.setAssetPrefix('')
}
handleNextRequests(req, res)
})
server.listen(port, (err) => {
if (err) {
throw err
}
console.log(`> Ready on http://localhost:${port}`)
})
})
<a id="dynamic-import"></a>
動(dòng)態(tài)導(dǎo)入
<p><details>
<summary markdown="span"><b>Examples</b></summary>
<ul>
<li><a >With Dynamic Import</a></li>
</ul>
</details></p>
ext.js 支持 JavaScript 的 TC39 提議dynamic import proposal。你可以動(dòng)態(tài)導(dǎo)入 JavaScript 模塊(如 React 組件)乃摹。
動(dòng)態(tài)導(dǎo)入相當(dāng)于把代碼分成各個(gè)塊管理禁漓。Next.js 服務(wù)端動(dòng)態(tài)導(dǎo)入功能,你可以做很多炫酷事情孵睬。
下面介紹一些動(dòng)態(tài)導(dǎo)入方式:
<a id="1-basic-usage-also-does-ssr"></a>
1. 基礎(chǔ)支持 (同樣支持 SSR)
import dynamic from 'next/dynamic'
const DynamicComponent = dynamic(import('../components/hello'))
export default () =>
<div>
<Header />
<DynamicComponent />
<p>HOME PAGE is here!</p>
</div>
<a id="2-with-custom-loading-componen"></a>
2. 自定義加載組件
import dynamic from 'next/dynamic'
const DynamicComponentWithCustomLoading = dynamic(
import('../components/hello2'),
{
loading: () => <p>...</p>
}
)
export default () =>
<div>
<Header />
<DynamicComponentWithCustomLoading />
<p>HOME PAGE is here!</p>
</div>
<a id="3-with-no-ssr"></a>
3. 禁止使用 SSR
import dynamic from 'next/dynamic'
const DynamicComponentWithNoSSR = dynamic(import('../components/hello3'), {
ssr: false
})
export default () =>
<div>
<Header />
<DynamicComponentWithNoSSR />
<p>HOME PAGE is here!</p>
</div>
<a id="4-with-multiple-modules-at-once"></a>
4. 同時(shí)加載多個(gè)模塊
import dynamic from 'next/dynamic'
const HelloBundle = dynamic({
modules: () => {
const components = {
Hello1: import('../components/hello1'),
Hello2: import('../components/hello2')
}
return components
},
render: (props, { Hello1, Hello2 }) =>
<div>
<h1>
{props.title}
</h1>
<Hello1 />
<Hello2 />
</div>
})
export default () => <HelloBundle title="Dynamic Bundle" />
<a id="custom-app"></a>
自定義 <App>
<p><details>
<summary markdown="span"><b>Examples</b></summary>
<ul><li><a >Using _app.js
for layout</a></li></ul>
<ul><li><a >Using _app.js
to override componentDidCatch
</a></li></ul>
</details></p>
組件來初始化頁面播歼。你可以重寫它來控制頁面初始化,如下面的事:
- 當(dāng)頁面變化時(shí)保持頁面布局
- 當(dāng)路由變化時(shí)保持頁面狀態(tài)
- 使用
componentDidCatch
自定義處理錯(cuò)誤 - 注入額外數(shù)據(jù)到頁面里 (如 GraphQL 查詢)
重寫的話掰读,新建./pages/_app.js
文件秘狞,重寫 App 模塊如下所示:
import App, {Container} from 'next/app'
import React from 'react'
export default class MyApp extends App {
static async getInitialProps ({ Component, router, ctx }) {
let pageProps = {}
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx)
}
return {pageProps}
}
render () {
const {Component, pageProps} = this.props
return <Container>
<Component {...pageProps} />
</Container>
}
}
<a id="custom-document"></a>
自定義 <Document>
<p><details>
<summary markdown="span"><b>Examples</b></summary>
<ul><li><a >Styled components custom document</a></li></ul>
<ul><li><a >Google AMP</a></li></ul>
</details></p>
- 在服務(wù)端呈現(xiàn)
- 初始化服務(wù)端時(shí)添加文檔標(biāo)記元素
- 通常實(shí)現(xiàn)服務(wù)端渲染會(huì)使用一些 css-in-js 庫,如styled-components, glamorous 或 emotion蹈集。styled-jsx是 Next.js 自帶默認(rèn)使用的 css-in-js 庫
Next.js
會(huì)自動(dòng)定義文檔標(biāo)記烁试,比如,你從來不需要添加<html>
, <body>
等拢肆。如果想自定義文檔標(biāo)記减响,你可以新建./pages/_document.js
,然后擴(kuò)展Document
類:
// _document is only rendered on the server side and not on the client side
// Event handlers like onClick can't be added to this file
// ./pages/_document.js
import Document, { Head, Main, NextScript } from 'next/document'
export default class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx)
return { ...initialProps }
}
render() {
return (
<html>
<Head>
<style>{`body { margin: 0 } /* custom! */`}</style>
</Head>
<body className="custom_class">
<Main />
<NextScript />
</body>
</html>
)
}
}
鉤子getInitialProps
接收到的參數(shù)ctx
對象都是一樣的
- 回調(diào)函數(shù)
renderPage
是會(huì)執(zhí)行 React 渲染邏輯的函數(shù)(同步)善榛,這種做法有助于此函數(shù)支持一些類似于 Aphrodite 的 renderStatic 等一些服務(wù)器端渲染容器辩蛋。
注意:<Main />
外的 React 組件將不會(huì)渲染到瀏覽器中,所以那添加應(yīng)用邏輯代碼移盆。如果你頁面需要公共組件(菜單或工具欄)悼院,可以參照上面說的App
組件代替。
<a id="custom-error-handling"></a>
自定義錯(cuò)誤處理
404和500錯(cuò)誤客戶端和服務(wù)端都會(huì)通過error.js
組件處理咒循。如果你想改寫它据途,則新建_error.js
在文件夾中:
import React from 'react'
export default class Error extends React.Component {
static getInitialProps({ res, err }) {
const statusCode = res ? res.statusCode : err ? err.statusCode : null;
return { statusCode }
}
render() {
return (
<p>
{this.props.statusCode
? `An error ${this.props.statusCode} occurred on server`
: 'An error occurred on client'}
</p>
)
}
}
<a id="reusing-the-built-in-error-page"></a>
渲染內(nèi)置錯(cuò)誤頁面
如果你想渲染內(nèi)置錯(cuò)誤頁面绞愚,你可以使用next/error
:
import React from 'react'
import Error from 'next/error'
import fetch from 'isomorphic-unfetch'
export default class Page extends React.Component {
static async getInitialProps() {
const res = await fetch('https://api.github.com/repos/zeit/next.js')
const statusCode = res.statusCode > 200 ? res.statusCode : false
const json = await res.json()
return { statusCode, stars: json.stargazers_count }
}
render() {
if (this.props.statusCode) {
return <Error statusCode={this.props.statusCode} />
}
return (
<div>
Next stars: {this.props.stars}
</div>
)
}
}
如果你自定義了個(gè)錯(cuò)誤頁面,你可以引入自己的錯(cuò)誤頁面來代替
next/error
<a id="custom-configuration"></a>
自定義配置
如果你想自定義 Next.js 的高級配置颖医,可以在根目錄下新建next.config.js
文件(與pages/
和 package.json
一起)
注意:next.config.js
是一個(gè) Node.js 模塊位衩,不是一個(gè) JSON 文件,可以用于 Next 啟動(dòng)服務(wù)已經(jīng)構(gòu)建階段熔萧,但是不作用于瀏覽器端糖驴。
// next.config.js
module.exports = {
/* config options here */
}
或使用一個(gè)函數(shù):
module.exports = (phase, {defaultConfig}) => {
//
// https://github.com/zeit/
return {
/* config options here */
}
}
phase
是配置文件被加載時(shí)的當(dāng)前內(nèi)容。你可看到所有的 phases 常量:constants
這些常量可以通過next/constants
引入:
const {PHASE_DEVELOPMENT_SERVER} = require('next/constants')
module.exports = (phase, {defaultConfig}) => {
if(phase === PHASE_DEVELOPMENT_SERVER) {
return {
/* development only config options here */
}
}
return {
/* config options for all phases except development here */
}
}
<a id="setting-a-custom-build-directory"></a>
設(shè)置自定義構(gòu)建目錄
你可以自定義一個(gè)構(gòu)建目錄佛致,如新建build
文件夾來代替.next
文件夾成為構(gòu)建目錄贮缕。如果沒有配置構(gòu)建目錄,構(gòu)建時(shí)將會(huì)自動(dòng)新建.next
文件夾
// next.config.js
module.exports = {
distDir: 'build'
}
<a id="disabling-etag-generation"></a>
禁止 etag 生成
你可以禁止 etag 生成根據(jù)你的緩存策略俺榆。如果沒有配置感昼,Next 將會(huì)生成 etags 到每個(gè)頁面中。
// next.config.js
module.exports = {
generateEtags: false
}
<a id="configuring-the-ondemandentries"></a>
配置 onDemandEntries
Next 暴露一些選項(xiàng)來給你控制服務(wù)器部署以及緩存頁面:
module.exports = {
onDemandEntries: {
// period (in ms) where the server will keep pages in the buffer
maxInactiveAge: 25 * 1000,
// number of pages that should be kept simultaneously without being disposed
pagesBufferLength: 2,
}
}
這個(gè)只是在開發(fā)環(huán)境才有的功能罐脊。如果你在生成環(huán)境中想緩存 SSR 頁面定嗓,請查看SSR-caching
<a id="configuring-extensions-looked-for-when-resolving-pages-in-pages"></a>
配置頁面后綴名解析擴(kuò)展
如 typescript 模塊@zeit/next-typescript
,需要支持解析后綴名為.ts
的文件萍桌。pageExtensions
允許你擴(kuò)展后綴名來解析各種 pages 下的文件宵溅。
// next.config.js
module.exports = {
pageExtensions: ['jsx', 'js']
}
<a id="configuring-the-build-id"></a>
配置構(gòu)建 ID
Next.js 使用構(gòu)建時(shí)生成的常量來標(biāo)識(shí)你的應(yīng)用服務(wù)是哪個(gè)版本。在每臺(tái)服務(wù)器上運(yùn)行構(gòu)建命令時(shí)梗夸,可能會(huì)導(dǎo)致多服務(wù)器部署出現(xiàn)問題层玲。為了保持同一個(gè)構(gòu)建 ID号醉,可以配置generateBuildId
函數(shù):
// next.config.js
module.exports = {
generateBuildId: async () => {
// For example get the latest git commit hash here
return 'my-build-id'
}
}
<a id="customizing-webpack-config"></a>
自定義 webpack 配置
<p><details>
<summary markdown="span"><b>Examples</b></summary>
<ul><li><a >Custom webpack bundle analyzer</a></li></ul>
</details></p>
可以使用些一些常見的模塊
注意: webpack
方法將被執(zhí)行兩次反症,一次在服務(wù)端一次在客戶端。你可以用isServer
屬性區(qū)分客戶端和服務(wù)端來配置
多配置可以組合在一起畔派,如:
const withTypescript = require('@zeit/next-typescript')
const withSass = require('@zeit/next-sass')
module.exports = withTypescript(withSass({
webpack(config, options) {
// Further custom configuration here
return config
}
}))
為了擴(kuò)展webpack
使用铅碍,可以在next.config.js
定義函數(shù)。
// next.config.js is not transformed by Babel. So you can only use javascript features supported by your version of Node.js.
module.exports = {
webpack: (config, { buildId, dev, isServer, defaultLoaders }) => {
// Perform customizations to webpack config
// Important: return the modified config
return config
},
webpackDevMiddleware: config => {
// Perform customizations to webpack dev middleware config
// Important: return the modified config
return config
}
}
webpack
的第二個(gè)參數(shù)是個(gè)對象线椰,你可以自定義配置它胞谈,對象屬性如下所示:
-
buildId
- 字符串類型,構(gòu)建的唯一標(biāo)示 -
dev
-Boolean
型憨愉,判斷你是否在開發(fā)環(huán)境下 -
isServer
-Boolean
型烦绳,為true
使用在服務(wù)端, 為false
使用在客戶端. -
defaultLoaders
- 對象型 ,內(nèi)部加載器, 你可以如下配置-
babel
- 對象型配紫,配置babel-loader
. -
hotSelfAccept
- 對象型径密,hot-self-accept-loader
配置選項(xiàng).這個(gè)加載器只能用于高階案例。如@zeit/next-typescript
添加頂層 typescript 頁面躺孝。
-
defaultLoaders.babel
使用案例如下:
// Example next.config.js for adding a loader that depends on babel-loader
// This source was taken from the @zeit/next-mdx plugin source:
// https://github.com/zeit/next-plugins/blob/master/packages/next-mdx
module.exports = {
webpack: (config, {}) => {
config.module.rules.push({
test: /\.mdx/,
use: [
options.defaultLoaders.babel,
{
loader: '@mdx-js/loader',
options: pluginOptions.options
}
]
})
return config
}
}
<a id="customizing-babel-config"></a>
自定義 babel 配置
<p><details>
<summary markdown="span"><b>Examples</b></summary>
<ul><li><a >Custom babel configuration</a></li></ul>
</details></p>
為了擴(kuò)展方便我們使用babel
享扔,可以在應(yīng)用根目錄新建.babelrc
文件底桂,該文件可配置。
如果有該文件惧眠,我們將會(huì)考慮數(shù)據(jù)源籽懦,因此也需要定義 next 項(xiàng)目需要的東西,也就是 next/babel
預(yù)設(shè)氛魁。
這種設(shè)計(jì)方案將會(huì)使你不詫異于我們可以定制 babel 配置暮顺。
下面是.babelrc
文件案例:
{
"presets": ["next/babel"],
"plugins": []
}
next/babel
預(yù)設(shè)可處理各種 React 應(yīng)用所需要的情況。包括:
- preset-env
- preset-react
- plugin-proposal-class-properties
- plugin-proposal-object-rest-spread
- plugin-transform-runtime
- styled-jsx
presets / plugins 不允許添加到.babelrc
中秀存,然而你可以配置next/babel
預(yù)設(shè):
{
"presets": [
["next/babel", {
"preset-env": {},
"transform-runtime": {},
"styled-jsx": {},
"class-properties": {}
}]
],
"plugins": []
}
"preset-env"
模塊選項(xiàng)應(yīng)該保持為 false拖云,否則 webpack 代碼分割將被禁用。
<a id="exposing-configuration-to-the-server--client-side"></a>
暴露配置到服務(wù)端和客戶端
next/config
模塊使你應(yīng)用運(yùn)行時(shí)可以讀取些存儲(chǔ)在next.config.js
的配置項(xiàng)应又。serverRuntimeConfig
屬性只在服務(wù)器端可用宙项,publicRuntimeConfig
屬性在服務(wù)端和客戶端可用。
// next.config.js
module.exports = {
serverRuntimeConfig: { // Will only be available on the server side
mySecret: 'secret'
},
publicRuntimeConfig: { // Will be available on both server and client
staticFolder: '/static',
mySecret: process.env.MY_SECRET // Pass through env variables
}
}
// pages/index.js
import getConfig from 'next/config'
// Only holds serverRuntimeConfig and publicRuntimeConfig from next.config.js nothing else.
const {serverRuntimeConfig, publicRuntimeConfig} = getConfig()
console.log(serverRuntimeConfig.mySecret) // Will only be available on the server side
console.log(publicRuntimeConfig.staticFolder) // Will be available on both server and client
export default () => <div>
<img src={`${publicRuntimeConfig.staticFolder}/logo.png`} alt="logo" />
</div>
<a id="starting-the-server-on-alternative-hostname"></a>
啟動(dòng)服務(wù)選擇 hostname
啟動(dòng)開發(fā)環(huán)境服務(wù)可以設(shè)置不同的 hostname株扛,你可以在啟動(dòng)命令后面加上--hostname 主機(jī)名
或 -H 主機(jī)名
尤筐。它將會(huì)啟動(dòng)一個(gè) TCP 服務(wù)器來監(jiān)聽連接所提供的主機(jī)。
<a id="cdn-support-with-asset-prefix"></a>
CDN 支持前綴
建立一個(gè) CDN洞就,你能配置assetPrefix
選項(xiàng)盆繁,去配置你的 CDN 源。
const isProd = process.env.NODE_ENV === 'production'
module.exports = {
// You may only need to add assetPrefix in the production.
assetPrefix: isProd ? 'https://cdn.mydomain.com' : ''
}
注意:Next.js 運(yùn)行時(shí)將會(huì)自動(dòng)添加前綴旬蟋,但是對于/static
是沒有效果的油昂,如果你想這些靜態(tài)資源也能使用 CDN,你需要自己添加前綴倾贰。有一個(gè)方法可以判斷你的環(huán)境來加前綴冕碟,如 in this example。
<a id="production-deployment"></a>
項(xiàng)目部署
部署中匆浙,你可以先構(gòu)建打包生成環(huán)境代碼安寺,再啟動(dòng)服務(wù)。因此首尼,構(gòu)建和啟動(dòng)分為下面兩條命令:
next build
next start
例如挑庶,使用now
去部署package.json
配置文件如下:
{
"name": "my-app",
"dependencies": {
"next": "latest"
},
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
}
}
然后就可以直接運(yùn)行now
了。
Next.js 也有其他托管解決方案软能。請查考 wiki 章節(jié)'Deployment' 迎捺。
注意:NODE_ENV
可以通過next
命令配置,如果沒有配置查排,會(huì)最大渲染凳枝,如果你使用編程式寫法的話programmatically,你需要手動(dòng)設(shè)置NODE_ENV=production
雹嗦。
注意:推薦將.next
或自定義打包文件夾custom dist folder放入.gitignore
或 .npmignore
中范舀。否則合是,使用files
或 now.files
添加部署白名單,并排除.next
或自定義打包文件夾锭环。
<a id="browser-support"></a>
瀏覽器支持
Next.js 支持 IE11 和所有的現(xiàn)代瀏覽器使用了@babel/preset-env
聪全。為了支持 IE11,Next.js 需要全局添加Promise
的 polyfill辅辩。有時(shí)你的代碼或引入的其他 NPM 包的部分功能現(xiàn)代瀏覽器不支持难礼,則需要用 polyfills 去實(shí)現(xiàn)。
ployflls 實(shí)現(xiàn)案例為polyfills玫锋。
<a id="static-html-export"></a>
導(dǎo)出靜態(tài)頁面
<p><details>
<summary markdown="span"><b>Examples</b></summary>
<ul><li><a >Static export</a></li></ul>
</details></p>
next export
可以輸出一個(gè) Next.js 應(yīng)用作為靜態(tài)資源應(yīng)用而不依靠 Node.js 服務(wù)蛾茉。
這個(gè)輸出的應(yīng)用幾乎支持 Next.js 的所有功能,包括動(dòng)態(tài)路由撩鹿,預(yù)獲取谦炬,預(yù)加載以及動(dòng)態(tài)導(dǎo)入。
next export
將把所有有可能渲染出的 HTML 都生成节沦。這是基于映射對象的pathname
關(guān)鍵字關(guān)聯(lián)到頁面對象键思。這個(gè)映射叫做exportPathMap
。
頁面對象有2個(gè)屬性:
-
page
- 字符串類型甫贯,頁面生成目錄 -
query
- 對象類型吼鳞,當(dāng)預(yù)渲染時(shí),query
對象將會(huì)傳入頁面的生命周期getInitialProps
中叫搁。默認(rèn)為{}
赔桌。
<a id="usage"></a>
使用
通常開發(fā) Next.js 應(yīng)用你將會(huì)運(yùn)行:
next build
next export
next export
命令默認(rèn)不需要任何配置,將會(huì)自動(dòng)生成默認(rèn)exportPathMap
生成pages
目錄下的路由你頁面渴逻。
如果你想動(dòng)態(tài)配置路由疾党,可以在next.config.js
中添加異步函數(shù)exportPathMap
。
// next.config.js
module.exports = {
exportPathMap: async function (defaultPathMap) {
return {
'/': { page: '/' },
'/about': { page: '/about' },
'/readme.md': { page: '/readme' },
'/p/hello-nextjs': { page: '/post', query: { title: 'hello-nextjs' } },
'/p/learn-nextjs': { page: '/post', query: { title: 'learn-nextjs' } },
'/p/deploy-nextjs': { page: '/post', query: { title: 'deploy-nextjs' } }
}
}
}
注意:如果 path 的結(jié)尾是目錄名裸卫,則將導(dǎo)出
/dir-name/index.html
仿贬,但是如果結(jié)尾有擴(kuò)展名,將會(huì)導(dǎo)出對應(yīng)的文件墓贿,如上/readme.md
。如果你使用.html
以外的擴(kuò)展名解析文件時(shí)蜓氨,你需要設(shè)置 header 的Content-Type
頭為"text/html".
輸入下面命令:
next build
next export
你可以在package.json
添加一個(gè) NPM 腳本聋袋,如下所示:
{
"scripts": {
"build": "next build",
"export": "npm run build && next export"
}
}
接著只用執(zhí)行一次下面命令:
npm run export
然后你將會(huì)有一個(gè)靜態(tài)頁面應(yīng)用在out
目錄下。
你也可以自定義輸出目錄穴吹∮睦眨可以運(yùn)行
next export -h
命令查看幫助。
現(xiàn)在你可以部署out
目錄到任意靜態(tài)資源服務(wù)器上港令。注意如果部署 GitHub Pages 需要加個(gè)額外的步驟啥容,文檔如下
例如锈颗,訪問out
目錄并用下面命令部署應(yīng)用ZEIT Now.
now
<a id="limitation"></a>
限制
使用next export
,我們創(chuàng)建了個(gè)靜態(tài) HTML 應(yīng)用咪惠。構(gòu)建時(shí)將會(huì)運(yùn)行頁面里生命周期getInitialProps
函數(shù)击吱。
req
和res
只在服務(wù)端可用,不能通過getInitialProps
遥昧。
所以你不能預(yù)構(gòu)建 HTML 文件時(shí)動(dòng)態(tài)渲染 HTML 頁面覆醇。如果你想動(dòng)態(tài)渲染可以運(yùn)行
next start
或其他自定義服務(wù)端 API。
<a id="multi-zones"></a>
多 zone
<p><details>
<summary markdown="span"><b>Examples</b></summary>
<ul><li><a >With Zones</a></li></ul>
</details></p>
一個(gè) zone 時(shí)一個(gè)單獨(dú)的 Next.js 應(yīng)用炭臭。如果你有很多 zone永脓,你可以合并成一個(gè)應(yīng)用。
例如鞋仍,你如下有兩個(gè) zone:
-
https://docs.my-app.com 服務(wù)于路由
/docs/**
- https://ui.my-app.com 服務(wù)于所有頁面
有多 zone 應(yīng)用技術(shù)支持常摧,你可以將幾個(gè)應(yīng)用合并到一個(gè),而且可以自定義 URL 路徑威创,使你能同時(shí)單獨(dú)開發(fā)各個(gè)應(yīng)用排宰。
與 microservices 觀念類似, 只是應(yīng)用于前端應(yīng)用.
<a id="how-to-define-a-zone"></a>
怎么定義一個(gè) zone
zone 沒有單獨(dú)的 API 文檔。你需要做下面事即可:
- 確保你的應(yīng)用里只有需要的頁面 (例如, https://ui.my-app.com 不包含
/docs/**
) - 確保你的應(yīng)用有個(gè)前綴assetPrefix那婉。(你也可以定義動(dòng)態(tài)前綴dynamically)
<a id="how-to-merge-them"></a>
怎么合并他們
你能使用 HTTP 代理合并 zone
你能使用代理micro proxy來作為你的本地代理服務(wù)板甘。它允許你定義路由規(guī)則如下:
{
"rules": [
{"pathname": "/docs**", "method":["GET", "POST", "OPTIONS"], "dest": "https://docs.my-app.com"},
{"pathname": "/**", "dest": "https://ui.my-app.com"}
]
}
生產(chǎn)環(huán)境部署,如果你使用了ZEIT now详炬,可以它的使用path alias 功能盐类。否則,你可以設(shè)置你已使用的代理服務(wù)編寫上面規(guī)則來路由 HTML 頁面
<a id="recipes"></a>
技巧
- 設(shè)置301重定向
- 只處理服務(wù)器端模塊
- 構(gòu)建項(xiàng)目 React-Material-UI-Next-Express-Mongoose-Mongodb
- 構(gòu)建一個(gè) SaaS 產(chǎn)品 React-Material-UI-Next-MobX-Express-Mongoose-MongoDB-TypeScript
<a id="faq"></a>
問答
<details>
<summary markdown="span">這個(gè)產(chǎn)品可以用于生產(chǎn)環(huán)境嗎呛谜?</summary>
<div markdown="span">
https://zeit.co 都是一直用 Next.js 寫的在跳。
它的開發(fā)體驗(yàn)和終端用戶體驗(yàn)都很好,所以我們決定開源出來給大家共享隐岛。
</div>
</details>
<details>
<summary markdown="span">體積多大猫妙?</summary>
<div markdown="span">
客戶端大小根據(jù)應(yīng)用需求不一樣大小也不一樣。
一個(gè)最簡單 Next 應(yīng)該用 gzip 壓縮后大約65kb
</div>
</details>
<details >
<summary markdown="span">這個(gè)像 create-react-app
?</summary>
<div markdown="span">
是或不是.
是聚凹,因?yàn)樗屇愕?SSR 開發(fā)更簡單割坠。
不是,因?yàn)樗?guī)定了一定的目錄結(jié)構(gòu)妒牙,使我們能做以下更高級的事:
- 服務(wù)端渲染
- 自動(dòng)代碼分割
此外彼哼,Next.js 還提供兩個(gè)內(nèi)置特性:
- 路由與懶加載組件:
<Link>
(通過引入next/link
) - 修改
<head>
的組件:<Head>
(通過引入next/head
)
如果你想寫共用組件,可以嵌入 Next.js 應(yīng)用和 React 應(yīng)用中湘今,推薦使用create-react-app
敢朱。你可以更改import
保持代碼清晰。
</div>
</details>
<details>
<summary markdown="span">怎么解決 CSS 嵌入 JS 問題?</summary>
<div markdown="span">
Next.js 自帶styled-jsx庫支持 CSS 嵌入 JS。而且你可以選擇其他嵌入方法到你的項(xiàng)目中拴签,可參考文檔as mentioned before孝常。
</div>
</details>
<details>
<summary markdown="span">哪些語法會(huì)被轉(zhuǎn)換?怎么轉(zhuǎn)換它們蚓哩?</summary>
<div markdown="span">
我們遵循 V8 引擎的构灸,如今 V8 引擎廣泛支持 ES6 語法以及async
和await
語法,所以我們支持轉(zhuǎn)換它們杖剪。但是 V8 引擎不支持修飾器語法冻押,所以我們也不支持轉(zhuǎn)換這語法。
可以參照這些 以及 這些
</div>
</details>
<details>
<summary markdown="span">為什么使用新路由?</summary>
<div markdown="span">
Next.js 的特別之處如下所示:
- 路由不需要被提前知道
- 路由總是被懶加載
- 頂層組件可以定義生命周期
getInitialProps
來阻止路由加載(當(dāng)服務(wù)端渲染或路由懶加載時(shí))
因此,我們可以介紹一個(gè)非常簡單的路由方法,它由下面兩部分組成:
- 每個(gè)頂層組件都將會(huì)收到一個(gè)
url
對象盛嘿,來檢查 url 或修改歷史記錄 -
<Link />
組件用于包裝如(<a/>
)標(biāo)簽的元素容器洛巢,來執(zhí)行客戶端轉(zhuǎn)換。
我們使用了些有趣的場景來測試路由的靈活性次兆,例如稿茉,可查看nextgram。
</div>
</details>
<details>
<summary markdown="span">我怎么定義自定義路由?</summary>
<div markdown="span">
我們通過請求處理來添加任意 URL 與任意組件之前的映射關(guān)系芥炭。
在客戶端漓库,我們<Link>
組件有個(gè)屬性as
,可以裝飾改變獲取到的 URL园蝠。
</div>
</details>
<details>
<summary markdown="span">怎么獲取數(shù)據(jù)?</summary>
<div markdown="span">
這由你決定渺蒿。getInitialProps
是一個(gè)異步函數(shù)async
(也就是函數(shù)將會(huì)返回個(gè)Promise
)恋拍。你可以在任意位置獲取數(shù)據(jù)遭笋。
</div>
</details>
<details>
<summary markdown="span">我可以使用 GraphQL 嗎?</summary>
<div markdown="span">
是的! 這里有個(gè)例子Apollo.
</div>
</details>
<details>
<summary markdown="span">我可以使用 Redux 嗎?</summary>
<div markdown="span">
是的! 這里有個(gè)例子
</div>
</details>
<details>
<summary markdown="span">我可以在 Next 應(yīng)用中使用我喜歡的 Javascript 庫或工具包嗎?</summary>
<div markdown="span">
從我們第一次發(fā)版就已經(jīng)提供很多例子顶伞,你可以查看這些例子抗愁。
</div>
</details>
<details>
<summary markdown="span">什么啟發(fā)我們做這個(gè)?</summary>
<div markdown="span">
我們實(shí)現(xiàn)的大部分目標(biāo)都是通過 Guillermo Rauch 的Web 應(yīng)用的7原則來啟發(fā)出的。
PHP 的易用性也是個(gè)很好的靈感來源声功,我們覺得 Next.js 可以替代很多需要用 PHP 輸出 HTML 的場景幻妓。
與 PHP 不同的是疆偿,我們得利于 ES6 模塊系統(tǒng)易遣,每個(gè)文件會(huì)輸出一個(gè)組件或方法彼妻,以便可以輕松的導(dǎo)入用于懶加載和測試
我們研究 React 的服務(wù)器渲染時(shí)并沒有花費(fèi)很大的步驟,因?yàn)槲覀儼l(fā)現(xiàn)一個(gè)類似于 Next.js 的產(chǎn)品豆茫,React 作者 Jordan Walke 寫的react-page (現(xiàn)在已經(jīng)廢棄)
</div>
</details>
<a id="contributing"></a>
貢獻(xiàn)
可查看 contributing.md
<a id="authors"></a>
作者
- Arunoda Susiripala (@arunoda) – ZEIT
- Tim Neutkens (@timneutkens) – ZEIT
- Naoyuki Kanezawa (@nkzawa) – ZEIT
- Tony Kovanen (@tonykovanen) – ZEIT
- Guillermo Rauch (@rauchg) – ZEIT
- Dan Zajdband (@impronunciable) – Knight-Mozilla / Coral Project