免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
Getting Started

安裝它:

npm install --save next react react-dom

將下面腳本添加到 package.json 中:

{  'scripts': {    'dev': 'next',    'build': 'next build',    'start': 'next start'  }}

Next.js 只支持React 16.
由于我們使用 React 16 的特性,所以不得不放棄對(duì) React 15 以及以下版本的支持. 當(dāng)前譯版為7.0.0-canary.8

下面, 文件系統(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 命令并打開(kāi) http://localhost:3000。 如果你想使用其他端口,可運(yùn)行 npm run dev -- -p <設(shè)置端口號(hào)>.

目前為止我們可以了解到:

  • 自動(dòng)打包編譯 (使用 webpack 和 babel)
  • 熱加載
  • ./pages作為服務(wù)端的渲染和索引
  • 靜態(tài)文件服務(wù). ./static/ 映射到 /static/ (可以 創(chuàng)建一個(gè)靜態(tài)目錄 在你的項(xiàng)目中)

這里有個(gè)簡(jiǎn)單的案例,可以下載看看 sample app - nextgram

每個(gè)頁(yè)面只會(huì)導(dǎo)入import中綁定以及被用到的代碼. 也就是說(shuō)并不會(huì)加載不需要的代碼!

import cowsay from 'cowsay-browser'export default () =>  <pre>    {cowsay.say({ text: 'hi there!' })}  </pre>
案例

我們綁定 styled-jsx 來(lái)生成獨(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查看.

內(nèi)嵌樣式

Examples

有些情況可以使用 CSS 內(nèi)嵌 JS 寫(xiě)法。如下所示:

export default () => <p style={{ color: 'red' }}>hi there</p>

更復(fù)雜的內(nèi)嵌樣式解決方案,特別是服務(wù)端渲染的時(shí)樣式更改。我們可以通過(guò)包裹自定義 Document,來(lái)添加樣式,案例如下:custom <Document>

使用 CSS / Sass / Less / Stylus files

支持用.css, .scss, .less or .styl,需要配置默認(rèn)文件 next.config.js,具體可查看下面鏈接

在根目錄下新建文件夾叫static。代碼可以通過(guò)/static/來(lái)引入相關(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)資源。

<head>

Examples

我們?cè)O(shè)置一個(gè)內(nèi)置組件來(lái)裝載<head>到頁(yè)面中。

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屬性來(lái)避免重復(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)容將被清除。請(qǐng)確保每個(gè)頁(yè)面都在其<head>定義了所需要的內(nèi)容,而不是假設(shè)其他頁(yè)面已經(jīng)加過(guò)了

Examples

如果你需要一個(gè)有狀態(tài)、生命周期或有初始數(shù)據(jù)的 React 組件(而不是上面的無(wú)狀態(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)頁(yè)面渲染時(shí)加載數(shù)據(jù),我們使用了一個(gè)異步方法getInitialProps。它能異步獲取 JS 普通對(duì)象,并綁定在props

當(dāng)服務(wù)渲染時(shí),getInitialProps將會(huì)把數(shù)據(jù)序列化,就像JSON.stringify。所以確保getInitialProps返回的是一個(gè)普通 JS 對(duì)象,而不是Date, MapSet類型。

當(dāng)頁(yè)面初始化加載時(shí),getInitialProps只會(huì)加載在服務(wù)端。只有當(dāng)路由跳轉(zhuǎn)(Link組件跳轉(zhuǎn)或 API 方法跳轉(zhuǎn))時(shí),客戶端才會(huì)執(zhí)行getInitialProps

注意:getInitialProps將不能使用在子組件中。只能使用在pages頁(yè)面中。


只有服務(wù)端用到的模塊放在getInitialProps里,請(qǐng)確保正確的導(dǎo)入了它們,可參考import them properly。 否則會(huì)拖慢你的應(yīng)用速度。


你也可以給無(wú)狀態(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)?duì)象的屬性如下:

  • pathname - URL 的 path 部分
  • query - URL 的 query 部分,并被解析成對(duì)象
  • asPath - 顯示在瀏覽器中的實(shí)際路徑(包含查詢部分),為String類型
  • req - HTTP 請(qǐng)求對(duì)象 (只有服務(wù)器端有)
  • res - HTTP 返回對(duì)象 (只有服務(wù)器端有)
  • jsonPageRes - 獲取數(shù)據(jù)響應(yīng)對(duì)象 (只有客戶端有)
  • err - 渲染過(guò)程中的任何錯(cuò)誤

<Link>用法

Examples

可以用 <Link> 組件實(shí)現(xiàn)客戶端的路由切換。

// pages/index.jsimport Link from 'next/link'export default () =>  <div>    Click{' '}    <Link href='/about'>      <a>here</a>    </Link>{' '}    to read more  </div>
// pages/about.jsexport default () => <p>Welcome to About!</p>

注意:可以使用<Link prefetch>使鏈接和預(yù)加載在后臺(tái)同時(shí)進(jìn)行,來(lái)達(dá)到頁(yè)面的最佳性能。

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

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

如果需要注入pathname, queryasPath到你組件中,你可以使用withRouter。

URL 對(duì)象
Examples

組件<Link>接收 URL 對(duì)象,而且它會(huì)自動(dòng)格式化生成 URL 字符串

// pages/index.jsimport 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定義過(guò)的屬性。

替換路由

<Link>組件默認(rèn)將新 url 推入路由棧中。你可以使用replace屬性來(lái)防止添加新輸入。

// pages/index.jsimport Link from 'next/link'export default () =>  <div>    Click{' '}    <Link href='/about' replace>      <a>here</a>    </Link>{' '}    to read more  </div>
支持有點(diǎn)擊事件 onClick的組件

<Link>支持任何有onClick事件的組件。 如果你不包含<a>標(biāo)簽,它僅給組件添加onClick事件,而不會(huì)添加href屬性。

// pages/index.jsimport Link from 'next/link'export default () =>  <div>    Click{' '}    <Link href='/about'>      <img src='/static/image.png' alt='image' />    </Link>  </div>
暴露 href 給子元素

如子元素是一個(gè)沒(méi)有 href 屬性的<a>標(biāo)簽,我們將會(huì)指定它以免用戶重復(fù)操作。然而有些時(shí)候,我們需要里面有<a>標(biāo)簽,但是Link組件不會(huì)被識(shí)別成超鏈接,結(jié)果不能將href傳遞給子元素。在這種場(chǎng)景下,你可以定義一個(gè)Link組件中的布爾屬性passHref,強(qiáng)制將href傳遞給子元素。

注意: 使用a之外的標(biāo)簽而且沒(méi)有通過(guò)passHref的鏈接可能會(huì)使導(dǎo)航看上去正確,但是當(dāng)搜索引擎爬行檢測(cè)時(shí),將不會(huì)識(shí)別成鏈接(由于缺乏 href 屬性),這會(huì)對(duì)你網(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>
禁止?jié)L動(dòng)到頁(yè)面頂部

<Link>的默認(rèn)行為就是滾到頁(yè)面頂部。當(dāng)有 hash 定義時(shí)(#),頁(yè)面將會(huì)滾動(dòng)到對(duì)應(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>

命令式

Examples

你也可以用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>

攔截器 popstate

有些情況(比如使用custom router),你可能想監(jiān)聽(tīng)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對(duì)象的 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) - 頁(yè)面渲染第一個(gè)參數(shù) url 的頁(yè)面,瀏覽器欄顯示的是第二個(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ì)起作用。

URL 對(duì)象用法

pushreplace可接收的 URL 對(duì)象(<Link>組件的 URL 對(duì)象一樣)來(lái)生成 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ù)。

