`
-
-
- Examples
-
-
-
-
-- 在服务端呈现
-- 初始化服务端时添加文档标记元素
-- 通常实现服务端渲染会使用一些 css-in-js 库,如[styled-components](./examples/with-styled-components), [glamorous](./examples/with-glamorous) 或 [emotion](with-emotion)。[styled-jsx](https://github.com/zeit/styled-jsx)是 Next.js 自带默认使用的 css-in-js 库
-
-`Next.js`会自动定义文档标记,比如,你从来不需要添加``, ``等。如果想自定义文档标记,你可以新建`./pages/_document.js`,然后扩展`Document`类:
-
-```jsx
-// _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 (
-
-
-
-
-
-
-
-
-
- )
- }
-}
-```
-
-钩子[`getInitialProps`](#fetching-data-and-component-lifecycle)接收到的参数`ctx`对象都是一样的
-
-- 回调函数`renderPage`是会执行 React 渲染逻辑的函数(同步),这种做法有助于此函数支持一些类似于 Aphrodite 的 renderStatic 等一些服务器端渲染容器。
-
-**注意:` `外的 React 组件将不会渲染到浏览器中,所以那添加应用逻辑代码。如果你页面需要公共组件(菜单或工具栏),可以参照上面说的`App`组件代替。**
-
-
-
-#### 自定义 `renderPage`
-
-🚧 应该注意的是,您应该定制“renderPage”的唯一原因是使用 css-in-js 库,需要将应用程序包装起来以正确使用服务端渲染。 🚧
-
-- 它将一个选项对象作为参数进行进一步的自定义:
-
-```js
-import Document from 'next/document'
-
-class MyDocument extends Document {
- static async getInitialProps(ctx) {
- const originalRenderPage = ctx.renderPage
-
- ctx.renderPage = () =>
- originalRenderPage({
- // useful for wrapping the whole react tree
- enhanceApp: App => App,
- // useful for wrapping in a per-page basis
- enhanceComponent: Component => Component,
- })
-
- // Run the parent `getInitialProps` using `ctx` that now includes our custom `renderPage`
- const initialProps = await Document.getInitialProps(ctx)
-
- return initialProps
- }
-}
-
-export default MyDocument
-```
-
-### 自定义错误处理
-
-404 和 500 错误客户端和服务端都会通过`error.js`组件处理。如果你想改写它,则新建`_error.js`在文件夹中:
-
-⚠️ 该`pages/_error.js`组件仅用于生产。在开发过程中,您会收到调用堆栈错误,以了解错误源自何处。 ⚠️
-
-```jsx
-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 (
-
- {this.props.statusCode
- ? `An error ${this.props.statusCode} occurred on server`
- : 'An error occurred on client'}
-
- )
- }
-}
-```
-
-
-
-### 渲染内置错误页面
-
-如果你想渲染内置错误页面,你可以使用`next/error`:
-
-```jsx
-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
- }
-
- return Next stars: {this.props.stars}
- }
-}
-```
-
-> 如果你自定义了个错误页面,你可以引入自己的错误页面来代替`next/error`
-
-
-
-### 自定义配置
-
-如果你想自定义 Next.js 的高级配置,可以在根目录下新建`next.config.js`文件(与`pages/` 和 `package.json`一起)
-
-注意:`next.config.js`是一个 Node.js 模块,不是一个 JSON 文件,可以用于 Next 启动服务已经构建阶段,但是不作用于浏览器端。
-
-```js
-// next.config.js
-module.exports = {
- /* config options here */
-}
-```
-
-或使用一个函数:
-
-```js
-module.exports = (phase, { defaultConfig }) => {
- //
- // https://github.com/zeit/
- return {
- /* config options here */
- }
-}
-```
-
-`phase`是配置文件被加载时的当前内容。你可看到所有的 phases 常量:[constants](./lib/constants.js)
-这些常量可以通过`next/constants`引入:
-
-```js
-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 */
- }
-}
-```
-
-
-
-#### 设置自定义构建目录
-
-你可以自定义一个构建目录,如新建`build`文件夹来代替`.next` 文件夹成为构建目录。如果没有配置构建目录,构建时将会自动新建`.next`文件夹
-
-```js
-// next.config.js
-module.exports = {
- distDir: 'build',
-}
-```
-
-
-
-#### 禁止 etag 生成
-
-你可以禁止 etag 生成根据你的缓存策略。如果没有配置,Next 将会生成 etags 到每个页面中。
-
-```js
-// next.config.js
-module.exports = {
- generateEtags: false,
-}
-```
-
-
-
-#### 配置 onDemandEntries
-
-Next 暴露一些选项来给你控制服务器部署以及缓存页面:
-
-```js
-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,
- },
-}
-```
-
-这个只是在开发环境才有的功能。如果你在生成环境中想缓存 SSR 页面,请查看[SSR-caching](https://github.com/zeit/next.js/tree/canary/examples/ssr-caching)
-
-
-
-#### 配置解析路由时的页面文件后缀名
-
-如 typescript 模块[`@zeit/next-typescript`](https://github.com/zeit/next-plugins/tree/master/packages/next-typescript),需要支持解析后缀名为`.ts`的文件。`pageExtensions` 允许你扩展后缀名来解析各种 pages 下的文件。
-
-```js
-// next.config.js
-module.exports = {
- pageExtensions: ['jsx', 'js'],
-}
-```
-
-
-
-#### 配置构建 ID
-
-Next.js 使用构建时生成的常量来标识你的应用服务是哪个版本。在每台服务器上运行构建命令时,可能会导致多服务器部署出现问题。为了保持同一个构建 ID,可以配置`generateBuildId`函数:
-
-```js
-// next.config.js
-module.exports = {
- generateBuildId: async () => {
- // For example get the latest git commit hash here
- return 'my-build-id'
- },
-}
-```
-
-
-
-### 自定义 webpack 配置
-
-
- Examples
-
-
-
-可以使用些一些常见的模块
-
-- [@zeit/next-css](https://github.com/zeit/next-plugins/tree/master/packages/next-css)
-- [@zeit/next-sass](https://github.com/zeit/next-plugins/tree/master/packages/next-sass)
-- [@zeit/next-less](https://github.com/zeit/next-plugins/tree/master/packages/next-less)
-- [@zeit/next-preact](https://github.com/zeit/next-plugins/tree/master/packages/next-preact)
-- [@zeit/next-typescript](https://github.com/zeit/next-plugins/tree/master/packages/next-typescript)
-
-_注意: `webpack`方法将被执行两次,一次在服务端一次在客户端。你可以用`isServer`属性区分客户端和服务端来配置_
-
-多配置可以组合在一起,如:
-
-```js
-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
- },
- })
-)
-```
-
-为了扩展`webpack`使用,可以在`next.config.js`定义函数。
-
-```js
-// 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`的第二个参数是个对象,你可以自定义配置它,对象属性如下所示:
-
-- `buildId` - 字符串类型,构建的唯一标示
-- `dev` - `Boolean`型,判断你是否在开发环境下
-- `isServer` - `Boolean` 型,为`true`使用在服务端, 为`false`使用在客户端.
-- `defaultLoaders` - 对象型 ,内部加载器, 你可以如下配置
- - `babel` - 对象型,配置`babel-loader`.
-
-`defaultLoaders.babel`使用案例如下:
-
-```js
-// 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
- },
-}
-```
-
-
-
-### 自定义 babel 配置
-
-
- Examples
-
-
-
-为了扩展方便我们使用`babel`,可以在应用根目录新建`.babelrc`文件,该文件可配置。
-
-如果有该文件,我们将会考虑数据源,因此也需要定义 next 项目需要的东西,也就是 `next/babel`预设。
-
-这种设计方案将会使你不诧异于我们可以定制 babel 配置。
-
-下面是`.babelrc`文件案例:
-
-```json
-{
- "presets": ["next/babel"],
- "plugins": []
-}
-```
-
-`next/babel`预设可处理各种 React 应用所需要的情况。包括:
-
-- preset-env
-- preset-react
-- plugin-proposal-class-properties
-- plugin-proposal-object-rest-spread
-- plugin-transform-runtime
-- styled-jsx
-
-presets / plugins 不允许添加到`.babelrc`中,然而你可以配置`next/babel`预设:
-
-```json
-{
- "presets": [
- [
- "next/babel",
- {
- "preset-env": {},
- "transform-runtime": {},
- "styled-jsx": {},
- "class-properties": {}
- }
- ]
- ],
- "plugins": []
-}
-```
-
-`"preset-env"`模块选项应该保持为 false,否则 webpack 代码分割将被禁用。
-
-
-
-### 暴露配置到服务端和客户端
-
-在应用程序中通常需要提供配置值
-
-Next.js 支持 2 种提供配置的方式:
-
-- 构建时配置
-- 运行时配置
-
-#### 构建时配置
-
-构建时配置的工作方式是将提供的值内联到 Javascript 包中。
-
-你可以在`next.config.js`设置`env`:
-
-```js
-// next.config.js
-module.exports = {
- env: {
- customKey: 'value',
- },
-}
-```
-
-这将允许你在代码中使用`process.env.customKey`,例如:
-
-```jsx
-// pages/index.js
-function Index() {
- return The value of customKey is: {process.env.customKey}
-}
-
-export default Index
-```
-
-#### 运行时配置
-
-> ⚠️ 请注意,使用此选项时不可用 `target: 'serverless'`
-
-> ⚠️ 通常,您希望使用构建时配置来提供配置。原因是运行时配置增加了一个小的 rendering/initialization 开销。
-
-`next/config`模块使你应用运行时可以读取些存储在`next.config.js`的配置项。`serverRuntimeConfig`属性只在服务器端可用,`publicRuntimeConfig`属性在服务端和客户端可用。
-
-```js
-// next.config.js
-module.exports = {
- serverRuntimeConfig: {
- // Will only be available on the server side
- mySecret: 'secret',
- secondSecret: process.env.SECOND_SECRET, // Pass through env variables
- },
- publicRuntimeConfig: {
- // Will be available on both server and client
- staticFolder: '/static',
- },
-}
-```
-
-```js
-// 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
-
-function MyImage() {
- return (
-
-
-
- )
-}
-
-export default MyImage
-```
-
-### 启动服务选择 hostname
-
-启动开发环境服务可以设置不同的 hostname,你可以在启动命令后面加上`--hostname 主机名` 或 `-H 主机名`。它将会启动一个 TCP 服务器来监听连接所提供的主机。
-
-
-
-### CDN 支持前缀
-
-建立一个 CDN,你能配置`assetPrefix`选项,去配置你的 CDN 源。
-
-```js
-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 运行时将会自动添加前缀,但是对于`/static`是没有效果的,如果你想这些静态资源也能使用 CDN,你需要自己添加前缀。有一个方法可以判断你的环境来加前缀,如 [in this example](https://github.com/zeit/next.js/tree/master/examples/with-universal-configuration-build-time)。
-
-
-
-## 项目部署
-
-部署中,你可以先构建打包生成环境代码,再启动服务。因此,构建和启动分为下面两条命令:
-
-```bash
-next build
-next start
-```
-
-例如,使用[`now`](https://zeit.co/now)去部署`package.json`配置文件如下:
-
-```json
-{
- "name": "my-app",
- "dependencies": {
- "next": "latest"
- },
- "scripts": {
- "dev": "next",
- "build": "next build",
- "start": "next start"
- }
-}
-```
-
-然后就可以直接运行`now`了。
-
-Next.js 也有其他托管解决方案。请查考 wiki 章节['Deployment'](https://github.com/zeit/next.js/wiki/Deployment) 。
-
-注意:`NODE_ENV`可以通过`next`命令配置,如果没有配置,会最大渲染,如果你使用编程式写法的话[programmatically](#custom-server-and-routing),你需要手动设置`NODE_ENV=production`。
-
-注意:推荐将`.next`或自定义打包文件夹[custom dist folder](https://github.com/zeit/next.js#custom-configuration)放入`.gitignore` 或 `.npmignore`中。否则,使用`files` 或 `now.files`
-添加部署白名单,并排除`.next`或自定义打包文件夹。
-
-
-
-### 无服务器部署
-
-
- 例子
-
-
-
-无服务器部署通过将应用程序拆分为更小的部分(也称为[**lambdas**](https://zeit.co/docs/v2/deployments/concepts/lambdas/))来显着提高可靠性和可伸缩性。在 Next.js 中,`pages`目录中的每个页面都变成了无服务器的 lambda。
-对于无服务器的人来说,有[许多好处](https://zeit.co/blog/serverless-express-js-lambdas-with-now-2#benefits-of-serverless-express)。引用的链接在 Express 的上下文中讨论了其中的一些,但这些原则普遍适用:无服务器允许分布式故障点,无限的可扩展性,并且通过“为您使用的内容付费”的模式来提供难以置信的价格。
-
-要在 Next.js 中启用**无服务器模式**,可在`Next.config.js`中配置`target`值为`serverless`:
-
-```js
-// next.config.js
-module.exports = {
- target: 'serverless',
-}
-```
-
-`serverless`将每页输出一个 lambda。此文件是完全独立的,不需要运行任何依赖项:
-
-- `pages/index.js` => `.next/serverless/pages/index.js`
-- `pages/about.js` => `.next/serverless/pages/about.js`
-
-Next.js 无服务器功能的签名类似于 Node.js HTTP 服务器回调:
-
-```ts
-export function render(req: http.IncomingMessage, res: http.ServerResponse) => void
-```
-
-- [http.IncomingMessage](https://nodejs.org/api/http.html#http_class_http_incomingmessage)
-- [http.ServerResponse](https://nodejs.org/api/http.html#http_class_http_serverresponse)
-- `void` 指的是没有返回值的函数,它等同于 JavaScript`undefined`。调用该函数将完成请求。
-
-使用无服务配置, 你可以讲 Next.js 部署到[ZEIT Now](https://zeit.co/now) 并提供所有的好处和易于控制; [custom routes](https://zeit.co/guides/custom-next-js-server-to-routes/) 缓存头. 要了解更多信息,请参阅 [ZEIT Guide for Deploying Next.js with Now](https://zeit.co/guides/deploying-nextjs-with-now/)
-
-#### 降级部署
-
-Next.js 为无服务器部署提供低级 API,因为托管平台具有不同的功能签名。通常,您需要使用兼容性层包装 Next.js 无服务器构建的输出。
-
-例如,如果平台支持 Node.js[`http.Server`](https://nodejs.org/api/http.html#http_class_http_server)类:
-
-```js
-const http = require('http')
-const page = require('./.next/serverless/pages/about.js')
-const server = new http.Server((req, res) => page.render(req, res))
-server.listen(3000, () => console.log('Listening on http://localhost:3000'))
-```
-
-有关特定平台示例,请参阅[the examples section above](#serverless-deployment).
-
-#### 摘要
-
-- 用于实现无服务器部署的 Low-level API
-- `pages`目录中的每个页面都成为无服务器功能(lambda)
-- 创建最小的无服务器功能 (50Kb base zip size)
-- 针对功能的快速[cold start](https://zeit.co/blog/serverless-ssr#cold-start) 进行了优化
-- 无服务器函数有 0 个依赖项 (依赖项包含在函数包中)
-- 使用 Node.js 中的[http.IncomingMessage](https://nodejs.org/api/http.html#http_class_http_incomingmessage)和[http.ServerResponse](https://nodejs.org/api/http.html#http_class_http_serverresponse)
-- 选择使用`target: 'serverless'` in `next.config.js`
-- 在执行函数时不要加载`next.config.js`,请注意这意味着`publicRuntimeConfig` / `serverRuntimeConfig`不支持。
-
-## 浏览器支持
-
-Next.js 支持 IE11 和所有的现代浏览器使用了[`@babel/preset-env`](https://new.babeljs.io/docs/en/next/babel-preset-env.html)。为了支持 IE11,Next.js 需要全局添加`Promise`的 polyfill。有时你的代码或引入的其他 NPM 包的部分功能现代浏览器不支持,则需要用 polyfills 去实现。
-
-ployflls 实现案例为[polyfills](https://github.com/zeit/next.js/tree/canary/examples/with-polyfills)。
-
-
-
-## 导出静态页面
-
-
- Examples
-
-
-
-`next export`可以输出一个 Next.js 应用作为静态资源应用而不依靠 Node.js 服务。
-这个输出的应用几乎支持 Next.js 的所有功能,包括动态路由,预获取,预加载以及动态导入。
-
-`next export`将把所有有可能渲染出的 HTML 都生成。这是基于映射对象的`pathname`关键字关联到页面对象。这个映射叫做`exportPathMap`。
-
-页面对象有 2 个属性:
-
-- `page` - 字符串类型,页面生成目录
-- `query` - 对象类型,当预渲染时,`query`对象将会传入页面的生命周期`getInitialProps`中。默认为`{}`。
-
-
-
-### 使用
-
-通常开发 Next.js 应用你将会运行:
-
-```
-next build
-next export
-```
-
-`next export`命令默认不需要任何配置,将会自动生成默认`exportPathMap`生成`pages`目录下的路由你页面。
-
-如果你想动态配置路由,可以在`next.config.js`中添加异步函数`exportPathMap`。
-
-```js
-// 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 的结尾是目录名,则将导出`/dir-name/index.html`,但是如果结尾有扩展名,将会导出对应的文件,如上`/readme.md`。如果你使用`.html`以外的扩展名解析文件时,你需要设置 header 的`Content-Type`头为"text/html".
-
-输入下面命令:
-
-```sh
-next build
-next export
-```
-
-你可以在`package.json`添加一个 NPM 脚本,如下所示:
-
-```json
-{
- "scripts": {
- "build": "next build",
- "export": "npm run build && next export"
- }
-}
-```
-
-接着只用执行一次下面命令:
-
-```sh
-npm run export
-```
-
-然后你将会有一个静态页面应用在`out` 目录下。
-
-> 你也可以自定义输出目录。可以运行`next export -h`命令查看帮助。
-
-现在你可以部署`out`目录到任意静态资源服务器上。注意如果部署 GitHub Pages 需要加个额外的步骤,[文档如下](https://github.com/zeit/next.js/wiki/Deploying-a-Next.js-app-into-GitHub-Pages)
-
-例如,访问`out`目录并用下面命令部署应用[ZEIT Now](https://zeit.co/now).
-
-```sh
-now
-```
-
-
-
-### 复制自定义文件
-
-如果您必须复制 robots.txt 等自定义文件或生成 sitemap.xml,您可以在其中执行此操作`exportPathMap`。 `exportPathMap`获取一些上下文参数来帮助您创建/复制文件:
-
-- `dev` - `true`表示在开发环境下使用`exportPathMap`. `false`表示运行于`next export`. 在开发中,“exportpathmap”用于定义路由,不需要复制文件等行为。
-- `dir` - 项目目录的绝对路径
-- `outDir` - 指向`out`目录的绝对路径(可配置为`-o`或`--outdir`)。当`dev`为`true`时,`outdir`的值将为`null`。
-- `distDir` - `.next`目录的绝对路径(可使用`distDir`配置键配置)
-- `buildId` - 导出正在运行的 buildId
-
-```js
-// next.config.js
-const fs = require('fs')
-const { join } = require('path')
-const { promisify } = require('util')
-const copyFile = promisify(fs.copyFile)
-
-module.exports = {
- exportPathMap: async function(
- defaultPathMap,
- { dev, dir, outDir, distDir, buildId }
- ) {
- if (dev) {
- return defaultPathMap
- }
- // This will copy robots.txt from your project root into the out directory
- await copyFile(join(dir, 'robots.txt'), join(outDir, 'robots.txt'))
- return defaultPathMap
- },
-}
-```
-
-### 限制
-
-使用`next export`,我们创建了个静态 HTML 应用。构建时将会运行页面里生命周期`getInitialProps` 函数。
-
-`req`和`res`只在服务端可用,不能通过`getInitialProps`。
-
-> 所以你不能预构建 HTML 文件时动态渲染 HTML 页面。如果你想动态渲染可以运行`next start`或其他自定义服务端 API。
-
-
-
-## 多 zone
-
-
- Examples
-
-
-
-一个 zone 时一个单独的 Next.js 应用。如果你有很多 zone,你可以合并成一个应用。
-
-例如,你如下有两个 zone:
-
-- https://docs.my-app.com 服务于路由 `/docs/**`
-- https://ui.my-app.com 服务于所有页面
-
-有多 zone 应用技术支持,你可以将几个应用合并到一个,而且可以自定义 URL 路径,使你能同时单独开发各个应用。
-
-> 与 microservices 观念类似, 只是应用于前端应用.
-
-
-
-### 怎么定义一个 zone
-
-zone 没有单独的 API 文档。你需要做下面事即可:
-
-- 确保你的应用里只有需要的页面 (例如, https://ui.my-app.com 不包含 `/docs/**`)
-- 确保你的应用有个前缀[assetPrefix](https://github.com/zeit/next.js#cdn-support-with-asset-prefix)。(你也可以定义动态前缀[dynamically](https://github.com/zeit/next.js#dynamic-assetprefix))
-
-
-
-### 怎么合并他们
-
-你能使用 HTTP 代理合并 zone
-
-你能使用代理[micro proxy](https://github.com/zeit/micro-proxy)来作为你的本地代理服务。它允许你定义路由规则如下:
-
-```json
-{
- "rules": [
- {
- "pathname": "/docs**",
- "method": ["GET", "POST", "OPTIONS"],
- "dest": "https://docs.my-app.com"
- },
- { "pathname": "/**", "dest": "https://ui.my-app.com" }
- ]
-}
-```
-
-生产环境部署,如果你使用了[ZEIT now](https://zeit.co/now),可以它的使用[path alias](https://zeit.co/docs/features/path-aliases) 功能。否则,你可以设置你已使用的代理服务编写上面规则来路由 HTML 页面
-
-
-
-## 技巧
-
-- [设置 301 重定向](https://www.raygesualdo.com/posts/301-redirects-with-nextjs/)
-- [只处理服务器端模块](https://arunoda.me/blog/ssr-and-server-only-modules)
-- [构建项目 React-Material-UI-Next-Express-Mongoose-Mongodb](https://github.com/builderbook/builderbook)
-- [构建一个 SaaS 产品 React-Material-UI-Next-MobX-Express-Mongoose-MongoDB-TypeScript](https://github.com/async-labs/saas)
-
-
-
-## 问答
-
-
- 这个产品可以用于生产环境吗?
- https://zeit.co 都是一直用 Next.js 写的。
-
-它的开发体验和终端用户体验都很好,所以我们决定开源出来给大家共享。
-
-
-
-
- 体积多大?
-
-客户端大小根据应用需求不一样大小也不一样。
-
-一个最简单 Next 应该用 gzip 压缩后大约 65kb
-
-
-
-
- 这个像 `create-react-app`?
-
-是或不是.
-
-是,因为它让你的 SSR 开发更简单。
-
-不是,因为它规定了一定的目录结构,使我们能做以下更高级的事:
-
-- 服务端渲染
-- 自动代码分割
-
-此外,Next.js 还提供两个内置特性:
-
-- 路由与懒加载组件: ` ` (通过引入 `next/link`)
-- 修改``的组件: `` (通过引入 `next/head`)
-
-如果你想写共用组件,可以嵌入 Next.js 应用和 React 应用中,推荐使用`create-react-app`。你可以更改`import`保持代码清晰。
-
-
-
-
- 怎么解决 CSS 嵌入 JS 问题?
-
-Next.js 自带[styled-jsx](https://github.com/zeit/styled-jsx)库支持 CSS 嵌入 JS。而且你可以选择其他嵌入方法到你的项目中,可参考文档[as mentioned before](#css-in-js)。
-
-
-
-
- 哪些语法会被转换?怎么转换它们?
-
-我们遵循 V8 引擎的,如今 V8 引擎广泛支持 ES6 语法以及`async`和`await`语法,所以我们支持转换它们。但是 V8 引擎不支持修饰器语法,所以我们也不支持转换这语法。
-
-可以参照[这些](https://github.com/zeit/next.js/blob/master/server/build/webpack.js#L79) 以及 [这些](https://github.com/zeit/next.js/issues/26)
-
-
-
-
- 为什么使用新路由?
-
-Next.js 的特别之处如下所示:
-
-- 路由不需要被提前知道
-- 路由总是被懒加载
-- 顶层组件可以定义生命周期`getInitialProps`来阻止路由加载(当服务端渲染或路由懒加载时)
-
-因此,我们可以介绍一个非常简单的路由方法,它由下面两部分组成:
-
-- 每个顶层组件都将会收到一个`url`对象,来检查 url 或修改历史记录
-- ` `组件用于包装如(` `)标签的元素容器,来执行客户端转换。
-
-我们使用了些有趣的场景来测试路由的灵活性,例如,可查看[nextgram](https://github.com/zeit/nextgram)。
-
-
-
-
-我怎么定义自定义路由?
-
-我们通过请求处理来[添加](#custom-server-and-routing)任意 URL 与任意组件之前的映射关系。
-
-在客户端,我们` `组件有个属性`as`,可以装饰改变获取到的 URL。
-
-
-
-
-怎么获取数据?
-
-这由你决定。`getInitialProps`是一个异步函数`async`(也就是函数将会返回个`Promise`)。你可以在任意位置获取数据。
-
-
-
-
- 我可以使用 GraphQL 吗?
-
-是的! 这里有个例子[Apollo](./examples/with-apollo).
-
-
-
-
-我可以使用 Redux 吗?
-
-是的! 这里有个[例子](./examples/with-redux)
-
-
-
-
-我可以在 Next 应用中使用我喜欢的 Javascript 库或工具包吗?
-
-从我们第一次发版就已经提供**很多**例子,你可以查看这些[例子](./examples)。
-
-
-
-
-什么启发我们做这个?
-
-我们实现的大部分目标都是通过 Guillermo Rauch 的[Web 应用的 7 原则](http://rauchg.com/2014/7-principles-of-rich-web-applications/)来启发出的。
-
-PHP 的易用性也是个很好的灵感来源,我们觉得 Next.js 可以替代很多需要用 PHP 输出 HTML 的场景。
-
-与 PHP 不同的是,我们得利于 ES6 模块系统,每个文件会输出一个**组件或方法**,以便可以轻松的导入用于懒加载和测试
-
-我们研究 React 的服务器渲染时并没有花费很大的步骤,因为我们发现一个类似于 Next.js 的产品,React 作者 Jordan Walke 写的[react-page](https://github.com/facebookarchive/react-page) (现在已经废弃)
-
-
-
-
-
-## 贡献
-
-可查看 [contributing.md](./contributing.md)
-
-
-
-## 作者
-
-- Arunoda Susiripala ([@arunoda](https://twitter.com/arunoda)) – [ZEIT](https://zeit.co)
-- Tim Neutkens ([@timneutkens](https://twitter.com/timneutkens)) – [ZEIT](https://zeit.co)
-- Naoyuki Kanezawa ([@nkzawa](https://twitter.com/nkzawa)) – [ZEIT](https://zeit.co)
-- Tony Kovanen ([@tonykovanen](https://twitter.com/tonykovanen)) – [ZEIT](https://zeit.co)
-- Guillermo Rauch ([@rauchg](https://twitter.com/rauchg)) – [ZEIT](https://zeit.co)
-- Dan Zajdband ([@impronunciable](https://twitter.com/impronunciable)) – Knight-Mozilla / Coral Project
diff --git a/examples/amp/pages/index.js b/examples/amp/pages/index.js
index b9af23a3cf63c..f7952214e0f1f 100644
--- a/examples/amp/pages/index.js
+++ b/examples/amp/pages/index.js
@@ -18,6 +18,22 @@ export default () => {
The Cat (AMP-first Page)
Meowwwwwwww
+
+
+
Cat ipsum dolor sit amet ,
eat grass, throw it back up but refuse to leave cardboard box or groom
diff --git a/packages/next/build/webpack/config/blocks/css/plugins.ts b/packages/next/build/webpack/config/blocks/css/plugins.ts
index 81b9a9bcbc844..cbf5166a3cf2d 100644
--- a/packages/next/build/webpack/config/blocks/css/plugins.ts
+++ b/packages/next/build/webpack/config/blocks/css/plugins.ts
@@ -193,6 +193,15 @@ export async function getPostCssPlugins(
}
throw new Error(genericErrorText)
}
+ } else if (typeof plugin === 'function') {
+ console.error(
+ `${chalk.red.bold(
+ 'Error'
+ )}: A PostCSS Plugin was passed as a function using require(), but it must be provided as a ${chalk.bold(
+ 'string'
+ )}.`
+ )
+ throw new Error(genericErrorText)
} else {
console.error(
`${chalk.red.bold(
diff --git a/test/integration/css-customization/test/index.test.js b/test/integration/css-customization/test/index.test.js
index c16a70d710e82..2153553cb2e48 100644
--- a/test/integration/css-customization/test/index.test.js
+++ b/test/integration/css-customization/test/index.test.js
@@ -331,6 +331,23 @@ describe('Bad CSS Customization Array (7)', () => {
})
})
+describe('Bad CSS Customization Array (8)', () => {
+ const appDir = join(fixturesDir, 'bad-custom-configuration-arr-8')
+
+ beforeAll(async () => {
+ await remove(join(appDir, '.next'))
+ })
+
+ it('should fail the build', async () => {
+ const { stderr } = await nextBuild(appDir, [], { stderr: true })
+
+ expect(stderr).toMatch(
+ /A PostCSS Plugin was passed as a function using require\(\), but it must be provided as a string/
+ )
+ expect(stderr).toMatch(/Build error occurred/)
+ })
+})
+
describe('Bad CSS Customization Function', () => {
const appDir = join(fixturesDir, 'bad-custom-configuration-func')
diff --git a/test/integration/css-fixtures/bad-custom-configuration-arr-8/pages/_app.js b/test/integration/css-fixtures/bad-custom-configuration-arr-8/pages/_app.js
new file mode 100644
index 0000000000000..17a2196742e95
--- /dev/null
+++ b/test/integration/css-fixtures/bad-custom-configuration-arr-8/pages/_app.js
@@ -0,0 +1,12 @@
+import React from 'react'
+import App from 'next/app'
+import '../styles/global.css'
+
+class MyApp extends App {
+ render() {
+ const { Component, pageProps } = this.props
+ return
+ }
+}
+
+export default MyApp
diff --git a/test/integration/css-fixtures/bad-custom-configuration-arr-8/pages/index.js b/test/integration/css-fixtures/bad-custom-configuration-arr-8/pages/index.js
new file mode 100644
index 0000000000000..b3ba78da2d5e1
--- /dev/null
+++ b/test/integration/css-fixtures/bad-custom-configuration-arr-8/pages/index.js
@@ -0,0 +1,3 @@
+export default function Home() {
+ return
+}
diff --git a/test/integration/css-fixtures/bad-custom-configuration-arr-8/postcss.config.js b/test/integration/css-fixtures/bad-custom-configuration-arr-8/postcss.config.js
new file mode 100644
index 0000000000000..5f1f2140125eb
--- /dev/null
+++ b/test/integration/css-fixtures/bad-custom-configuration-arr-8/postcss.config.js
@@ -0,0 +1,3 @@
+module.exports = {
+ plugins: [require('postcss-trolling')],
+}
diff --git a/test/integration/css-fixtures/bad-custom-configuration-arr-8/styles/global.css b/test/integration/css-fixtures/bad-custom-configuration-arr-8/styles/global.css
new file mode 100644
index 0000000000000..78d27f7edd8e4
--- /dev/null
+++ b/test/integration/css-fixtures/bad-custom-configuration-arr-8/styles/global.css
@@ -0,0 +1,14 @@
+/* this should pass through untransformed */
+@media (480px <= width < 768px) {
+ a::before {
+ content: '';
+ }
+ ::placeholder {
+ color: green;
+ }
+}
+
+/* this should be transformed to width/height */
+.video {
+ -xyz-max-size: 400rem 300rem;
+}