Nextjs中文文檔

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。




<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, MapSet類型僧鲁。

當(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á)到頁面的最佳性能硝全。

客戶端路由行為與瀏覽器很相似:

  1. 組件獲取
  2. 如果組件定義了getInitialProps栖雾,數(shù)據(jù)獲取了。如果有錯(cuò)誤情況將會(huì)渲染 _error.js伟众。
  3. 1和2都完成了析藕,pushState執(zhí)行,新組件被渲染凳厢。

如果需要注入pathname, queryasPath到你組件中账胧,你可以使用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 a replaceState call with the given url
  • beforePopState(cb=function) - 在路由器處理事件之前攔截.

pushreplace 函數(shù)的第二個(gè)參數(shù)as探越,是為了裝飾 URL 作用。如果你在服務(wù)器端設(shè)置了自定義路由將會(huì)起作用窑业。

<a id="with-url-object-1"></a>

URL 對象用法

pushreplace可接收的 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,得到更新后的路由屬性pathnamequery相种,并不失去 state 狀態(tài)威恼。

你可以給Router.pushRouter.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, glamorousemotion蹈集。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中范舀。否則合是,使用filesnow.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ù)击吱。

reqres只在服務(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:

有多 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>

技巧

<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 語法以及asyncawait語法,所以我們支持轉(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>

作者

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末侨歉,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子澜薄,更是在濱河造成了極大的恐慌为肮,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肤京,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)忘分,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進(jìn)店門棋枕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人妒峦,你說我怎么就攤上這事重斑。” “怎么了肯骇?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵窥浪,是天一觀的道長。 經(jīng)常有香客問我笛丙,道長漾脂,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任胚鸯,我火速辦了婚禮骨稿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘姜钳。我一直安慰自己坦冠,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布哥桥。 她就那樣靜靜地躺著辙浑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪拟糕。 梳的紋絲不亂的頭發(fā)上判呕,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天,我揣著相機(jī)與錄音已卸,去河邊找鬼佛玄。 笑死,一個(gè)胖子當(dāng)著我的面吹牛累澡,可吹牛的內(nèi)容都是我干的梦抢。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼愧哟,長吁一口氣:“原來是場噩夢啊……” “哼奥吩!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蕊梧,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤霞赫,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后肥矢,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體端衰,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡叠洗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了旅东。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片灭抑。...
    茶點(diǎn)故事閱讀 38,617評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖抵代,靈堂內(nèi)的尸體忽然破棺而出腾节,到底是詐尸還是另有隱情,我是刑警寧澤荤牍,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布案腺,位于F島的核電站,受9級特大地震影響康吵,放射性物質(zhì)發(fā)生泄漏劈榨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一涎才、第九天 我趴在偏房一處隱蔽的房頂上張望鞋既。 院中可真熱鬧,春花似錦耍铜、人聲如沸邑闺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽陡舅。三九已至,卻和暖如春伴挚,著一層夾襖步出監(jiān)牢的瞬間靶衍,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工茎芋, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留颅眶,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓田弥,卻偏偏與公主長得像涛酗,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子偷厦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評論 2 348

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理商叹,服務(wù)發(fā)現(xiàn),斷路器只泼,智...
    卡卡羅2017閱讀 134,629評論 18 139
  • 用兩張圖告訴你剖笙,為什么你的 App 會(huì)卡頓? - Android - 掘金 Cover 有什么料? 從這篇文章中你...
    hw1212閱讀 12,699評論 2 59
  • 1请唱、通過CocoaPods安裝項(xiàng)目名稱項(xiàng)目信息 AFNetworking網(wǎng)絡(luò)請求組件 FMDB本地?cái)?shù)據(jù)庫組件 SD...
    陽明先生_X自主閱讀 15,969評論 3 119
  • 送完孩子回到家弥咪,打開電腦先在百度首頁看了幾條信息我題目过蹂,大多數(shù)是關(guān)于各類寵物狗的,這肯定是女兒上網(wǎng)時(shí)瀏覽過然后百度...
    會(huì)飛的魚媽閱讀 176評論 1 0
  • 在父母眼里孽惰,我永遠(yuǎn)是長不大的孩子晚岭。下了車,看著老爸步履蹣跚的朝我走來勋功,還要幫我拿沉重的背包坦报,被我拒絕。 當(dāng)老媽把我...
    一人獨(dú)占一江水閱讀 158評論 0 1