路由事件

你可以監(jiān)聽(tīng)路由相關(guān)事件。 下面是事件支持列表:

  • routeChangeStart(url) - 路由開(kāi)始切換時(shí)觸發(fā)
  • routeChangeComplete(url) - 完成路由切換時(shí)觸發(fā)
  • routeChangeError(err, url) - 路由切換報(bào)錯(cuò)時(shí)觸發(fā)
  • beforeHistoryChange(url) - 瀏覽器 history 模式開(kāi)始切換時(shí)觸發(fā)
  • hashChangeStart(url) - 開(kāi)始切換 hash 值但是沒(méi)有切換頁(yè)面路由時(shí)觸發(fā)
  • hashChangeComplete(url) - 完成切換 hash 值但是沒(méi)有切換頁(yè)面路由時(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)

如果你不想長(zhǎng)期監(jiān)聽(tīng)該事件,你可以用off事件去取消監(jiān)聽(tīng):

Router.events.off('routeChangeStart', handleRouteChange)

如果路由加載被取消(比如快速連續(xù)雙擊鏈接)

Router.events.on('routeChangeError', (err, url) => {  if (err.cancelled) {    console.log(`Route to ${url} was cancelled!`)  }})
淺層路由
Examples

淺層路由允許你改變 URL 但是不執(zhí)行getInitialProps生命周期。你可以加載相同頁(yè)面的 URL,得到更新后的路由屬性pathnamequery,并不失去 state 狀態(tài)。

你可以給Router.pushRouter.replace方法加shallow: true參數(shù)。如下面的例子所示:

// Current URL is '/'const href = '/?counter=10'const as = hrefRouter.push(href, as, { shallow: true })

現(xiàn)在 URL 更新為/?counter=10。在組件里查看this.props.router.query你將會(huì)看到更新的 URL。

你可以在componentdidupdate鉤子函數(shù)中監(jiān)聽(tīng) 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)新頁(yè)面,即使我們加了淺層路由,但是它還是會(huì)卸載當(dāng)前頁(yè),會(huì)加載新的頁(yè)面并觸發(fā)新頁(yè)面的getInitialProps。

Examples

如果你想應(yīng)用里每個(gè)組件都處理路由對(duì)象,你可以使用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)

上面路由對(duì)象的 API 可以參考next/router.

?? 只有生產(chǎn)環(huán)境才有此功能 ??

Examples

Next.js 有允許你預(yù)加載頁(yè)面的 API。

用 Next.js 服務(wù)端渲染你的頁(yè)面,可以達(dá)到所有你應(yīng)用里所有未來(lái)會(huì)跳轉(zhuǎn)的路徑即時(shí)響應(yīng),有效的應(yīng)用 Next.js,可以通過(guò)預(yù)加載應(yīng)用程序的功能,最大程度的初始化網(wǎng)站性能。查看更多.

Next.js 的預(yù)加載功能只預(yù)加載 JS 代碼。當(dāng)頁(yè)面渲染時(shí),你可能需要等待數(shù)據(jù)請(qǐng)求。

<Link>用法

你可以給<Link>添加 prefetch 屬性,Next.js 將會(huì)在后臺(tái)預(yù)加載這些頁(yè)面。

import Link from 'next/link'// example header componentexport 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>

命令式 prefetch 寫(xiě)法

大多數(shù)預(yù)加載是通過(guò)<Link />處理的,但是我們還提供了命令式 API 用于更復(fù)雜的場(chǎng)景。

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 事件寫(xiě)在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)
Examples

一般你使用next start命令來(lái)啟動(dòng) next 服務(wù),你還可以編寫(xiě)代碼來(lái)自定義路由,如使用路由正則等。

當(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 Babelconst { 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)用是否在開(kāi)發(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的對(duì)象相同 - 默認(rèn){}

生產(chǎn)環(huán)境的話,可以更改 package.json 里的start腳本為NODE_ENV=production node server.js。

默認(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.jsmodule.exports = {  useFileSystemPublicRoutes: false}

注意useFileSystemPublicRoutes只禁止服務(wù)端的文件路由;但是客戶端的還是禁止不了。

你如果想配置客戶端路由不能跳轉(zhuǎn)文件路由,可以參考Intercepting popstate。

動(dòng)態(tài)前綴

有時(shí)你需要設(shè)置動(dòng)態(tài)前綴,可以在請(qǐng)求時(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}`)  })})
Examples

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)入方式:

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>

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>

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>

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' />
Examples

組件來(lái)初始化頁(yè)面。你可以重寫(xiě)它來(lái)控制頁(yè)面初始化,如下面的事:

  • 當(dāng)頁(yè)面變化時(shí)保持頁(yè)面布局
  • 當(dāng)路由變化時(shí)保持頁(yè)面狀態(tài)
  • 使用componentDidCatch自定義處理錯(cuò)誤
  • 注入額外數(shù)據(jù)到頁(yè)面里 (如 GraphQL 查詢)

重寫(xiě)的話,新建./pages/_app.js文件,重寫(xiě) 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>  }}
Examples

解釋

  • 在服務(wù)端呈現(xiàn)
  • 初始化服務(wù)端時(shí)添加文檔標(biāo)記元素
  • 通常實(shí)現(xiàn)服務(wù)端渲染會(huì)使用一些 css-in-js 庫(kù),如styled-components, glamorousemotion。styled-jsx是 Next.js 自帶默認(rèn)使用的 css-in-js 庫(kù)

Next.js會(huì)自動(dòng)定義文檔標(biāo)記,比如,你從來(lái)不需要添加<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.jsimport 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對(duì)象都是一樣的

  • 回調(diào)函數(shù)renderPage是會(huì)執(zhí)行 React 渲染邏輯的函數(shù)(同步),這種做法有助于此函數(shù)支持一些類似于 Aphrodite 的 renderStatic 等一些服務(wù)器端渲染容器。

注意:<Main />外的 React 組件將不會(huì)渲染到瀏覽器中,所以那添加應(yīng)用邏輯代碼。如果你頁(yè)面需要公共組件(菜單或工具欄),可以參照上面說(shuō)的App組件代替。

404和500錯(cuò)誤客戶端和服務(wù)端都會(huì)通過(guò)error.js組件處理。如果你想改寫(xiě)它,則新建_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>    )  }}

如果你想渲染內(nèi)置錯(cuò)誤頁(yè)面,你可以使用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ò)誤頁(yè)面,你可以引入自己的錯(cuò)誤頁(yè)面來(lái)代替next/error

如果你想自定義 Next.js 的高級(jí)配置,可以在根目錄下新建next.config.js文件(與pages/package.json一起)

注意:next.config.js是一個(gè) Node.js 模塊,不是一個(gè) JSON 文件,可以用于 Next 啟動(dòng)服務(wù)已經(jīng)構(gòu)建階段,但是不作用于瀏覽器端。

// next.config.jsmodule.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 常量: 這些常量可以通過(guò)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 */  }}

設(shè)置自定義構(gòu)建目錄

你可以自定義一個(gè)構(gòu)建目錄,如新建build文件夾來(lái)代替.next 文件夾成為構(gòu)建目錄。如果沒(méi)有配置構(gòu)建目錄,構(gòu)建時(shí)將會(huì)自動(dòng)新建.next文件夾

// next.config.jsmodule.exports = {  distDir: 'build'}

禁止 etag 生成

你可以禁止 etag 生成根據(jù)你的緩存策略。如果沒(méi)有配置,Next 將會(huì)生成 etags 到每個(gè)頁(yè)面中。

// next.config.jsmodule.exports = {  generateEtags: false}

配置 onDemandEntries

Next 暴露一些選項(xiàng)來(lái)給你控制服務(wù)器部署以及緩存頁(yè)面:

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è)只是在開(kāi)發(fā)環(huán)境才有的功能。如果你在生成環(huán)境中想緩存 SSR 頁(yè)面,請(qǐng)查看SSR-caching

配置頁(yè)面后綴名解析擴(kuò)展

如 typescript 模塊@zeit/next-typescript,需要支持解析后綴名為.ts的文件。pageExtensions 允許你擴(kuò)展后綴名來(lái)解析各種 pages 下的文件。

// next.config.jsmodule.exports = {  pageExtensions: ['jsx', 'js']}

配置構(gòu)建 ID

Next.js 使用構(gòu)建時(shí)生成的常量來(lái)標(biāo)識(shí)你的應(yīng)用服務(wù)是哪個(gè)版本。在每臺(tái)服務(wù)器上運(yùn)行構(gòu)建命令時(shí),可能會(huì)導(dǎo)致多服務(wù)器部署出現(xiàn)問(wèn)題。為了保持同一個(gè)構(gòu)建 ID,可以配置generateBuildId函數(shù):

// next.config.jsmodule.exports = {  generateBuildId: async () => {    // For example get the latest git commit hash here    return 'my-build-id'  }}
Examples

可以使用些一些常見(jiàn)的模塊

注意: webpack方法將被執(zhí)行兩次,一次在服務(wù)端一次在客戶端。你可以用isServer屬性區(qū)分客戶端和服務(wù)端來(lái)配置

多配置可以組合在一起,如:

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è)對(duì)象,你可以自定義配置它,對(duì)象屬性如下所示:

  • buildId - 字符串類型,構(gòu)建的唯一標(biāo)示
  • dev - Boolean型,判斷你是否在開(kāi)發(fā)環(huán)境下
  • isServer - Boolean 型,為true使用在服務(wù)端, 為false使用在客戶端.
  • defaultLoaders - 對(duì)象型 ,內(nèi)部加載器, 你可以如下配置

    • babel - 對(duì)象型,配置babel-loader.
    • hotSelfAccept - 對(duì)象型, hot-self-accept-loader配置選項(xiàng).這個(gè)加載器只能用于高階案例。如 @zeit/next-typescript添加頂層 typescript 頁(yè)面。

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-mdxmodule.exports = {  webpack: (config, {}) => {    config.module.rules.push({      test: /.mdx/,      use: [        options.defaultLoaders.babel,        {          loader: '@mdx-js/loader',          options: pluginOptions.options        }      ]    })    return config  }}
Examples

為了擴(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 代碼分割將被禁用。

next/config模塊使你應(yīng)用運(yùn)行時(shí)可以讀取些存儲(chǔ)在next.config.js的配置項(xiàng)。serverRuntimeConfig屬性只在服務(wù)器端可用,publicRuntimeConfig屬性在服務(wù)端和客戶端可用。

// next.config.jsmodule.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.jsimport 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 sideconsole.log(publicRuntimeConfig.staticFolder) // Will be available on both server and clientexport default () => <div>  <img src={`${publicRuntimeConfig.staticFolder}/logo.png`} alt='logo' /></div>

啟動(dòng)開(kāi)發(fā)環(huán)境服務(wù)可以設(shè)置不同的 hostname,你可以在啟動(dòng)命令后面加上--hostname 主機(jī)名-H 主機(jī)名。它將會(huì)啟動(dòng)一個(gè) TCP 服務(wù)器來(lái)監(jiān)聽(tīng)連接所提供的主機(jī)。

建立一個(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)添加前綴,但是對(duì)于/static是沒(méi)有效果的,如果你想這些靜態(tài)資源也能使用 CDN,你需要自己添加前綴。有一個(gè)方法可以判斷你的環(huán)境來(lái)加前綴,如 in this example

部署中,你可以先構(gòu)建打包生成環(huán)境代碼,再啟動(dòng)服務(wù)。因此,構(gòu)建和啟動(dòng)分為下面兩條命令:

next buildnext start

例如,使用now去部署package.json配置文件如下:

{  'name': 'my-app',  'dependencies': {    'next': 'latest'  },  'scripts': {    'dev': 'next',    'build': 'next build',    'start': 'next start'  }}

然后就可以直接運(yùn)行now了。

Next.js 也有其他托管解決方案。請(qǐng)查考 wiki 章節(jié)'Deployment' 。

注意:NODE_ENV可以通過(guò)next命令配置,如果沒(méi)有配置,會(huì)最大渲染,如果你使用編程式寫(xiě)法的話programmatically,你需要手動(dòng)設(shè)置NODE_ENV=production

注意:推薦將.next或自定義打包文件夾custom dist folder放入.gitignore.npmignore中。否則,使用filesnow.files添加部署白名單,并排除.next或自定義打包文件夾。

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

Examples

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 都生成。這是基于映射對(duì)象的pathname關(guān)鍵字關(guān)聯(lián)到頁(yè)面對(duì)象。這個(gè)映射叫做exportPathMap。

頁(yè)面對(duì)象有2個(gè)屬性:

  • page - 字符串類型,頁(yè)面生成目錄
  • query - 對(duì)象類型,當(dāng)預(yù)渲染時(shí),query對(duì)象將會(huì)傳入頁(yè)面的生命周期getInitialProps中。默認(rèn)為{}。

通常開(kāi)發(fā) Next.js 應(yīng)用你將會(huì)運(yùn)行:

next buildnext export

next export命令默認(rèn)不需要任何配置,將會(huì)自動(dòng)生成默認(rèn)exportPathMap生成pages目錄下的路由你頁(yè)面。

如果你想動(dòng)態(tài)配置路由,可以在next.config.js中添加異步函數(shù)exportPathMap。

// next.config.jsmodule.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)出對(duì)應(yīng)的文件,如上/readme.md。如果你使用.html以外的擴(kuò)展名解析文件時(shí),你需要設(shè)置 header 的Content-Type頭為'text/html'.

輸入下面命令:

next buildnext export

你可以在package.json添加一個(gè) NPM 腳本,如下所示:

{  'scripts': {    'build': 'next build',    'export': 'npm run build && next export'  }}

接著只用執(zhí)行一次下面命令:

npm run export

然后你將會(huì)有一個(gè)靜態(tài)頁(yè)面應(yīng)用在out 目錄下。

你也可以自定義輸出目錄。可以運(yùn)行next export -h命令查看幫助。

現(xiàn)在你可以部署out目錄到任意靜態(tài)資源服務(wù)器上。注意如果部署 GitHub Pages 需要加個(gè)額外的步驟,文檔如下

例如,訪問(wèn)out目錄并用下面命令部署應(yīng)用ZEIT Now.

now

使用next export,我們創(chuàng)建了個(gè)靜態(tài) HTML 應(yīng)用。構(gòu)建時(shí)將會(huì)運(yùn)行頁(yè)面里生命周期getInitialProps 函數(shù)。

reqres只在服務(wù)端可用,不能通過(guò)getInitialProps

所以你不能預(yù)構(gòu)建 HTML 文件時(shí)動(dòng)態(tài)渲染 HTML 頁(yè)面。如果你想動(dòng)態(tài)渲染可以運(yùn)行next start或其他自定義服務(wù)端 API。

Examples

一個(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ú)開(kāi)發(fā)各個(gè)應(yīng)用。

與 microservices 觀念類似, 只是應(yīng)用于前端應(yīng)用.

zone 沒(méi)有單獨(dú)的 API 文檔。你需要做下面事即可:

  • 確保你的應(yīng)用里只有需要的頁(yè)面 (例如, https://ui.my-app.com 不包含 /docs/**)
  • 確保你的應(yīng)用有個(gè)前綴assetPrefix。(你也可以定義動(dòng)態(tài)前綴dynamically

你能使用 HTTP 代理合并 zone

你能使用代理micro proxy來(lái)作為你的本地代理服務(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ù)編寫(xiě)上面規(guī)則來(lái)路由 HTML 頁(yè)面

這個(gè)產(chǎn)品可以用于生產(chǎn)環(huán)境嗎?https://zeit.co 都是一直用 Next.js 寫(xiě)的。

它的開(kāi)發(fā)體驗(yàn)和終端用戶體驗(yàn)都很好,所以我們決定開(kāi)源出來(lái)給大家共享。

體積多大?

客戶端大小根據(jù)應(yīng)用需求不一樣大小也不一樣。

一個(gè)最簡(jiǎn)單 Next 應(yīng)該用 gzip 壓縮后大約65kb

這個(gè)像 `create-react-app`?

是或不是.

是,因?yàn)樗屇愕?SSR 開(kāi)發(fā)更簡(jiǎn)單。

不是,因?yàn)樗?guī)定了一定的目錄結(jié)構(gòu),使我們能做以下更高級(jí)的事:

  • 服務(wù)端渲染
  • 自動(dòng)代碼分割

此外,Next.js 還提供兩個(gè)內(nèi)置特性:

  • 路由與懶加載組件: <Link> (通過(guò)引入 next/link)
  • 修改<head>的組件: <Head> (通過(guò)引入 next/head)

如果你想寫(xiě)共用組件,可以嵌入 Next.js 應(yīng)用和 React 應(yīng)用中,推薦使用create-react-app。你可以更改import保持代碼清晰。

怎么解決 CSS 嵌入 JS 問(wèn)題?

Next.js 自帶styled-jsx庫(kù)支持 CSS 嵌入 JS。而且你可以選擇其他你喜歡的嵌入方法到你的項(xiàng)目中,可參考文檔嵌入樣式。

哪些語(yǔ)法會(huì)被轉(zhuǎn)換?怎么轉(zhuǎn)換它們?

我們遵循 V8 引擎的,如今 V8 引擎廣泛支持 ES6 語(yǔ)法以及asyncawait語(yǔ)法,所以我們支持轉(zhuǎn)換它們。但是 V8 引擎不支持修飾器語(yǔ)法,所以我們也不支持轉(zhuǎn)換這語(yǔ)法。

可以參照這些 以及 這些

為什么使用新路由?

Next.js 的特別之處如下所示:

  • 路由不需要被提前知道
  • 路由總是被懶加載
  • 頂層組件可以定義生命周期getInitialProps來(lái)阻止路由加載(當(dāng)服務(wù)端渲染或路由懶加載時(shí))

因此,我們可以介紹一個(gè)非常簡(jiǎn)單的路由方法,它由下面兩部分組成:

  • 每個(gè)頂層組件都將會(huì)收到一個(gè)url對(duì)象,來(lái)檢查 url 或修改歷史記錄
  • <Link />組件用于包裝如(<a/>)標(biāo)簽的元素容器,來(lái)執(zhí)行客戶端轉(zhuǎn)換。

我們使用了些有趣的場(chǎng)景來(lái)測(cè)試路由的靈活性,例如,可查看nextgram。

我怎么定義自定義路由?

我們通過(guò)請(qǐng)求處理來(lái)添加任意 URL 與任意組件之前的映射關(guān)系。

在客戶端,我們<Link>組件有個(gè)屬性as,可以裝飾改變獲取到的 URL。

怎么獲取數(shù)據(jù)?

這由你決定。getInitialProps是一個(gè)異步函數(shù)async(也就是函數(shù)將會(huì)返回個(gè)Promise)。你可以在任意位置獲取數(shù)據(jù)。

我可以使用 GraphQL 嗎?

是的! 這里有個(gè)例子Apollo.

我可以使用 Redux 嗎?

是的! 這里有個(gè)例子

我可以在 Next 應(yīng)用中使用我喜歡的 Javascript 庫(kù)或工具包嗎?

從我們第一次發(fā)版就已經(jīng)提供很多例子,你可以查看這些例子

什么啟發(fā)我們做這個(gè)?

我們實(shí)現(xiàn)的大部分目標(biāo)都是通過(guò) Guillermo Rauch 的Web 應(yīng)用的7原則來(lái)啟發(fā)出的。

PHP 的易用性也是個(gè)很好的靈感來(lái)源,我們覺(jué)得 Next.js 可以替代很多需要用 PHP 輸出 HTML 的場(chǎng)景。

與 PHP 不同的是,我們得利于 ES6 模塊系統(tǒng),每個(gè)文件會(huì)輸出一個(gè)組件或方法,以便可以輕松的導(dǎo)入用于懶加載和測(cè)試

我們研究 React 的服務(wù)器渲染時(shí)并沒(méi)有花費(fèi)很大的步驟,因?yàn)槲覀儼l(fā)現(xiàn)一個(gè)類似于 Next.js 的產(chǎn)品,React 作者 Jordan Walke 寫(xiě)的react-page (現(xiàn)在已經(jīng)廢棄)

可點(diǎn)擊查看

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
基于Vue的前端架構(gòu),我做了這15點(diǎn)
Vue Koa從零打造一個(gè)H5頁(yè)面可視化編輯器——Quark-h5
漸進(jìn)式入門(mén)教程 | Taro 文檔
第7章 小程序開(kāi)發(fā)框架
如何搭建一個(gè)vue-cli4+webpack移動(dòng)端框架?本文詳解
管理后臺(tái)Vue
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服