├── .nvmrc ├── .yarnrc ├── base-commit.json ├── components ├── intersection-observer │ ├── index.js │ ├── utils.js │ ├── manager.js │ └── intersection-observer.js ├── hoc │ └── pure.js ├── icons │ ├── arrow-right.js │ └── github.js ├── docs │ ├── text │ │ ├── quotes.js │ │ ├── headings.js │ │ ├── code.js │ │ └── link.js │ ├── head.js │ ├── documentation.js │ ├── heading.js │ ├── sidebar.js │ └── docs.mdx ├── contributions │ ├── contributor.js │ └── contributions.mdx ├── media-query.js ├── logo.js ├── container.js ├── header.js ├── navbar.js └── page.js ├── .gitignore ├── public └── static │ └── favicon │ ├── favicon.ico │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── mstile-150x150.png │ ├── apple-touch-icon.png │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ ├── browserconfig.xml │ ├── site.webmanifest │ └── safari-pinned-tab.svg ├── scripts ├── copy-latest-target.sh └── show-lastest-commit.sh ├── .editorconfig ├── lib ├── polyfill.js └── rehype-readme.js ├── .eslintrc.json ├── pages ├── index.js ├── contribution │ └── index.js ├── _document.js └── docs │ └── index.js ├── README.md ├── next.config.js └── package.json /.nvmrc: -------------------------------------------------------------------------------- 1 | lts/erbium 2 | -------------------------------------------------------------------------------- /.yarnrc: -------------------------------------------------------------------------------- 1 | save-prefix "" 2 | -------------------------------------------------------------------------------- /base-commit.json: -------------------------------------------------------------------------------- 1 | { 2 | "ref": "d16f39a20bbdcaf821480817bc283ab2ead3aa64" 3 | } 4 | -------------------------------------------------------------------------------- /components/intersection-observer/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './intersection-observer'; 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .next 2 | .idea 3 | node_modules 4 | .DS_Store 5 | .vscode 6 | out 7 | yarn-error.log 8 | bundles 9 | -------------------------------------------------------------------------------- /public/static/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nextjs-ja-translation/nextjs-docs-ja/HEAD/public/static/favicon/favicon.ico -------------------------------------------------------------------------------- /public/static/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nextjs-ja-translation/nextjs-docs-ja/HEAD/public/static/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /public/static/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nextjs-ja-translation/nextjs-docs-ja/HEAD/public/static/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /public/static/favicon/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nextjs-ja-translation/nextjs-docs-ja/HEAD/public/static/favicon/mstile-150x150.png -------------------------------------------------------------------------------- /public/static/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nextjs-ja-translation/nextjs-docs-ja/HEAD/public/static/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /public/static/favicon/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nextjs-ja-translation/nextjs-docs-ja/HEAD/public/static/favicon/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/static/favicon/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nextjs-ja-translation/nextjs-docs-ja/HEAD/public/static/favicon/android-chrome-512x512.png -------------------------------------------------------------------------------- /scripts/copy-latest-target.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | dst_path="./components/docs/docs.mdx" 4 | 5 | curl -o "${dst_path}" https://raw.githubusercontent.com/5t111111/nextjs-docs-ja-omegat/master/target/docs.mdx 6 | -------------------------------------------------------------------------------- /scripts/show-lastest-commit.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | pushd $NEXT_SITE_REPOSITORY_PATH > /dev/null 4 | latest_commit=$(git log --pretty=format:'%h' -n 1 -- components/docs/docs.mdx) 5 | echo $latest_commit 6 | popd > /dev/null 7 | 8 | -------------------------------------------------------------------------------- /components/hoc/pure.js: -------------------------------------------------------------------------------- 1 | import { PureComponent } from 'react' 2 | 3 | export default function (Comp) { 4 | return class extends PureComponent { 5 | render () { 6 | return 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [{package.json,*.yml}] 12 | indent_style = space 13 | indent_size = 2 -------------------------------------------------------------------------------- /components/icons/arrow-right.js: -------------------------------------------------------------------------------- 1 | export default () => 2 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /lib/polyfill.js: -------------------------------------------------------------------------------- 1 | import "core-js/fn/array/find"; 2 | import "core-js/fn/array/find-index"; 3 | import "core-js/fn/array/from"; 4 | import "core-js/fn/object/entries"; 5 | import "core-js/fn/object/values"; 6 | import "core-js/fn/symbol/iterator"; 7 | import "core-js/fn/string/starts-with"; 8 | -------------------------------------------------------------------------------- /public/static/favicon/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #000000 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /components/docs/text/quotes.js: -------------------------------------------------------------------------------- 1 | export const Blockquote = ({ children, ...props }) => ( 2 |
3 | {children} 4 | 5 | 20 |
21 | ); 22 | -------------------------------------------------------------------------------- /public/static/favicon/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Next.js", 3 | "short_name": "Next.js", 4 | "icons": [ 5 | { 6 | "src": "/static/favicons/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/static/favicons/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#000000", 17 | "background_color": "#000000", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /components/contributions/contributor.js: -------------------------------------------------------------------------------- 1 | export default props => { 2 | return ( 3 |
4 |
5 | {props.avatarURL} 10 |
11 |
12 | 13 | {props.username} 14 | 15 |
16 |
17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": ["airbnb", "prettier", "prettier/react"], 4 | "env": { 5 | "browser": true 6 | }, 7 | "rules": { 8 | "react/react-in-jsx-scope": 0, 9 | "react/prop-types": 0, 10 | "react/jsx-filename-extension": 0, 11 | "react/destructuring-assignment": 0, 12 | "jsx-a11y/anchor-is-valid": 0, 13 | "no-nested-ternary": 0, 14 | "array-callback-return": 0, 15 | "consistent-return": 0, 16 | "no-param-reassign": 0, 17 | "lines-between-class-members": 0, 18 | "global-require": 0, 19 | "import/prefer-default-export": 0, 20 | "import/no-extraneous-dependencies": 0 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /components/icons/github.js: -------------------------------------------------------------------------------- 1 | export default () => 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /pages/index.js: -------------------------------------------------------------------------------- 1 | import withPure from '../components/hoc/pure'; 2 | 3 | const Content = withPure(() => ( 4 |
5 |

Next.js 公式ドキュメント日本語翻訳プロジェクト

6 |

7 | 12 | Next.js の公式ドキュメント 13 | 14 | を日本語に翻訳するプロジェクトです。 15 |

16 | 24 |

25 | GitHub の翻訳プロジェクトは 26 | 31 | こちら 32 | 33 |

34 |
35 | )); 36 | 37 | export default () => ; 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nextjs-docs-ja 2 | 3 | [Next.js の公式ドキュメント](https://nextjs.org/docs/)を日本語に翻訳し公開するためのプロジェクトです。 4 | 5 | ## 翻訳対象 6 | 7 | 翻訳対象の元ファイルはこちらです。 8 | 9 | https://github.com/zeit/next-site/blob/master/components/docs/docs.mdx 10 | 11 | [components/docs/docs.mdx](https://github.com/5t111111/nextjs-docs-ja/blob/master/components/docs/docs.mdx) が日本語訳されたファイルになります。 12 | 13 | ## 翻訳プロジェクトを手伝ってくれる方へ 14 | 15 | 翻訳を手伝っていただける方を募集しています。 16 | 17 | - 翻訳を追加や修正 18 | - サイトの改善 19 | 20 | などをやっていただける場合、一般的な GitHub リポジトリ同様に pull-request を出していただければ取り込みます。 21 | 22 | 翻訳自体の作業は、翻訳メモリを利用するために以下のプロジェクトで OmegaT という翻訳ツールを利用していますが、メンテナが翻訳メモリへの反映を行いますので、翻訳に貢献いただける方は気にする必要はありません。 23 | https://github.com/5t111111/nextjs-docs-omegat 24 | 25 | ## 翻訳のベースコミット 26 | 27 | 翻訳元に更新があったことを検知するため、翻訳元となるファイルのコミットへの参照を記録したファイルを用意しています。 28 | 29 | - [base-commit.json](https://github.com/5t111111/nextjs-docs-ja/blob/master/base-commit.json) 30 | 31 | 翻訳に貢献いただく際は、基本的に上記コミットをベースとしてくださいますようお願いします。 32 | -------------------------------------------------------------------------------- /pages/contribution/index.js: -------------------------------------------------------------------------------- 1 | import Page from '../../components/page'; 2 | import Header from '../../components/header'; 3 | import Navbar from '../../components/navbar'; 4 | import Container from '../../components/container'; 5 | import { MediaQueryConsumer } from '../../components/media-query'; 6 | import withPure from '../../components/hoc/pure'; 7 | 8 | import Markdown from '../../components/contributions/contributions.mdx'; 9 | import { components } from '../../components/docs/documentation'; 10 | 11 | const Content = withPure(() => ); 12 | 13 | export default () => ( 14 | 15 | 16 | {({ isMobile }) => ( 17 |
22 | 23 |
24 | )} 25 |
26 | 27 | 28 | 29 |
30 | ); 31 | -------------------------------------------------------------------------------- /components/contributions/contributions.mdx: -------------------------------------------------------------------------------- 1 | import Contributor from "./contributor.js"; 2 | 3 | ## 貢献 4 | 5 | ### Next.js 公式ドキュメント翻訳プロジェクトメンテナ一覧 6 | 7 | 12 | 13 | ### Next.js 公式ドキュメント翻訳プロジェクト貢献者一覧 14 | 15 | 20 | 25 | 30 | 35 | -------------------------------------------------------------------------------- /components/docs/head.js: -------------------------------------------------------------------------------- 1 | import Head from "next/head"; 2 | 3 | export default ({ children, ...props }) => ( 4 | 5 | {`Documentation - ${props.title} | Next.js`} 6 | 10 | 11 | 12 | {props.description ? ( 13 | 14 | ) : null} 15 | {props.ogDescription ? ( 16 | 17 | ) : ( 18 | 19 | )} 20 | {props.video 21 | ? [ 22 | , 23 | , 24 | 25 | ] 26 | : null} 27 | 28 | {children} 29 | 30 | ); 31 | -------------------------------------------------------------------------------- /components/docs/text/headings.js: -------------------------------------------------------------------------------- 1 | const H1 = ({ children, ...props }) => ( 2 |

3 | {children} 4 | 5 | 10 |

11 | ); 12 | 13 | const H2 = ({ children, ...props }) => ( 14 |

15 | {children} 16 | 17 | 21 |

22 | ); 23 | 24 | const H3 = ({ children, ...props }) => ( 25 |

26 | {children} 27 | 28 | 32 |

33 | ); 34 | 35 | const H4 = ({ children, ...props }) => ( 36 |

37 | {children} 38 | 39 | 43 |

44 | ); 45 | 46 | const H5 = ({ children, ...props }) => ( 47 |
48 | {children} 49 | 50 | 55 |
56 | ); 57 | 58 | export { H1, H2, H3, H4, H5 }; 59 | -------------------------------------------------------------------------------- /components/media-query.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from "react"; 2 | 3 | const { 4 | Provider: MediaQueryProvider, 5 | Consumer: MediaQueryConsumer 6 | } = React.createContext({ 7 | isMobile: false, 8 | isTablet: false 9 | }); 10 | 11 | const withMediaQuery = Comp => 12 | class extends PureComponent { 13 | state = { 14 | isMobile: false, 15 | isTablet: false 16 | }; 17 | componentDidMount() { 18 | window.addEventListener("resize", this.onResize); 19 | this.onResize(); 20 | } 21 | componentWillUnmount() { 22 | window.removeEventListener("resize", this.onResize); 23 | } 24 | onResize = () => { 25 | const isMobile = window.innerWidth < 640; 26 | const isTablet = window.innerWidth < 960; 27 | 28 | if (isMobile !== this.state.isMobile) { 29 | this.setState({ isMobile }); 30 | } 31 | if (isTablet !== this.state.isTablet) { 32 | this.setState({ isTablet }); 33 | } 34 | }; 35 | render() { 36 | const { isMobile, isTablet } = this.state; 37 | 38 | return ( 39 | 40 | 41 | 42 | ); 43 | } 44 | }; 45 | 46 | export { MediaQueryProvider, MediaQueryConsumer, withMediaQuery }; 47 | -------------------------------------------------------------------------------- /components/docs/text/code.js: -------------------------------------------------------------------------------- 1 | export const Code = ({ children, syntax }) => ( 2 |
 3 |     {children}
 4 |     
21 |   
22 | ); 23 | 24 | export const InlineCode = ({ children, wrap = false }) => ( 25 | 26 | {children} 27 | 57 | 58 | ); 59 | -------------------------------------------------------------------------------- /components/logo.js: -------------------------------------------------------------------------------- 1 | import withPure from "./hoc/pure"; 2 | 3 | export default withPure(({ size }) => ( 4 | 16 | 21 | 22 | )); 23 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const webpack = require("webpack"); 3 | const rehypePrism = require("@mapbox/rehype-prism"); 4 | const nextMDX = require("@next/mdx"); 5 | const rehypeReadme = require("./lib/rehype-readme"); 6 | 7 | // only enable rehypeReadme for this file 8 | // because the github relative path replacement 9 | // might break things in other markdowns 10 | const withGitHubMDX = nextMDX({ 11 | extension: path.join(__dirname, "components", "docs", "docs.mdx"), 12 | options: { 13 | hastPlugins: [ 14 | rehypePrism, 15 | [ 16 | rehypeReadme, 17 | { 18 | repo: "zeit/next.js", 19 | branch: "master", 20 | level: 4 21 | } 22 | ] 23 | ] 24 | } 25 | }); 26 | 27 | const withContributionMDX = nextMDX({ 28 | extension: path.join( 29 | __dirname, 30 | "components", 31 | "contributions", 32 | "contributions.mdx" 33 | ) 34 | }); 35 | 36 | const withMDX = nextMDX({ 37 | extension: /\/(pages)\/(.+)\.mdx?$/, 38 | options: { 39 | hastPlugins: [rehypePrism] 40 | } 41 | }); 42 | 43 | const config = { 44 | pageExtensions: ["jsx", "js", "mdx"], 45 | webpack: (config, { dev, isServer }) => { 46 | config.plugins = config.plugins || []; 47 | config.plugins.push( 48 | new webpack.ContextReplacementPlugin( 49 | /highlight\.js[\/\\]lib[\/\\]languages$/, 50 | new RegExp(`^./(${["javascript", "json", "xml"].join("|")})$`) 51 | ) 52 | ); 53 | 54 | return config; 55 | } 56 | }; 57 | 58 | module.exports = withContributionMDX(withGitHubMDX(withMDX(config))); 59 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nextjs-docs-ja", 3 | "description": "Japanese Translation of Next.js Official documents", 4 | "version": "1.0.0", 5 | "repository": "5t111111/nextjs-docs-ja", 6 | "license": "MIT", 7 | "engines": { 8 | "node": ">=10.x" 9 | }, 10 | "scripts": { 11 | "dev": "next", 12 | "build": "next build", 13 | "export": "next export", 14 | "start": "next start", 15 | "lint": "eslint" 16 | }, 17 | "dependencies": { 18 | "@mapbox/rehype-prism": "^0.3.1", 19 | "@mdx-js/loader": "0.20.3", 20 | "@mdx-js/mdx": "0.20.3", 21 | "@mdx-js/tag": "0.20.3", 22 | "@next/mdx": "9.1.4", 23 | "babel-plugin-module-resolver": "^3.2.0", 24 | "classnames": "^2.2.6", 25 | "date-fns": "^2.8.1", 26 | "github-slugger": "1.2.1", 27 | "highlight.js": "^9.16.2", 28 | "intersection-observer": "^0.7.0", 29 | "mitt": "^1.2.0", 30 | "next": "9.1.4", 31 | "polished": "^3.4.2", 32 | "prop-types": "^15.7.2", 33 | "react": "^16.12.0", 34 | "react-dom": "^16.12.0", 35 | "react-frame-component": "^4.1.1", 36 | "react-highlight": "^0.12.0", 37 | "react-spring": "^8.0.27", 38 | "react-virtualized": "^9.21.2", 39 | "scroll-into-view-if-needed": "^2.2.20", 40 | "unist-util-visit": "2.0.1" 41 | }, 42 | "devDependencies": { 43 | "babel-eslint": "^10.0.3", 44 | "eslint": "^6.7.2", 45 | "eslint-config-airbnb": "^18.0.1", 46 | "eslint-config-prettier": "6.7.0", 47 | "eslint-plugin-import": "^2.18.2", 48 | "eslint-plugin-jsx-a11y": "^6.2.3", 49 | "eslint-plugin-react": "^7.17.0", 50 | "prettier": "^1.19.1" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /components/docs/text/link.js: -------------------------------------------------------------------------------- 1 | import NativeLink from "next/link"; 2 | 3 | export const GenericLink = props => { 4 | if (props.href.startsWith("/") && !props.href.startsWith("/docs")) { 5 | return ; 6 | } 7 | 8 | if (props.href.includes("@") || props.href.startsWith("#")) { 9 | return ; 10 | } 11 | 12 | return ; 13 | }; 14 | 15 | export const InternalLink = ({ href, as, children, error = false }) => ( 16 | 17 | 18 | {children} 19 | 20 | 30 | 31 | 32 | ); 33 | 34 | export const AnchorLink = ({ href, onClick, children }) => ( 35 | 36 | {children} 37 | 38 | 52 | 53 | ); 54 | 55 | export const ExternalLink = ({ href, children }) => ( 56 | 57 | {children} 58 | 59 | 67 | 68 | ); 69 | -------------------------------------------------------------------------------- /components/intersection-observer/utils.js: -------------------------------------------------------------------------------- 1 | export function isDOMNode(node) { 2 | return ( 3 | node && Object.prototype.hasOwnProperty.call(node, 'getBoundingClientRect') 4 | ); 5 | } 6 | 7 | export function parseOptions(options = {}) { 8 | return { 9 | root: options.root || null, 10 | rootMargin: parseRootMargin(options.rootMargin), 11 | threshold: parseThreshold(options.threshold) 12 | }; 13 | } 14 | 15 | export function hasEqualOptions(observer, options) { 16 | return ( 17 | equalPair(options.root, observer.root) && 18 | equalPair(options.rootMargin, observer.rootMargin) && 19 | equalPair(options.threshold, observer.thresholds) 20 | ); 21 | } 22 | 23 | function parseRootMargin(rootMargin) { 24 | const margins = (rootMargin || '0px').trim().split(/\s+/); 25 | margins.forEach(validateRootMargin); 26 | margins[1] = margins[1] || margins[0]; 27 | margins[2] = margins[2] || margins[0]; 28 | margins[3] = margins[3] || margins[1]; 29 | return margins.join(' '); 30 | } 31 | 32 | function validateRootMargin(margin) { 33 | if (!/^-?\d*\.?\d+(px|%)$/.test(margin)) { 34 | throw new Error('rootMargin must be specified as a CSS margin property'); 35 | } 36 | } 37 | 38 | function parseThreshold(threshold) { 39 | return !Array.isArray(threshold) 40 | ? [typeof threshold !== 'undefined' ? threshold : 0] 41 | : threshold; 42 | } 43 | 44 | function equalPair(optionA, optionB) { 45 | if (Array.isArray(optionA) && Array.isArray(optionB)) { 46 | if (optionA.length === optionB.length) { 47 | return optionA.every((element, idx) => 48 | equalPair(optionA[idx], optionB[idx]) 49 | ); 50 | } 51 | } 52 | return optionA === optionB; 53 | } 54 | -------------------------------------------------------------------------------- /pages/_document.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable react/no-danger */ 2 | import Document, { Head, Main, NextScript } from "next/document"; 3 | 4 | export default class NextSite extends Document { 5 | render() { 6 | return ( 7 | 8 | 9 | 13 | Next.js 14 | 15 | 20 | 26 | 32 | 33 | 38 | 39 | 40 | 44 | 45 | 46 | 47 | 48 |
49 | 50 | 51 | 52 | ); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /components/intersection-observer/manager.js: -------------------------------------------------------------------------------- 1 | import { hasEqualOptions, parseOptions } from './utils'; 2 | 3 | if (typeof window !== 'undefined') { 4 | require('intersection-observer'); 5 | } 6 | 7 | const manager = (function makeManager() { 8 | const observers = new Map(); 9 | 10 | function getObserver(options) { 11 | return ( 12 | findObserver(options) || 13 | new IntersectionObserver(intersectionCallback, options) 14 | ); 15 | } 16 | 17 | function findObserver(options = {}) { 18 | const parsedOptions = parseOptions(options); 19 | for (const observer of observers.keys()) { 20 | if (hasEqualOptions(observer, parsedOptions)) { 21 | return observer; 22 | } 23 | } 24 | return null; 25 | } 26 | 27 | function getObserverTargets(observer) { 28 | return !observers.has(observer) 29 | ? observers.set(observer, new Map()).get(observer) 30 | : observers.get(observer); 31 | } 32 | 33 | function observeTarget(observer, target, handler) { 34 | const targets = getObserverTargets(observer); 35 | targets.set(target, handler); 36 | observer.observe(target); 37 | } 38 | 39 | function unobserveTarget(observer, target) { 40 | const handlers = getObserverTargets(observer); 41 | handlers.delete(target); 42 | observer.unobserve(target); 43 | } 44 | 45 | function intersectionCallback(entries, observer) { 46 | for (let entry of entries) { 47 | const handlers = getObserverTargets(observer); 48 | const handler = handlers.get(entry.target); 49 | if (handler) { 50 | handler(entry); 51 | } 52 | } 53 | } 54 | 55 | return { 56 | getObserver, 57 | observeTarget, 58 | unobserveTarget 59 | }; 60 | })(); 61 | 62 | export default manager; 63 | export const { getObserver } = manager; 64 | export const { observeTarget } = manager; 65 | export const { unobserveTarget } = manager; 66 | -------------------------------------------------------------------------------- /public/static/favicon/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.11, written by Peter Selinger 2001-2013 9 | 10 | 12 | 26 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /pages/docs/index.js: -------------------------------------------------------------------------------- 1 | import Page from "../../components/page"; 2 | import Header from "../../components/header"; 3 | import Navbar from "../../components/navbar"; 4 | import Container from "../../components/container"; 5 | import { MediaQueryConsumer } from "../../components/media-query"; 6 | import withPure from "../../components/hoc/pure"; 7 | 8 | import Markdown, { headings } from "../../components/docs/docs.mdx"; 9 | import Documentation, { components } from "../../components/docs/documentation"; 10 | import baseCommit from "../../base-commit.json"; 11 | 12 | const Content = withPure(() => ); 13 | 14 | const TranslationInformation = () => { 15 | const baseCommitUrl = `https://github.com/zeit/next-site/tree/${baseCommit.ref}`; 16 | 17 | return ( 18 |
19 |

20 | このドキュメント日本語翻訳は、ドキュメント原文の登録されているリポジトリのコミット 21 | 22 | 23 | {baseCommit.ref} 24 | 25 | 26 | を元に翻訳されています。 27 |

28 |

29 | 情報が古くなっている場合もありますので、できるだけ 30 | 35 | 原文のドキュメント 36 | 37 | で最新の情報を参照ください。 38 |

39 | 47 |
48 | ); 49 | }; 50 | 51 | export default () => ( 52 | 53 | 54 | {({ isMobile }) => ( 55 |
60 | 61 |
62 | )} 63 |
64 | 65 | 66 | 67 | 68 | 69 | 70 |
71 | ); 72 | -------------------------------------------------------------------------------- /components/container.js: -------------------------------------------------------------------------------- 1 | export default function Container({ 2 | center, 3 | vCenter, 4 | dark, 5 | gray, 6 | wide, 7 | small, 8 | padding, 9 | overflow, 10 | minHeight, 11 | dotBackground, 12 | children, 13 | mobileStyle, 14 | divider, 15 | ...props 16 | }) { 17 | return ( 18 |
19 | 71 | {children} 72 |
73 | ); 74 | } 75 | -------------------------------------------------------------------------------- /components/intersection-observer/intersection-observer.js: -------------------------------------------------------------------------------- 1 | // Packages 2 | import { Component, cloneElement, Children } from 'react'; 3 | import { findDOMNode } from 'react-dom'; 4 | import PropTypes from 'prop-types'; 5 | 6 | // Private Observer Manager functions and manager 7 | import { getObserver, observeTarget, unobserveTarget } from './manager'; 8 | import { hasEqualOptions, isDOMNode } from './utils'; 9 | 10 | export default class Observer extends Component { 11 | static propTypes = { 12 | disabled: PropTypes.bool, 13 | once: PropTypes.bool, 14 | onIntersect: PropTypes.func.isRequired, 15 | render: PropTypes.func, 16 | root: PropTypes.element, 17 | rootMargin: PropTypes.string, 18 | threshold: PropTypes.oneOfType([ 19 | PropTypes.arrayOf(PropTypes.number), 20 | PropTypes.number 21 | ]), 22 | value: PropTypes.string 23 | }; 24 | 25 | static defaultProps = { 26 | disabled: false, 27 | once: false 28 | }; 29 | 30 | shouldReobserve = false; 31 | 32 | componentDidMount() { 33 | this.observer = getObserver(getOptions(this.props)); 34 | this.observe(); 35 | } 36 | 37 | UNSAFE_componentWillReceiveProps(nextProps) { 38 | const nextOptions = getOptions(nextProps); 39 | if (!hasEqualOptions(this.observer, nextOptions)) { 40 | this.unobserve(); 41 | this.observer = getObserver(nextOptions); 42 | this.shouldReobserve = true; 43 | } 44 | 45 | if (this.props.disabled && !nextProps.disabled) { 46 | this.shouldReobserve = true; 47 | } 48 | 49 | if (!this.props.disabled && nextProps.disabled) { 50 | this.unobserve(); 51 | } 52 | } 53 | 54 | componentDidUpdate() { 55 | if (this.shouldReobserve) { 56 | this.observe(); 57 | this.shouldReobserve = false; 58 | } 59 | } 60 | 61 | componentWillUnmount() { 62 | this.unobserve(); 63 | } 64 | 65 | handleTarget = node => { 66 | // eslint-disable-next-line 67 | const element = isDOMNode(node) ? node : findDOMNode(node); 68 | if (this.target && this.target !== element) { 69 | this.unobserve(); 70 | this.shouldReobserve = true; 71 | } 72 | this.target = element; 73 | }; 74 | 75 | observe() { 76 | if (!this.props.disabled) { 77 | observeTarget(this.observer, this.target, this.handleIntersect); 78 | } 79 | } 80 | 81 | unobserve() { 82 | unobserveTarget(this.observer, this.target); 83 | } 84 | 85 | handleIntersect = entry => { 86 | this.props.onIntersect(entry, this.props.value); 87 | if (this.props.once && entry.isIntersecting) { 88 | this.unobserve(); 89 | } 90 | }; 91 | 92 | render() { 93 | return this.props.render 94 | ? this.props.render({ innerRef: this.handleTarget }) 95 | : cloneElement(Children.only(this.props.children), { 96 | ref: this.handleTarget 97 | }); 98 | } 99 | } 100 | 101 | const getOptions = props => ({ 102 | root: props.root, 103 | rootMargin: props.rootMargin, 104 | threshold: props.threshold 105 | }); 106 | -------------------------------------------------------------------------------- /components/header.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from "react"; 2 | import classNames from "classnames"; 3 | import { useAmp } from "next/amp"; 4 | 5 | export default function Header(props) { 6 | const { 7 | height, 8 | shadow, 9 | zIndex, 10 | background, 11 | defaultActive, 12 | dotBackground, 13 | children 14 | } = props; 15 | const isAmp = useAmp(); 16 | 17 | const desktopHeight = height.desktop || Number(height) || 0; 18 | const mobileHeight = height.mobile || desktopHeight; 19 | const tabletHeight = height.tablet || desktopHeight; 20 | 21 | const desktopShadow = 22 | shadow.desktop || (typeof shadow === "boolean" ? shadow : false); 23 | const tabletShadow = 24 | shadow.tablet || (typeof shadow === "boolean" ? shadow : false); 25 | const mobileShadow = 26 | shadow.mobile || (typeof shadow === "boolean" ? shadow : false); 27 | 28 | return ( 29 |
30 |
35 | {children} 36 |
37 | 100 |
101 | ); 102 | } 103 | -------------------------------------------------------------------------------- /components/docs/documentation.js: -------------------------------------------------------------------------------- 1 | import Head from "./head"; 2 | import { H1, H2, H3, H4, H5 } from "./text/headings"; 3 | import { Blockquote } from "./text/quotes"; 4 | import { InlineCode, Code } from "./text/code"; 5 | import { GenericLink } from "./text/link"; 6 | import Heading from "./heading"; 7 | import Sidebar from "./sidebar"; 8 | 9 | export default function Documentation({ children, headings }) { 10 | return ( 11 | <> 12 | 13 | 14 |
15 | 16 |
17 |
{children}
18 |
19 | 20 | 51 |
52 | 53 | ); 54 | } 55 | 56 | const DocH2 = ({ children, id }) => ( 57 |
58 | 59 |

{children}

60 |
61 | 66 |
67 | ); 68 | 69 | const DocH3 = ({ children, id }) => ( 70 |
71 | 72 |

{children}

73 |
74 | 79 |
80 | ); 81 | 82 | const DocH4 = ({ children, id }) => ( 83 |
84 | 85 |

{children}

86 |
87 |
88 | ); 89 | 90 | const Details = ({ children }) => { 91 | return ( 92 |
93 | {children} 94 | 106 |
107 | ); 108 | }; 109 | 110 | const Summary = ({ children }) => { 111 | return ( 112 | 113 | {children} 114 | 124 | 125 | ); 126 | }; 127 | 128 | export const components = { 129 | h1: H1, 130 | h2: DocH2, 131 | h3: DocH3, 132 | h4: DocH4, 133 | h5: H5, 134 | blockquote: Blockquote, 135 | code: Code, 136 | inlineCode: InlineCode, 137 | a: GenericLink, 138 | details: Details, 139 | summary: Summary 140 | }; 141 | -------------------------------------------------------------------------------- /components/docs/heading.js: -------------------------------------------------------------------------------- 1 | import GithubSlugger from "github-slugger"; 2 | 3 | const PermalinkIcon = () => ( 4 | 5 | 6 | permalink 7 | 8 | 15 | 23 | 24 | 25 | 26 | ); 27 | 28 | function Heading(props) { 29 | const { component, className, children, ...rest } = props; 30 | return React.cloneElement( 31 | component, 32 | { 33 | className: [className, component.props.className || ""].join(" "), 34 | ...rest 35 | }, 36 | children 37 | ); 38 | } 39 | 40 | export default props => { 41 | const { offsetTop } = props; 42 | const component = props.children; 43 | const children = component.props.children || ""; 44 | 45 | let id = props.id; 46 | let text = children; 47 | 48 | const slugger = new GithubSlugger(); 49 | 50 | if (null == id) { 51 | // If there are sub components, convert them to text 52 | if (Array.isArray(children)) { 53 | text = children 54 | .map(child => { 55 | return typeof child === "object" ? child.props.children : child; 56 | }) 57 | .join(""); 58 | } 59 | 60 | id = slugger.slug(text); 61 | } 62 | 63 | const targetStyle = 64 | null != offsetTop 65 | ? { marginTop: -offsetTop + "px", paddingTop: offsetTop + "px" } 66 | : null; 67 | return ( 68 | 73 | 74 | {children} 75 | 76 | 77 | 78 | 147 | 148 | ); 149 | }; 150 | -------------------------------------------------------------------------------- /lib/rehype-readme.js: -------------------------------------------------------------------------------- 1 | const url = require('url'); 2 | const visit = require('unist-util-visit'); 3 | const GitHubSlugger = require('github-slugger'); 4 | 5 | /** 6 | * 1. relative urls => github urls 7 | * 2. relative images => github images 8 | */ 9 | const ABSOLUTE_URL = /^https?:\/\/|^\/\//i; 10 | const resolveURL = (base, href) => url.resolve(base, href.replace(/^\//, '')); 11 | 12 | const toAbsoluteURL = ({ repo, img }) => node => { 13 | // match relative url 14 | if (node.properties) { 15 | let href = 16 | node.tagName === 'a' ? node.properties.href : node.properties.src; 17 | if (href && href[0] !== '#' && !ABSOLUTE_URL.test(href)) { 18 | if (node.tagName === 'a') { 19 | node.properties.href = resolveURL(repo, href); 20 | } else { 21 | node.properties.src = resolveURL(img, href); 22 | } 23 | } 24 | } 25 | }; 26 | 27 | /** 28 | * tokenizer to match `
` or `` 29 | */ 30 | const C_TAB = '\t'; 31 | const C_SPACE = ' '; 32 | const C_NEWLINE = '\n'; 33 | 34 | function generateTokenizer(name, repo) { 35 | return function(eat, value) { 36 | let index = 0; 37 | let length = value.length; 38 | let next; 39 | let line; 40 | 41 | let sequence = [ 42 | new RegExp('^<' + name + '(?=(s|>|$))'), 43 | new RegExp(''), 44 | name.length + 2 45 | ]; 46 | 47 | // eat initial spacing 48 | while (index < length) { 49 | let character = value.charAt(index); 50 | if (character !== C_TAB && character !== C_SPACE) { 51 | break; 52 | } 53 | index++; 54 | } 55 | 56 | next = value.indexOf(C_NEWLINE, index + 1); 57 | next = next === -1 ? length : next; 58 | line = value.slice(index, next); 59 | 60 | if (!sequence[0].test(line)) { 61 | return; 62 | } 63 | 64 | index = index + sequence[2]; 65 | let now = eat.now(); 66 | now.column += index; 67 | now.offset += index; 68 | 69 | let valueStart = index; 70 | 71 | // match content 72 | while (index < length) { 73 | next = value.indexOf(C_NEWLINE, index + 1); 74 | next = next === -1 ? length : next; 75 | line = value.slice(index + 1, next); 76 | 77 | if (sequence[1].test(line)) { 78 | if (line) { 79 | index = next; 80 | } 81 | break; 82 | } 83 | 84 | index = next; 85 | } 86 | 87 | let subvalue = value.slice(0, index); 88 | let content = value.slice(valueStart, index - valueStart - 1); 89 | 90 | // trim content 91 | content = content 92 | .split('\n') 93 | .map(str => str.trim()) 94 | .join('\n'); 95 | 96 | // match links inside html (``) 97 | content = content.replace(/]*)(>[^<]+<\/a>)/g, function( 98 | str, 99 | attr, 100 | rest 101 | ) { 102 | attr = attr.replace(/href=(['"])([^'"]*)\1/, function(str, quote, href) { 103 | if (href && href[0] !== '#' && !ABSOLUTE_URL.test(href)) { 104 | return 'href=' + quote + resolveURL(repo, href) + quote; 105 | } 106 | return 'href=' + quote + href + quote; 107 | }); 108 | 109 | // add target='_blank' 110 | if (!attr.match(/target=['"]_blank\1/)) { 111 | attr += ' target="_blank"'; 112 | } 113 | 114 | return ' { 143 | let headings = [ 144 | { 145 | level: 0, 146 | title: 'Table of Contents' 147 | } 148 | ]; 149 | let levelHeads = [headings]; 150 | let tags = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].slice(0, level); 151 | 152 | visit( 153 | ast, 154 | node => tags.indexOf(node.tagName) !== -1, 155 | node => { 156 | let level = tags.indexOf(node.tagName) + 1; 157 | let data = { 158 | level, 159 | title: node.children.map(node => node.value).join('') 160 | }; 161 | 162 | do { 163 | if (!levelHeads.length) { 164 | break; 165 | } 166 | 167 | let currentLevelList = levelHeads[levelHeads.length - 1]; 168 | if (!currentLevelList.length || currentLevelList[0].level === level) { 169 | // empty 170 | currentLevelList.push(data); 171 | break; 172 | } else if (currentLevelList[0].level < level) { 173 | // add as child 174 | let newLevelList = [data]; 175 | levelHeads.push(newLevelList); 176 | currentLevelList.push(newLevelList); 177 | break; 178 | } else { 179 | // pop 180 | while (currentLevelList.length && currentLevelList[0].level > level) { 181 | levelHeads.pop(); 182 | currentLevelList = levelHeads[levelHeads.length - 1]; 183 | } 184 | } 185 | } while (true); 186 | } 187 | ); 188 | 189 | return headings.slice(1); 190 | }; 191 | 192 | /** 193 | * The plugin 194 | */ 195 | const readme = function(options) { 196 | if (!options.repo) { 197 | throw new Error( 198 | 'Please set a GitHub repo name in `options.repo`! e.g. `zeit/next.js`' 199 | ); 200 | } 201 | options.branch = options.branch || 'master'; 202 | options.level = options.level || 6; 203 | 204 | // base URL 205 | let repo = 206 | 'https://github.com/' + options.repo + '/blob/' + options.branch + '/'; 207 | let img = 208 | 'https://raw.githubusercontent.com/' + 209 | options.repo + 210 | '/' + 211 | options.branch + 212 | '/'; 213 | 214 | const Parser = this.Parser; 215 | 216 | const tokenizers = Parser.prototype.blockTokenizers; 217 | tokenizers.details = generateTokenizer('details', repo); 218 | tokenizers.summary = generateTokenizer('summary', repo); 219 | 220 | const methods = Parser.prototype.blockMethods; 221 | methods.splice(methods.indexOf('html'), 0, 'summary'); 222 | methods.splice(methods.indexOf('html'), 0, 'details'); 223 | 224 | return function(ast) { 225 | visit( 226 | ast, 227 | node => node.tagName === 'a' || node.tagName === 'img', 228 | toAbsoluteURL({ repo, img }) 229 | ); 230 | 231 | let tags = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].slice(0, options.level); 232 | const slugger = new GitHubSlugger(); 233 | 234 | visit(ast, 'element', node => { 235 | if (tags.indexOf(node.tagName) !== -1) { 236 | node.properties.id = slugger.slug( 237 | node.children.map(node => node.value).join('') 238 | ); 239 | } 240 | }); 241 | 242 | let headings = getHeadings(ast, options.level); 243 | ast.children.push({ 244 | type: 'export', 245 | value: 'export const headings = ' + JSON.stringify(headings) 246 | }); 247 | }; 248 | }; 249 | 250 | module.exports = readme; 251 | -------------------------------------------------------------------------------- /components/docs/sidebar.js: -------------------------------------------------------------------------------- 1 | import GithubSlugger from "github-slugger"; 2 | import Header from "../header"; 3 | import Navbar from "../navbar"; 4 | import Container from "../container"; 5 | import ArrowRight from "../icons/arrow-right"; 6 | 7 | function flattenHeadings(headings) { 8 | if (!Array.isArray(headings)) { 9 | return headings; 10 | } 11 | return [].concat(...headings.map(flattenHeadings)); 12 | } 13 | 14 | function slugifyHeadings(headings) { 15 | const slugger = new GithubSlugger(); 16 | 17 | return headings.map(heading => { 18 | // n.b. mutation is required here unfortunately 19 | // eslint-disable-next-line no-param-reassign 20 | heading.id = slugger.slug(heading.title); 21 | return heading; 22 | }); 23 | } 24 | 25 | export function SidebarNavItem({ item }) { 26 | const href = `#${item.id}`; 27 | const ampOn = `tap:AMP.navigateTo(url='${href}', target=_top)`; 28 | if (item.level === 2) { 29 | return ( 30 |
  • 31 | {item.title} 32 | 50 |
  • 51 | ); 52 | } 53 | 54 | let listStyle = ""; 55 | switch (item.level) { 56 | case 3: 57 | listStyle = "padding: 5px 3px 5px 0; font-size: 15px;"; 58 | break; 59 | case 4: 60 | listStyle = "padding: 3px 3px 3px 15px; font-size: 14px; color: #666;"; 61 | break; 62 | case 5: 63 | listStyle = "padding: 2px 3px 2px 30px; font-size: 13px; color: #666;"; 64 | break; 65 | case 6: 66 | listStyle = "padding: 2px 3px 2px 45px; font-size: 13px; color: #666;"; 67 | break; 68 | default: 69 | break; 70 | } 71 | 72 | return ( 73 |
  • 74 | {item.title} 75 | 95 |
  • 96 | ); 97 | } 98 | 99 | export function SidebarNavItemContainer({ headings }) { 100 | if (Array.isArray(headings)) { 101 | return ( 102 |
      103 | {headings.map((item, i) => { 104 | if (Array.isArray(item)) { 105 | return ( 106 |
    • 107 | 108 |
    • 109 | ); 110 | } 111 | return ; 112 | })} 113 | 119 |
    120 | ); 121 | } 122 | 123 | return ; 124 | } 125 | 126 | export default function Sidebar({ headings, mobile, desktop }) { 127 | slugifyHeadings(flattenHeadings(headings)); 128 | 129 | return ( 130 | <> 131 | {mobile && ( 132 | <> 133 |
    142 | 143 | 168 |
    169 | 170 | )} 171 | 210 | 223 | 224 | {desktop && ( 225 |
    226 | 229 |
    230 | )} 231 | 265 | 266 | ); 267 | } 268 | -------------------------------------------------------------------------------- /components/navbar.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | import Link from "next/link"; 3 | import { withRouter } from "next/router"; 4 | import classNames from "classnames"; 5 | 6 | import NextLogo from "./logo"; 7 | import Container from "./container"; 8 | 9 | import GitHubLogo from "./icons/github"; 10 | 11 | function Navbar({ className, hideLogo, route, isMobile }) { 12 | const [scrollPosition, setScrollPosition] = useState(0); 13 | const LOGO_TOP = 170; 14 | 15 | const handleScroll = () => { 16 | if (window.scrollY !== 0) { 17 | setScrollPosition(window.scrollY); 18 | } 19 | }; 20 | 21 | useEffect(() => { 22 | window.addEventListener("scroll", handleScroll); 23 | return () => { 24 | window.removeEventListener("scroll", handleScroll); 25 | }; 26 | }, []); 27 | 28 | if (isMobile) { 29 | return ( 30 | 31 |

    32 | Next.js 33 |

    34 | 166 |
    167 | ); 168 | } 169 | 170 | return ( 171 | 172 |

    173 | Next.js 174 |

    175 | 304 |
    305 | ); 306 | } 307 | 308 | export default withRouter(({ router, hideLogo = false }) => { 309 | const { route } = router; 310 | 311 | const hideLogoDesktop = 312 | typeof hideLogo.desktop === "boolean" 313 | ? hideLogo.desktop 314 | : typeof hideLogo === "boolean" 315 | ? hideLogo 316 | : false; 317 | const hideLogoMobile = 318 | typeof hideLogo.mobile === "boolean" 319 | ? hideLogo.mobile 320 | : typeof hideLogo === "boolean" 321 | ? hideLogo 322 | : false; 323 | 324 | return ( 325 | <> 326 | 332 | 338 | 352 | 353 | ); 354 | }); 355 | -------------------------------------------------------------------------------- /components/page.js: -------------------------------------------------------------------------------- 1 | import Head from "next/head"; 2 | 3 | import { withMediaQuery } from "./media-query"; 4 | 5 | function Page({ title, description, children }) { 6 | return ( 7 |
    8 | 9 | {title || "Next.js - The React Framework"} 10 | 16 | 17 | 24 | 381 | {children} 382 |
    383 | ); 384 | } 385 | 386 | export default withMediaQuery(Page); 387 | -------------------------------------------------------------------------------- /components/docs/docs.mdx: -------------------------------------------------------------------------------- 1 | ## 使い方 2 | 3 | ### セットアップ 4 | 5 | #### クイックスタート 6 | 7 | ```bash 8 | npx create-next-app 9 | ``` 10 | 11 | _([npx](https://medium.com/@maybekatz/introducing-npx-an-npm-package-runner-55f7d4bd282b) は npm 5.2 以上に同梱されています。[古いバージョンの npm ではこちらの手順を参照ください。](https://gist.github.com/timer/833d9946fa8a05ba855729d05a38ac23))_ 12 | 13 | #### 手動でのセットアップ 14 | 15 | 以下をプロジェクトにインストールしてください。 16 | 17 | ```bash 18 | npm install --save next react react-dom 19 | ``` 20 | 21 | 次に、package.json にスクリプトを追加してください。 22 | 23 | ```json 24 | { 25 | "scripts": { 26 | "dev": "next", 27 | "build": "next build", 28 | "start": "next start" 29 | } 30 | } 31 | ``` 32 | 33 | ファイルシステム自体をメインの API として利用できます。すべての `.js` ファイルがルーティングとして機能し、それらのファイルは自動的に処理されレンダリングされます。 34 | 35 | `./pages/index.js` ファイルをプロジェクトに追加してみましょう: 36 | 37 | ```jsx 38 | function Home() { 39 | return
    Welcome to Next.js!
    40 | } 41 | 42 | export default Home 43 | ``` 44 | 45 | 追加したら、`npm run dev` を実行し、`http://localhost:3000` を開いてください。別のポートに変更したい場合は `npm run dev -- -p <ポート番号>` として起動します。 46 | 47 | これだけで以下が実現できています: 48 | 49 | - (webpack と babel を利用した) 自動的なトランスパイルとビルド 50 | - コードのホットリローディング 51 | - `./pages` 配下のファイルの構造化とサーバーサイドレンダリング 52 | - 静的ファイルの配布`./public/` は `/` にマッピングされます (プロジェクトに [`./static/` ディレクトリを作成](#static-file-serving-eg-images)する必要があります。) 53 | 54 | ### 自動的なコードの分割 55 | 56 | `import` したものはすべて「各ページごとに」バンドルされて配布されます。これはつまり、ページに必要のないコードが無駄に読み込まれることがないということを意味しています! 57 | 58 | ```jsx 59 | import cowsay from 'cowsay-browser' 60 | 61 | function CowsayHi() { 62 | return
    {cowsay.say({ text: 'hi there!' })}
    63 | } 64 | 65 | export default CowsayHi 66 | ``` 67 | 68 | ### CSS 69 | 70 | #### 組み込みの CSS サポート 71 | 72 |
    73 | 74 | 77 |
    78 | 79 | Next.js には [styled-jsx](https://github.com/zeit/styled-jsx) の機能が同梱されており、スコープを分離した CSS の適用が可能になっています。これは Web Components の「Shadow CSS」に似た機能を提供することを目的としています (残念ながら Shadow CSS は[サーバーサイドレンダリングで利用することができません](https://github.com/w3c/webcomponents/issues/71)) 80 | 81 | ```jsx 82 | function HelloWorld() { 83 | return ( 84 |
    85 | Hello world 86 |

    scoped!

    87 | 100 | 105 |
    106 | ) 107 | } 108 | 109 | export default HelloWorld 110 | ``` 111 | 112 | [styled-jsx のドキュメント](https://www.npmjs.com/package/styled-jsx) により多くの例が書かれています。 113 | 114 | #### CSS-in-JS 115 | 116 |
    117 | 118 | 119 | 120 | 128 |
    129 | 130 | 既存のどんな CSS-in-JS も利用することができます。一番シンプルなのはインラインで記述するものです: 131 | 132 | ```jsx 133 | function HiThere() { 134 | return

    hi there

    135 | } 136 | 137 | export default HiThere 138 | ``` 139 | 140 | より洗練された CSS-in-JS のソリューションを使いたい場合には、サーバーサイドレンダリングでスタイルを設定するための実装を追加する必要があるでしょう。これは、各ページをラップする独自の[カスタム ``](#custom-document) コンポーネントを定義することで実現できます。 141 | 142 | #### CSS / Sass / Less / Stylus ファイルのインポート 143 | 144 | `.css` / `.scss` / `.less` / `.styl` ファイルをインポートするためには、サーバーサイドでリンダリングされるアプリケーション用の設定が施された以下のモジュールを利用してください。 145 | 146 | - [@zeit/next-css](https://github.com/zeit/next-plugins/tree/master/packages/next-css) 147 | - [@zeit/next-sass](https://github.com/zeit/next-plugins/tree/master/packages/next-sass) 148 | - [@zeit/next-less](https://github.com/zeit/next-plugins/tree/master/packages/next-less) 149 | - [@zeit/next-stylus](https://github.com/zeit/next-plugins/tree/master/packages/next-stylus) 150 | 151 | ### 静的ファイル (例: 画像) のサーブ 152 | 153 | プロジェクトのルートディレクトリに `public` というディレクトリを作成します。配置したファイルをコードから参照するには、 `/` のベース URL 直下を指定します。 154 | 155 | ```jsx 156 | function MyImage() { 157 | return my image 158 | } 159 | 160 | export default MyImage 161 | ``` 162 | 163 | つまり、ルートディレクトリで静的ファイルを公開するには、 `public` というフォルダーを追加し、そこに置かれたファイルはルートから参照可能ということです (例えば `/robots.txt`) 。 164 | 165 | _注意: ディレクトリ名を `public` 以外にはしないようにしてください。この名前は変更不可能であり、Next.js は唯一このディレクトリだけを静的ファイルの公開に利用します。_ 166 | 167 | ### 動的なルーティング 168 | 169 |
    170 | 171 | 174 |
    175 | 176 | 複雑なアプリケーションでは、事前に定義されたパスによってルートを定義するのだけでは不足な場合があります。そのため、Next.js では、 `[param]` のようにページに角括弧 (ブラケット) を設定することで動的なルーティングをすることができます。(これは slug や pretty url などと呼ばれることもあります) 177 | 178 | `pages/post/[pid].js` というページが以下の内容であるとします: 179 | 180 | ```jsx 181 | import { useRouter } from 'next/router' 182 | 183 | const Post = () => { 184 | const router = useRouter() 185 | const { pid } = router.query 186 | 187 | return

    Post: {pid}

    188 | } 189 | 190 | export default Post 191 | ``` 192 | 193 | このとき、`/post/1` や `/post/abc` などのルートは `pages/post/[pid].js` にマッチします。 194 | そして、マッチしたパスのパラメータはクエリパラメータとしてページに送られます。 195 | 196 | 例えば、`/post/abc` というルートは次の `query` オブジェクトを持ちます: `{ pid: 'abc' }` 。 197 | 同様に、`/post/abc?foo=bar` であれば `query` オブジェクトは次のようになります: `{ foo: 'bar', pid: 'abc' }` 。 198 | 199 | > 注意: 複数の動的なルートセグメントがあるときも同様です。 200 | > 201 | > 例えば、`pages/post/[pid]/[comment].js` は `/post/1/a-comment` にマッチしますが、 202 | > そのときの `query` オブジェクトは次のようになります: `{ pid: '1', comment: 'a-comment' }` 。 203 | 204 | `/post/abc` に対する `` はこのようになります: 205 | 206 | ```jsx 207 | 208 | First Post 209 | 210 | ``` 211 | 212 | - `href`: `pages` ディレクトリ以下のパス 213 | - `as`: ブラウザのアドレスバーに表示されるパス 214 | 215 | `href` はファイルシステム上のパスなので、ランタイムにそれを変更することはできません。したがって、パスを動的に設定する必要がある場合には `as` を動的に設定します。例えば、以下はリンクのリストを作成する例です: 216 | 217 | ```jsx 218 | const pids = ['id1', 'id2', 'id3'] 219 | { 220 | pids.map(pid => ( 221 | 222 | Post {pid} 223 | 224 | )) 225 | } 226 | ``` 227 | 228 | > [`` リンクに関しての詳細はこちらを参照ください](#with-link) 。 229 | 230 | もしクエリとルートのパラメータが同一の名前だった場合には、クエリのパラメータはルートのパラメータで上書きされることに注意してください。 231 | 例えば、`/post/abc?pid=bcd` は次の `query` オブジェクトを持ちます: `{ pid: 'abc' }` 。 232 | 233 | > **メモ**: 事前定義された静的なルーティングは動的なルーティングより優先されます。 234 | > 例えば、`pages/post/[pid].js` と `pages/post/create.js` というルートが存在する場合、`/post/create` は `pages/post/create.js` にマッチします。`[pid]` の動的なルーティングにはマッチしません。 235 | 236 | > **メモ**: [自動静的最適化](#automatic-static-optimization) されたページはルートパラメータなしで hydrate されます (`query` は `{}` のように空になります) 。 237 | > hydration されたあと、Next.js はクエリパラメータを `query` オブジェクトで渡すようにアプリケーションを更新します。 238 | > アプリケーション的にこの挙動だと都合が悪い場合には、`getInitialProps` 内でクエリパラメータをキャプチャすることでこの静的最適化をオプトアウトすることができます。 239 | 240 | > **メモ**: [ZEIT Now](https://zeit.co/now) にデプロイする場合、動的ルーティングは特に設定なしで動作します。 241 | > したがって、`now.json` でカスタムルーティングを構成する必要はありません。 242 | > 243 | > ZEIT Now に Next.js アプリケーションをデプロイすることについてもっと知りたいときは、[_Deploying a Next.js App_ Learn section](https://nextjs.org/learn/basics/deploying-a-nextjs-app) を参照ください。 244 | 245 | ### `` への挿入 246 | 247 |
    248 | Examples 249 | 253 |
    254 | 255 | ページの `` に要素を追加するために組み込みのコンポーネントを利用することができます。 256 | 257 | ```jsx 258 | import Head from 'next/head' 259 | 260 | function IndexPage() { 261 | return ( 262 |
    263 | 264 | My page title 265 | 266 | 267 |

    Hello world!

    268 |
    269 | ) 270 | } 271 | 272 | export default IndexPage 273 | ``` 274 | 275 | `` の中で要素が重複するのを避けるために `key` プロパティを使うことができます。これによって、あるタグが一度だけレンダリングされることを保証することができます。 276 | 277 | ```jsx 278 | import Head from 'next/head' 279 | 280 | function IndexPage() { 281 | return ( 282 |
    283 | 284 | My page title 285 | 290 | 291 | 292 | 297 | 298 |

    Hello world!

    299 |
    300 | ) 301 | } 302 | 303 | export default IndexPage 304 | ``` 305 | 306 | 例えば上記の例では、2番目の `` のみがレンダリングされます。 307 | 308 | _Note: The contents of `` get cleared upon unmounting the component, so make sure each page completely defines what it needs in ``, without making assumptions about what other pages added._ 309 | 310 | _Note: `` and `<meta>` elements need to be contained as **direct** children of the `<Head>` element, or wrapped into maximum one level of `<React.Fragment>`, otherwise the metatags won't be correctly picked up on clientside navigation._ 311 | 312 | ### データのフェッチとコンポーネントのライフサイクル 313 | 314 | <details> 315 | <summary><b>例</b></summary> 316 | <ul> 317 | <li><a href="/examples/data-fetch">Data fetch</a></li> 318 | </ul> 319 | </details> 320 | 321 | When you need state, lifecycle hooks or **initial data population** you can export a function component that uses [Hooks](https://reactjs.org/docs/hooks-intro.html) or a [class component](https://reactjs.org/docs/react-component.html). 322 | 323 | Using a function component: 324 | 325 | ```jsx 326 | import fetch from 'isomorphic-unfetch' 327 | 328 | function Page({ stars }) { 329 | return <div>Next stars: {stars}</div> 330 | } 331 | 332 | Page.getInitialProps = async ({ req }) => { 333 | const res = await fetch('https://api.github.com/repos/zeit/next.js') 334 | const json = await res.json() 335 | return { stars: json.stargazers_count } 336 | } 337 | 338 | export default Page 339 | ``` 340 | 341 | Using a class component: 342 | 343 | ```jsx 344 | import React from 'react' 345 | 346 | class HelloUA extends React.Component { 347 | static async getInitialProps({ req }) { 348 | const userAgent = req ?req.headers['user-agent'] : navigator.userAgent 349 | return { userAgent } 350 | } 351 | 352 | render() { 353 | return <div>Hello World {this.props.userAgent}</div> 354 | } 355 | } 356 | 357 | export default HelloUA 358 | ``` 359 | 360 | ページが読み込まれるときのデータを設定するために [`async`](https://zeit.co/blog/async-and-await) で static な `getInitialProps` メソッドを使っていることに注目してください。このメソッドは、JavaScript のプレーンな `Object` として扱えるものであれば何でも非同期的に取得して、それを `props` に含めます。 361 | 362 | サーバーサイドレンダリング時には `getInitialProps` の戻り値のデータはシリアライズされます。ちょうど `JSON.stringify` と似た感じです。`getInitialProps` が返すオブジェクトは必ず「プレーンな `Object`」でなければならず、`Date`,/ `Map` / `Set` は使用できないことに注意してください。 363 | 364 | 最初にページが読み込まれるとき、`getInitialProps` はサーバーサイドでのみ実行されます。`getInitialProps` がクライアントサイドで実行されるのは、`Link` コンポーネントかルーティング API を用いて別のルートに移動した場合のみです。 365 | 366 | <br/> 367 | 368 | > - `getInitialProps` can **not** be used in children components. Only in `pages`. 369 | > - If you are using some server only modules inside `getInitialProps`, make sure to [import them properly](https://arunoda.me/blog/ssr-and-server-only-modules), otherwise, it'll slow down your app. 370 | 371 | <br/> 372 | 373 | `getInitialProps` は context オブジェクトを受け取り、それは以下のプロパティを含みます: 374 | 375 | - `pathname` - path section of URL 376 | - `query` - query string section of URL parsed as an object 377 | - `asPath` - `String` of the actual path (including the query) shows in the browser 378 | - `req` - HTTP request object (server only) 379 | - `res` - HTTP response object (server only) 380 | - `err` - Error object if any error is encountered during the rendering 381 | 382 | ### Routing 383 | 384 | Next.js does not ship a routes manifest with every possible route in the application, so the current page is not aware of any other pages on the client side. All subsequent routes get lazy-loaded, for scalability sake. 385 | 386 | #### With `<Link>` 387 | 388 | <details> 389 | <summary><b>例</b></summary> 390 | <ul> 391 | <li><a href="/examples/hello-world">Hello World</a></li> 392 | </ul> 393 | </details> 394 | 395 | クライアントサイドでのルートの遷移は `<Link>` コンポーネントによって実現されます。 396 | 397 | > This component is not required for navigations to static pages that require a hard refresh, like when using [AMP](#amp-support). 398 | 399 | #### Basic Example 400 | 401 | 以下の2つのページがある場合を考えてみてください: 402 | 403 | ```jsx 404 | // pages/index.js 405 | import Link from 'next/link' 406 | 407 | function Home() { 408 | return ( 409 | <> 410 | <ul> 411 | <li>Home</li> 412 | <li> 413 | <Link href="/about"> 414 | <a>About Us</a> 415 | </Link> 416 | </li> 417 | </ul> 418 | 419 | <h1>This is our homepage.</h1> 420 | </> 421 | ) 422 | } 423 | 424 | export default Home 425 | ``` 426 | 427 | ```jsx 428 | // pages/about.js 429 | import Link from 'next/link' 430 | 431 | function About() { 432 | return ( 433 | <> 434 | <ul> 435 | <li> 436 | <Link href="/"> 437 | <a>Home</a> 438 | </Link> 439 | </li> 440 | <li>About Us</li> 441 | </ul> 442 | 443 | <h1>About</h1> 444 | <p>We are a cool company.</p> 445 | </> 446 | ) 447 | } 448 | 449 | export default About 450 | ``` 451 | 452 | Note: if passing a functional component as a child of `<Link>` you will need to wrap it in [`React.forwardRef`](https://reactjs.org/docs/react-api.html#reactforwardref) 453 | 454 | **Example with `React.forwardRef`** 455 | 456 | ```jsx 457 | import React from 'react' 458 | import Link from 'next/link' 459 | 460 | // `onClick`, `href`, and `ref` need to be passed to the DOM element 461 | // for proper handling 462 | const MyButton = React.forwardRef(({ onClick, href }, ref) => ( 463 | <a href={href} onClick={onClick} ref={ref}> 464 | Click Me 465 | </a> 466 | )) 467 | 468 | export default () => ( 469 | <> 470 | <Link href="/another"> 471 | <MyButton /> 472 | </Link> 473 | </> 474 | ) 475 | ``` 476 | 477 | #### Custom routes (using props from URL) 478 | 479 | If you find that your use case is not covered by [Dynamic Routing](#dynamic-routing) then you can create a custom server and manually add dynamic routes. 480 | 481 | Example: 482 | 483 | 1. Consider you have the URL `/post/:slug`. 484 | 485 | 2. You created `pages/post.js`: 486 | 487 | ```jsx 488 | import { useRouter } from 'next/router' 489 | 490 | const Post = () => { 491 | const router = useRouter() 492 | const { slug } = router.query 493 | 494 | return <p>My Blog Post: {slug}</p> 495 | } 496 | 497 | export default Post 498 | ``` 499 | 500 | 3. You add the route to `express` (or any other server) on `server.js` file (this is only for SSR). This will route the url `/post/:slug` to `pages/post.js` and provide `slug` as part of the `query` object to the page. 501 | 502 | ```jsx 503 | server.get('/post/:slug', (req, res) => { 504 | return app.render(req, res, '/post', { slug: req.params.slug }) 505 | }) 506 | ``` 507 | 508 | 4. For client side routing, use `next/link`: 509 | 510 | ```jsx 511 | <Link href="/post?slug=something" as="/post/something"> 512 | ``` 513 | 514 | - `href`: the path inside `pages` directory 515 | - `as`: the path used by your server routes 516 | 517 | クライアントサイドでのルーティングはブラウザとほぼ同じです: 518 | 519 | 1. The component is fetched. 520 | 2. もし `getInitialProps` が定義されていればデータを取得する。If an error occurs, `_error.js` is rendered. 521 | 3. After 1 and 2 complete, `pushState` is performed and the new component is rendered. 522 | 523 | To inject the `pathname`, `query` or `asPath` in your component, you can use the [useRouter](#userouter) hook, or [withRouter](#using-a-higher-order-component) for class components. 524 | 525 | #### With URL object 526 | 527 | <details> 528 | <summary><b>例</b></summary> 529 | <ul> 530 | <li><a href="/examples/with-url-object-routing">With URL Object Routing</a></li> 531 | </ul> 532 | </details> 533 | 534 | The component `<Link>` can also receive a URL object and it will automatically format it to create the URL string. 535 | 536 | ```jsx 537 | // pages/index.js 538 | import Link from 'next/link' 539 | 540 | function Home() { 541 | return ( 542 | <div> 543 | Click{' '} 544 | <Link href={{ pathname: '/about', query: { name: 'Zeit' } }}> 545 | <a>here</a> 546 | </Link>{' '} 547 | to read more 548 | </div> 549 | ) 550 | } 551 | 552 | export default Home 553 | ``` 554 | 555 | URL文字列`/about?name=Zeit`が作成され、[Node.jsモジュールドキュメント](https://nodejs.org/api/url.html#url_url_strings_and_url_objects)に定義されている全てのプロパティを利用することができます。 556 | 557 | #### Replace instead of push url 558 | 559 | The default behaviour for the `<Link>` component is to `push` a new url into the stack. You can use the `replace` prop to prevent adding a new entry. 560 | 561 | ```jsx 562 | // pages/index.js 563 | import Link from 'next/link' 564 | 565 | function Home() { 566 | return ( 567 | <div> 568 | Click{' '} 569 | <Link href="/about" replace> 570 | <a>here</a> 571 | </Link>{' '} 572 | to read more 573 | </div> 574 | ) 575 | } 576 | 577 | export default Home 578 | ``` 579 | 580 | #### Using a component that supports `onClick` 581 | 582 | `<Link>` supports any component that supports the `onClick` event. In case you don't provide an `<a>` tag, it will only add the `onClick` event handler and won't pass the `href` property. 583 | 584 | ```jsx 585 | // pages/index.js 586 | import Link from 'next/link' 587 | 588 | function Home() { 589 | return ( 590 | <div> 591 | Click{' '} 592 | <Link href="/about"> 593 | <img src="/static/image.png" alt="image" /> 594 | </Link> 595 | </div> 596 | ) 597 | } 598 | 599 | export default Home 600 | ``` 601 | 602 | #### Forcing the Link to expose `href` to its child 603 | 604 | If child is an `<a>` tag and doesn't have a href attribute we specify it so that the repetition is not needed by the user. However, sometimes, you’ll want to pass an `<a>` tag inside of a wrapper and the `Link` won’t recognize it as a _hyperlink_, and, consequently, won’t transfer its `href` to the child. In cases like that, you should define a boolean `passHref` property to the `Link`, forcing it to expose its `href` property to the child. 605 | 606 | **Please note**: using a tag other than `a` and failing to pass `passHref` may result in links that appear to navigate correctly, but, when being crawled by search engines, will not be recognized as links (owing to the lack of `href` attribute). This may result in negative effects on your sites SEO. 607 | 608 | ```jsx 609 | import Link from 'next/link' 610 | import Unexpected_A from 'third-library' 611 | 612 | function NavLink({ href, name }) { 613 | return ( 614 | <Link href={href} passHref> 615 | <Unexpected_A>{name}</Unexpected_A> 616 | </Link> 617 | ) 618 | } 619 | 620 | export default NavLink 621 | ``` 622 | 623 | #### Disabling the scroll changes to top on page 624 | 625 | The default behaviour of `<Link>` is to scroll to the top of the page. When there is a hash defined it will scroll to the specific id, just like a normal `<a>` tag. To prevent scrolling to the top / hash `scroll={false}` can be added to `<Link>`: 626 | 627 | ```jsx 628 | <Link scroll={false} href="/?counter=10"><a>Disables scrolling</a></Link> 629 | <Link href="/?counter=10"><a>Changes with scrolling to top</a></Link> 630 | ``` 631 | 632 | #### Imperatively 633 | 634 | <details> 635 | <summary><b>例</b></summary> 636 | <ul> 637 | <li><a href="/examples/using-router">Basic routing</a></li> 638 | <li><a href="/examples/with-loading">With a page loading indicator</a></li> 639 | </ul> 640 | </details> 641 | 642 | You can also do client-side page transitions using `next/router`: 643 | 644 | ```jsx 645 | import Router from 'next/router' 646 | 647 | function ReadMore() { 648 | return ( 649 | <div> 650 | Click <span onClick={() => Router.push('/about')}>here</span> to read more 651 | </div> 652 | ) 653 | } 654 | 655 | export default ReadMore 656 | ``` 657 | 658 | #### Intercepting `popstate` 659 | 660 | In some cases (for example, if using a [custom router](#custom-server-and-routing)), you may wish 661 | to listen to [`popstate`](https://developer.mozilla.org/en-US/docs/Web/Events/popstate) and react before the router acts on it. 662 | For example, you could use this to manipulate the request, or force an SSR refresh. 663 | 664 | ```jsx 665 | import Router from 'next/router' 666 | 667 | Router.beforePopState(({ url, as, options }) => { 668 | // I only want to allow these two routes! 669 | if (as !== '/' && as !== '/other') { 670 | // Have SSR render bad routes as a 404. 671 | window.location.href = as 672 | return false 673 | } 674 | 675 | return true 676 | }) 677 | ``` 678 | 679 | If the function you pass into `beforePopState` returns `false`, `Router` will not handle `popstate`; 680 | you'll be responsible for handling it, in that case. 681 | See [Disabling File-System Routing](#disabling-file-system-routing). 682 | 683 | Above `Router` object comes with the following API: 684 | 685 | - `route` - `String` of the current route 686 | - `pathname` - `String` of the current path excluding the query string 687 | - `query` - `Object` with the parsed query string. Defaults to `{}`. 688 | - `asPath` - `String` of the actual path (including the query) shows in the browser 689 | - `push(url, as=url)` - performs a `pushState` call with the given url 690 | - `replace(url, as=url)` - performs a `replaceState` call with the given url 691 | - `beforePopState(cb=function)` - intercept popstate before router processes the event 692 | 693 | The second `as` parameter for `push` and `replace` is an optional _decoration_ of the URL. Useful if you configured custom routes on the server. 694 | 695 | #### With URL object 696 | 697 | You can use a URL object the same way you use it in a `<Link>` component to `push` and `replace` a URL. 698 | 699 | ```jsx 700 | import Router from 'next/router' 701 | 702 | const handler = () => { 703 | Router.push({ 704 | pathname: '/about', 705 | query: { name: 'Zeit' }, 706 | }) 707 | } 708 | 709 | function ReadMore() { 710 | return ( 711 | <div> 712 | Click <span onClick={handler}>here</span> to read more 713 | </div> 714 | ) 715 | } 716 | 717 | export default ReadMore 718 | ``` 719 | 720 | This uses the same exact parameters as [in the `<Link>` component](#with-url-object). The first parameter maps to `href` while the second parameter maps to `as` in the `<Link>` component as documented [here](#with-url-object). 721 | 722 | #### Router Events 723 | 724 | You can also listen to different events happening inside the Router. 725 | Here's a list of supported events: 726 | 727 | - `routeChangeStart(url)` - Fires when a route starts to change 728 | - `routeChangeComplete(url)` - Fires when a route changed completely 729 | - `routeChangeError(err, url)` - Fires when there's an error when changing routes, or a route load is cancelled 730 | - `beforeHistoryChange(url)` - Fires just before changing the browser's history 731 | - `hashChangeStart(url)` - Fires when the hash will change but not the page 732 | - `hashChangeComplete(url)` - Fires when the hash has changed but not the page 733 | 734 | > Here `url` is the URL shown in the browser. If you call `Router.push(url, as)` (or similar), then the value of `url` will be `as`. 735 | 736 | Here's how to properly listen to the router event `routeChangeStart`: 737 | 738 | ```js 739 | const handleRouteChange = url => { 740 | console.log('App is changing to: ', url) 741 | } 742 | 743 | Router.events.on('routeChangeStart', handleRouteChange) 744 | ``` 745 | 746 | If you no longer want to listen to that event, you can unsubscribe with the `off` method: 747 | 748 | ```js 749 | Router.events.off('routeChangeStart', handleRouteChange) 750 | ``` 751 | 752 | If a route load is cancelled (for example by clicking two links rapidly in succession), `routeChangeError` will fire. The passed `err` will contain a `cancelled` property set to `true`. 753 | 754 | ```js 755 | Router.events.on('routeChangeError', (err, url) => { 756 | if (err.cancelled) { 757 | console.log(`Route to ${url} was cancelled!`) 758 | } 759 | }) 760 | ``` 761 | 762 | > **Note**: Using router events in `getInitialProps` is discouraged as it may result in unexpected behavior.<br/> 763 | > Router events should be registered when a component mounts (`useEffect` or `componentDidMount`/`componentWillUnmount`) or imperatively when an event happens. 764 | > 765 | > ```js 766 | > useEffect(() => { 767 | > const handleRouteChange = url => { 768 | > console.log('App is changing to: ', url) 769 | > } 770 | > 771 | > Router.events.on('routeChangeStart', handleRouteChange) 772 | > return () => { 773 | > Router.events.off('routeChangeStart', handleRouteChange) 774 | > } 775 | > }, []) 776 | > ``` 777 | 778 | #### Shallow Routing 779 | 780 | <details> 781 | <summary><b>例</b></summary> 782 | <ul> 783 | <li><a href="/examples/with-shallow-routing">Shallow Routing</a></li> 784 | </ul> 785 | </details> 786 | 787 | Shallow routing allows you to change the URL without running `getInitialProps`. You'll receive the updated `pathname` and the `query` via the `router` prop (injected by using [`useRouter`](#userouter) or [`withRouter`](#using-a-higher-order-component)), without losing state. 788 | 789 | You can do this by invoking either `Router.push` or `Router.replace` with the `shallow: true` option. Here's an example: 790 | 791 | ```js 792 | // Current URL is "/" 793 | const href = '/?counter=10' 794 | const as = href 795 | Router.push(href, as, { shallow: true }) 796 | ``` 797 | 798 | Now, the URL is updated to `/?counter=10`. You can see the updated URL with `this.props.router.query` inside the `Component` (make sure you are using [`withRouter`](#using-a-higher-order-component) around your `Component` to inject the `router` prop). 799 | 800 | You can watch for URL changes via [`componentDidUpdate`](https://reactjs.org/docs/react-component.html#componentdidupdate) hook as shown below: 801 | 802 | ```js 803 | componentDidUpdate(prevProps) { 804 | const { pathname, query } = this.props.router 805 | // verify props have changed to avoid an infinite loop 806 | if (query.id !== prevProps.router.query.id) { 807 | // fetch data based on the new query 808 | } 809 | } 810 | ``` 811 | 812 | > NOTES: 813 | > 814 | > Shallow routing works **only** for same page URL changes. For an example, let's assume we have another page called `about`, and you run this: 815 | > 816 | > ```js 817 | > Router.push('/?counter=10', '/about?counter=10', { shallow: true }) 818 | > ``` 819 | > 820 | > Since that's a new page, it'll unload the current page, load the new one and call `getInitialProps` even though we asked to do shallow routing. 821 | 822 | #### useRouter 823 | 824 | <details> 825 | <summary><b>例</b></summary> 826 | <ul> 827 | <li><a href="/examples/dynamic-routing">Dynamic routing</a></li> 828 | </ul> 829 | </details> 830 | 831 | If you want to access the `router` object inside any functional component in your app, you can use the `useRouter` hook, here's how to use it: 832 | 833 | ```jsx 834 | import { useRouter } from 'next/router' 835 | 836 | export default function ActiveLink({ children, href }) { 837 | const router = useRouter() 838 | const style = { 839 | marginRight: 10, 840 | color: router.pathname === href ?'red' : 'black', 841 | } 842 | 843 | const handleClick = e => { 844 | e.preventDefault() 845 | router.push(href) 846 | } 847 | 848 | return ( 849 | <a href={href} onClick={handleClick} style={style}> 850 | {children} 851 | </a> 852 | ) 853 | } 854 | ``` 855 | 856 | > **Note**: `useRouter` is a React hook, meaning it cannot be used with classes. 857 | > You can either use [`withRouter`](#using-a-higher-order-component) (a higher order component) or wrap your class in a functional component. 858 | 859 | The above `router` object comes with an API similar to [`next/router`](#imperatively). 860 | 861 | #### Using a Higher Order Component 862 | 863 | <details> 864 | <summary><b>例</b></summary> 865 | <ul> 866 | <li><a href="/examples/using-with-router">Using the `withRouter` utility</a></li> 867 | </ul> 868 | </details> 869 | 870 | If [useRouter](#userouter) is not the best fit for you, `withRouter` can also add the same `router` object to any component, here's how to use it: 871 | 872 | ```jsx 873 | import { withRouter } from 'next/router' 874 | 875 | function Page({ router }) { 876 | return <p>{router.pathname}</p> 877 | } 878 | 879 | export default withRouter(Page) 880 | ``` 881 | 882 | ### Prefetching Pages 883 | 884 | ⚠️ This is a production only feature ⚠️ 885 | 886 | <details> 887 | <summary><b>例</b></summary> 888 | <ul> 889 | <li><a href="/examples/with-prefetching">Prefetching</a></li> 890 | </ul> 891 | </details> 892 | 893 | Next.js has an API which allows you to prefetch pages. 894 | 895 | Since Next.js server-renders your pages, this allows all the future interaction paths of your app to be instant. Effectively Next.js gives you the great initial download performance of a _website_, with the ahead-of-time download capabilities of an _app_. [Read more](https://zeit.co/blog/next#anticipation-is-the-key-to-performance). 896 | 897 | > With prefetching Next.js only downloads JS code. When the page is getting rendered, you may need to wait for the data. 898 | 899 | > Automatic prefetching is disabled if your device is connected with 2G network or [Save-Data](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Save-Data) header is `on`. 900 | 901 | > `<link rel="preload">` is used for prefetching. Sometimes browsers will show a warning if the resource is not used within 3 seconds, these warnings can be ignored as per https://github.com/zeit/next.js/issues/6517#issuecomment-469063892. 902 | 903 | #### With `<Link>` 904 | 905 | `<Link>` will automatically prefetch pages in the background as they appear in the view. If certain pages are rarely visited you can manually set `prefetch` to `false`, here's how: 906 | 907 | ```jsx 908 | <Link href="/about" prefetch={false}> 909 | <a>About</a> 910 | </Link> 911 | ``` 912 | 913 | #### Imperatively 914 | 915 | Most prefetching needs are addressed by `<Link />`, but we also expose an imperative API for advanced usage: 916 | 917 | ```jsx 918 | import { useRouter } from 'next/router' 919 | 920 | export default function MyLink() { 921 | const router = useRouter() 922 | 923 | return ( 924 | <> 925 | <a onClick={() => setTimeout(() => router.push('/dynamic'), 100)}> 926 | A route transition will happen after 100ms 927 | </a> 928 | {// and we can prefetch it! 929 | router.prefetch('/dynamic')} 930 | </> 931 | ) 932 | } 933 | ``` 934 | 935 | `router` methods should be only used inside the client side of your app though. In order to prevent any error regarding this subject use the imperatively `prefetch` method in the `useEffect()` hook: 936 | 937 | ```jsx 938 | import { useRouter } from 'next/router' 939 | 940 | export default function MyLink() { 941 | const router = useRouter() 942 | 943 | useEffect(() => { 944 | router.prefetch('/dynamic') 945 | }) 946 | 947 | return ( 948 | <a onClick={() => setTimeout(() => router.push('/dynamic'), 100)}> 949 | A route transition will happen after 100ms 950 | </a> 951 | ) 952 | } 953 | ``` 954 | 955 | You can also add it to the `componentDidMount()` lifecycle method when using `React.Component`: 956 | 957 | ```jsx 958 | import React from 'react' 959 | import { withRouter } from 'next/router' 960 | 961 | class MyLink extends React.Component { 962 | componentDidMount() { 963 | const { router } = this.props 964 | router.prefetch('/dynamic') 965 | } 966 | 967 | render() { 968 | const { router } = this.props 969 | 970 | return ( 971 | <a onClick={() => setTimeout(() => router.push('/dynamic'), 100)}> 972 | A route transition will happen after 100ms 973 | </a> 974 | ) 975 | } 976 | } 977 | 978 | export default withRouter(MyLink) 979 | ``` 980 | 981 | ### API ルート 982 | 983 | <details> 984 | <summary><b>例</b></summary> 985 | <ul> 986 | <li><a href="/examples/api-routes">Basic API routes</a></li> 987 | <li><a href="/examples/api-routes-micro">API routes with micro</a></li> 988 | <li><a href="/examples/api-routes-middleware">API routes with middleware</a></li> 989 | <li><a href="/examples/api-routes-graphql">API routes with GraphQL server</a></li> 990 | <li><a href="/examples/api-routes-rest">API routes with REST</a></li> 991 | </ul> 992 | </details> 993 | 994 | API ルートによって、Next.js で **API** を構築することはとても簡単です。 995 | まず、`./pages` フォルダーに `api/` フォルダーを作成します。 996 | 997 | `./pages/api` に格納されているすべてのファイルは `/api/*` にマッピングされます。 998 | 例えば、`./pages/api/posts.js` は `/api/posts` というルートにマッピングされます。 999 | 1000 | 以下が API ルートのファイルの例です: 1001 | 1002 | ```js 1003 | export default (req, res) => { 1004 | res.setHeader('Content-Type', 'application/json') 1005 | res.statusCode = 200 1006 | res.end(JSON.stringify({ name: 'Nextjs' })) 1007 | } 1008 | ``` 1009 | 1010 | - `req` は [NextApiRequest](https://github.com/zeit/next.js/blob/v9.0.0/packages/next-server/lib/utils.ts#L143-L158) の値であり、[http.IncomingMessage](https://nodejs.org/api/http.html#http_class_http_incomingmessage) を拡張したものです 1011 | 1012 | - `res` は [NextApiResponse](https://github.com/zeit/next.js/blob/v9.0.0/packages/next-server/lib/utils.ts#L168-L178) の値であり、[http.ServerResponse](https://nodejs.org/api/http.html#http_class_http_serverresponse) を拡張したものです 1013 | 1014 | [API ルート](#api-routes)のために用意されているこれらの `NextApiRequest` と `NextApiResponse` という型は、それぞれ `Node.js` の request と response 型の拡張です。 1015 | 1016 | ```ts 1017 | import { NextApiRequest, NextApiResponse } from 'next' 1018 | 1019 | export default (req: NextApiRequest, res: NextApiResponse) => { 1020 | res.status(200).json({ title: 'Next.js' }) 1021 | } 1022 | ``` 1023 | 1024 | API 呼び出しで様々な HTTP メソッドを扱いたい場合は、リゾルバ関数内で `req.method` にアクセスすることができます: 1025 | 1026 | ```js 1027 | export default (req, res) => { 1028 | if (req.method === 'POST') { 1029 | // Process your POST request 1030 | } else { 1031 | // Handle the rest of your HTTP methods 1032 | } 1033 | } 1034 | ``` 1035 | 1036 | > **注意**: API ルートには [CORS ヘッダーが設定されていません](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)。したがって、デフォルトでは **同一オリジンのみ** で機能します。 1037 | > この挙動をカスタマイズしたい場合は、CORS ミドルウェアでラップして export することができます。 1038 | > [その例はこちらです](#api-middlewares)。 1039 | 1040 | API ルートによってクライアントサイドのバンドルのサイズが大きくなることはありません。それらはサーバーサイドのみのバンドルとなります。 1041 | 1042 | #### 動的なルーティングのサポート 1043 | 1044 | API ページは[動的なルーティング](#dynamic-routing)をサポートしているので、その機能のすべてを利用することが可能です。 1045 | 1046 | 例えば `./pages/api/post/[pid].js` というページがあった場合、リゾルバー関数では以下のようにしてパラメータを取得することができます。 1047 | 1048 | ```js 1049 | export default (req, res) => { 1050 | const { 1051 | query: { pid }, 1052 | } = req 1053 | 1054 | res.end(`Post: ${pid}`) 1055 | } 1056 | ``` 1057 | 1058 | #### API ミドルウェア 1059 | 1060 | API ルートには、送信されてきた `req` をパースするための組み込みミドルウェアが提供されています。 1061 | 以下がそれらのミドルウェアです: 1062 | 1063 | - `req.cookies` : request で送られてきた cookies を格納しているオブジェクトです。デフォルト値は `{}` です 1064 | - `req.query` [クエリストリング](https://en.wikipedia.org/wiki/Query_string)を格納しているオブジェクトです。デフォルト値は `{}` です 1065 | - `req.body` `content-type` にしたがってパースされた body を格納するオブジェクトで、body が含まれない場合には `null` となります 1066 | 1067 | リクエスト body のパースはデフォルトで有効になっていて、サイズの制限は `1mb` です。 1068 | もし `Stream` として利用する必要がある場合には、以下のようにして上記のデフォルトの挙動をオプトアウトすることが可能です: 1069 | 1070 | ```js 1071 | // ./pages/api/my-endpoint.js 1072 | export default (req, res) => { 1073 | // ... 1074 | } 1075 | 1076 | export const config = { 1077 | api: { 1078 | bodyParser: false, 1079 | }, 1080 | } 1081 | ``` 1082 | 1083 | パースされる body のサイズを変更したい場合は、`sizeLimit` キーを `bodyParser` に追加し、[bytes](https://github.com/visionmedia/bytes.js) ライブラリがサポートしている値を設定します: 1084 | 1085 | ```js 1086 | // ./pages/api/my-endpoint.js 1087 | export default (req, res) => { 1088 | // ... 1089 | } 1090 | 1091 | export const config = { 1092 | api: { 1093 | bodyParser: { 1094 | sizeLimit: '1mb', 1095 | }, 1096 | }, 1097 | } 1098 | ``` 1099 | 1100 | 更に嬉しい点として、[Micro])(https://github.com/zeit/micro) 互換の[ミドルウェア](https://github.com/amio/awesome-micro)を使うこともできます! 1101 | 1102 | 例えば、API エンドポイントで [CORS の構成](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)をしたいときは、`micro-cors` を利用することが可能です。 1103 | 1104 | まず、`micro-cors` をインストールします: 1105 | 1106 | ```bash 1107 | npm i micro-cors 1108 | # or 1109 | yarn add micro-cors 1110 | ``` 1111 | 1112 | そして、`micro-cors` を import し[設定してください](https://github.com/possibilities/micro-cors#readme)。最後に、export される関数をそのミドルウェアでラップすれば完成です。 1113 | 1114 | ```js 1115 | import Cors from 'micro-cors' 1116 | 1117 | const cors = Cors({ 1118 | allowedMethods: ['GET', 'HEAD'], 1119 | }) 1120 | 1121 | function Endpoint(req, res) { 1122 | res.json({ message: 'Hello Everyone!' }) 1123 | } 1124 | 1125 | export default cors(Endpoint) 1126 | ``` 1127 | 1128 | #### ヘルパー関数 1129 | 1130 | より良い developer experience を提供し、API エンドポイントをより高速に開発できるように、Express.js ライクなメソッドを用意しています: 1131 | 1132 | 1133 | ```js 1134 | export default (req, res) => { 1135 | res.status(200).json({ name: 'Next.js' }) 1136 | } 1137 | ``` 1138 | 1139 | - `res.status(code)` - ステータスコードを設定するための関数です。`code` は正しい [HTTP ステータスコード](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes) である必要があります 1140 | - `res.json(json)` - `JSON` レスポンスを送信します。`json` は正しい `JSON` オブジェクトである必要があります 1141 | - `res.send(body)` - HTTP レスポンスを送信します。`body` は `string` か `object`、または `Buffer` である必要があります 1142 | 1143 | ### カスタムサーバーとルーティング 1144 | 1145 | <details> 1146 | <summary><b>例</b></summary> 1147 | <ul> 1148 | <li><a href="/examples/custom-server">Basic custom server</a></li> 1149 | <li><a href="/examples/custom-server-express">Express integration</a></li> 1150 | <li><a href="/examples/custom-server-hapi">Hapi integration</a></li> 1151 | <li><a href="/examples/custom-server-koa">Koa integration</a></li> 1152 | <li><a href="/examples/parameterized-routing">Parameterized routing</a></li> 1153 | <li><a href="/examples/ssr-caching">SSR caching</a></li> 1154 | </ul> 1155 | </details> 1156 | 1157 | 一般的に`next server`でサーバーを立てます。しかし、ルーティングをカスタマイズするためやルーティングパターンを使うためなどにサーバーを100%プログラムで起動することができます。 1158 | 1159 | 例えば`server.js`と呼ばれるサーバーのためのファイルでカスタムなサーバーを使おうとする時は, `package.json`内のscriptsのkeyを下記のように上書きしていることを確認してください: 1160 | 1161 | ```json 1162 | { 1163 | "scripts": { 1164 | "dev": "node server.js", 1165 | "build": "next build", 1166 | "start": "NODE_ENV=production node server.js" 1167 | } 1168 | } 1169 | ``` 1170 | 1171 | この例では `/a` を `./pages/b`に対応させ, `/b` を `./pages/a`に対応させるようにしております: 1172 | 1173 | ```js 1174 | // This file doesn't go through babel or webpack transformation. 1175 | // Make sure the syntax and sources this file requires are compatible with the current node version you are running 1176 | // See https://github.com/zeit/next.js/issues/1245 for discussions on Universal Webpack or universal Babel 1177 | const { createServer } = require('http') 1178 | const { parse } = require('url') 1179 | const next = require('next') 1180 | 1181 | const dev = process.env.NODE_ENV !== 'production' 1182 | const app = next({ dev }) 1183 | const handle = app.getRequestHandler() 1184 | 1185 | app.prepare().then(() => { 1186 | createServer((req, res) => { 1187 | // Be sure to pass `true` as the second argument to `url.parse`. 1188 | // This tells it to parse the query portion of the URL. 1189 | const parsedUrl = parse(req.url, true) 1190 | const { pathname, query } = parsedUrl 1191 | 1192 | if (pathname === '/a') { 1193 | app.render(req, res, '/b', query) 1194 | } else if (pathname === '/b') { 1195 | app.render(req, res, '/a', query) 1196 | } else { 1197 | handle(req, res, parsedUrl) 1198 | } 1199 | }).listen(3000, err => { 1200 | if (err) throw err 1201 | console.log('> Ready on http://localhost:3000') 1202 | }) 1203 | }) 1204 | ``` 1205 | 1206 | The `next` API is as follows: 1207 | 1208 | - `next(opts: object)` 1209 | 1210 | Supported options: 1211 | 1212 | - `dev` (`bool`) whether to launch Next.js in dev mode - default `false` 1213 | - `dir` (`string`) where the Next project is located - default `'.'` 1214 | - `quiet` (`bool`) Hide error messages containing server information - default `false` 1215 | - `conf` (`object`) the same object you would use in `next.config.js` - default `{}` 1216 | 1217 | それから、`start`というscriptを `NODE_ENV=production node server.js`に変更してください。 1218 | 1219 | #### Disabling file-system routing 1220 | 1221 | By default, `Next` will serve each file in `/pages` under a pathname matching the filename (eg, `/pages/some-file.js` is served at `site.com/some-file`. 1222 | 1223 | もしあなたのプロジェクトがカスタムルーティングを使用しているのなら, この挙動によって異なるパスでも同じコンテンツが読み込まれるようになり、SEOやUX的な問題が起きます。 1224 | 1225 | この挙動を無効にして、 `/pages`のファイルに基づいたルーティングを防ぐのなら, `next.config.js`に下記のように記述してください: 1226 | 1227 | ```js 1228 | // next.config.js 1229 | module.exports = { 1230 | useFileSystemPublicRoutes: false, 1231 | } 1232 | ``` 1233 | 1234 | Note that `useFileSystemPublicRoutes` simply disables filename routes from SSR; client-side routing may still access those paths. If using this option, you should guard against navigation to routes you do not want programmatically. 1235 | 1236 | You may also wish to configure the client-side Router to disallow client-side redirects to filename routes; please refer to [Intercepting `popstate`](#intercepting-popstate). 1237 | 1238 | #### 動的なアセットプレフィックス 1239 | 1240 | しばしば、私たちは動的に`assetPrefix`を設定する必要があります。これは入ってくるリクエストに基づく`assetPrefix`を変更するときに役に立ちます。 1241 | そのために、私たちは `app.setAssetPrefix`を使うことができます。 1242 | 1243 | ここに使用例があります。 1244 | 1245 | ```js 1246 | const next = require('next') 1247 | const http = require('http') 1248 | 1249 | const dev = process.env.NODE_ENV !== 'production' 1250 | const app = next({ dev }) 1251 | const handleNextRequests = app.getRequestHandler() 1252 | 1253 | app.prepare().then(() => { 1254 | const server = new http.Server((req, res) => { 1255 | // Add assetPrefix support based on the hostname 1256 | if (req.headers.host === 'my-app.com') { 1257 | app.setAssetPrefix('http://cdn.com/myapp') 1258 | } else { 1259 | app.setAssetPrefix('') 1260 | } 1261 | 1262 | handleNextRequests(req, res) 1263 | }) 1264 | 1265 | server.listen(port, err => { 1266 | if (err) { 1267 | throw err 1268 | } 1269 | 1270 | console.log(`> Ready on http://localhost:${port}`) 1271 | }) 1272 | }) 1273 | ``` 1274 | 1275 | #### Changing x-powered-by 1276 | 1277 | By default Next.js will add `x-powered-by` to the request headers. There's an optional way to opt-out of this: 1278 | 1279 | ```js 1280 | // next.config.js 1281 | module.exports = { 1282 | poweredByHeader: false, 1283 | } 1284 | ``` 1285 | 1286 | ### Dynamic Import 1287 | 1288 | <details> 1289 | <summary><b>例</b></summary> 1290 | <ul> 1291 | <li><a href="/examples/with-dynamic-import">With Dynamic Import</a></li> 1292 | </ul> 1293 | </details> 1294 | 1295 | Next.js supports ES2020 [dynamic `import()`](https://github.com/tc39/proposal-dynamic-import) for JavaScript. 1296 | With that, you could import JavaScript modules (inc. React Components) dynamically and work with them. 1297 | 1298 | You can think dynamic imports as another way to split your code into manageable chunks. 1299 | Since Next.js supports dynamic imports with SSR, you could do amazing things with it. 1300 | 1301 | Here are a few ways to use dynamic imports. 1302 | 1303 | #### Basic Usage (Also does SSR) 1304 | 1305 | ```jsx 1306 | import dynamic from 'next/dynamic' 1307 | 1308 | const DynamicComponent = dynamic(() => import('../components/hello')) 1309 | 1310 | function Home() { 1311 | return ( 1312 | <div> 1313 | <Header /> 1314 | <DynamicComponent /> 1315 | <p>HOME PAGE is here!</p> 1316 | </div> 1317 | ) 1318 | } 1319 | 1320 | export default Home 1321 | ``` 1322 | 1323 | #### With named exports 1324 | 1325 | ```jsx 1326 | // components/hello.js 1327 | export function Hello() { 1328 | return <p>Hello!</p> 1329 | } 1330 | ``` 1331 | 1332 | ```jsx 1333 | import dynamic from 'next/dynamic' 1334 | 1335 | const DynamicComponent = dynamic(() => 1336 | import('../components/hello').then(mod => mod.Hello) 1337 | ) 1338 | 1339 | function Home() { 1340 | return ( 1341 | <div> 1342 | <Header /> 1343 | <DynamicComponent /> 1344 | <p>HOME PAGE is here!</p> 1345 | </div> 1346 | ) 1347 | } 1348 | 1349 | export default Home 1350 | ``` 1351 | 1352 | #### With Custom Loading Component 1353 | 1354 | ```jsx 1355 | import dynamic from 'next/dynamic' 1356 | 1357 | const DynamicComponentWithCustomLoading = dynamic( 1358 | () => import('../components/hello2'), 1359 | { loading: () => <p>...</p> } 1360 | ) 1361 | 1362 | function Home() { 1363 | return ( 1364 | <div> 1365 | <Header /> 1366 | <DynamicComponentWithCustomLoading /> 1367 | <p>HOME PAGE is here!</p> 1368 | </div> 1369 | ) 1370 | } 1371 | 1372 | export default Home 1373 | ``` 1374 | 1375 | #### With No SSR 1376 | 1377 | ```jsx 1378 | import dynamic from 'next/dynamic' 1379 | 1380 | const DynamicComponentWithNoSSR = dynamic( 1381 | () => import('../components/hello3'), 1382 | { ssr: false } 1383 | ) 1384 | 1385 | function Home() { 1386 | return ( 1387 | <div> 1388 | <Header /> 1389 | <DynamicComponentWithNoSSR /> 1390 | <p>HOME PAGE is here!</p> 1391 | </div> 1392 | ) 1393 | } 1394 | 1395 | export default Home 1396 | ``` 1397 | 1398 | ### `<App>`のカスタマイズ 1399 | 1400 | <details> 1401 | <summary><b>例</b></summary> 1402 | <ul> 1403 | <li><a href="/examples/with-app-layout">Using `_app.js` for layout</a></li> 1404 | <li><a href="/examples/with-componentdidcatch">Using `_app.js` to override `componentDidCatch`</a></li> 1405 | </ul> 1406 | </details> 1407 | 1408 | Next.jsはページを初期化するために`App`コンポーネントを使用します。`App`コンポーネントをオーバーライドし、ページの初期化をコントロールすることが可能です。それによってこのような素晴らしい事が可能になります: 1409 | 1410 | - ページ移動間の固定レイアウト 1411 | - ページ移動する際にステートを保持 1412 | - `componentDidCatch`を使用したカスタムエラーハンドリング 1413 | - ページに追加のデータを注入(例えばGraphQLクエリを使用することによって) 1414 | 1415 | オーバーライドするには`./pages/_app.js`ファイルを作成し、以下のようにAppクラスをオーバーライドします: 1416 | 1417 | ```js 1418 | import React from 'react' 1419 | import App from 'next/app' 1420 | 1421 | class MyApp extends App { 1422 | // Only uncomment this method if you have blocking data requirements for 1423 | // every single page in your application. This disables the ability to 1424 | // perform automatic static optimization, causing every page in your app to 1425 | // be server-side rendered. 1426 | // 1427 | // static async getInitialProps(appContext) { 1428 | // // calls page's `getInitialProps` and fills `appProps.pageProps` 1429 | // const appProps = await App.getInitialProps(appContext); 1430 | // 1431 | // return { ...appProps } 1432 | // } 1433 | 1434 | render() { 1435 | const { Component, pageProps } = this.props 1436 | return <Component {...pageProps} /> 1437 | } 1438 | } 1439 | 1440 | export default MyApp 1441 | ``` 1442 | 1443 | > **Note:** Adding a custom `getInitialProps` in App will affect [Automatic Static Optimization](#automatic-static-optimization) 1444 | 1445 | ### `<Document>`のカスタマイズ 1446 | 1447 | <details> 1448 | <summary><b>例</b></summary> 1449 | <ul> 1450 | <li><a href="/examples/with-styled-components">Styled components custom document</a></li> 1451 | </ul> 1452 | </details> 1453 | 1454 | A custom `<Document>` is commonly used to augment your application's `<html>` and `<body>` tags. 1455 | This is necessary because Next.js pages skip the definition of the surrounding document's markup. 1456 | 1457 | This allows you to support Server-Side Rendering for CSS-in-JS libraries like 1458 | [styled-components](https://github.com/zeit/next.js/tree/canary/examples/with-styled-components) or [emotion](https://github.com/zeit/next.js/tree/canary/examples/with-emotion). 1459 | Note, [styled-jsx](https://github.com/zeit/styled-jsx) is included in Next.js by default. 1460 | 1461 | A custom `<Document>` can also include `getInitialProps` for expressing asynchronous server-rendering data requirements. 1462 | 1463 | > **Note**: `<Document>`'s `getInitialProps` function is not called during client-side transitions, 1464 | > nor when a page is [automatically statically optimized](#automatic-static-optimization). 1465 | 1466 | > **Note**: Make sure to check if `ctx.req` / `ctx.res` are defined in `getInitialProps`. 1467 | > These variables will be `undefined` when a page is being statically exported for `next export` or [automatic static optimization](#automatic-static-optimization). 1468 | 1469 | To use a custom `<Document>`, you must create a file at `./pages/_document.js` and extend the `Document` class: 1470 | 1471 | ```jsx 1472 | // _documentはサーバーサイドのみでレンダリングされ、クライアントサイドでは使われません 1473 | // onClickのようなイベントハンドラはこのファイルには書けません 1474 | 1475 | // ./pages/_document.js 1476 | import Document, { Html, Head, Main, NextScript } from 'next/document' 1477 | 1478 | class MyDocument extends Document { 1479 | static async getInitialProps(ctx) { 1480 | const initialProps = await Document.getInitialProps(ctx) 1481 | return { ...initialProps } 1482 | } 1483 | 1484 | render() { 1485 | return ( 1486 | <Html> 1487 | <Head /> 1488 | <body> 1489 | <Main /> 1490 | <NextScript /> 1491 | </body> 1492 | </Html> 1493 | ) 1494 | } 1495 | } 1496 | 1497 | export default MyDocument 1498 | ``` 1499 | 1500 | All of `<Html>`, `<Head />`, `<Main />` and `<NextScript />` are required for page to be properly rendered. 1501 | 1502 | **Note: React-components outside of `<Main />` will not be initialised by the browser. アプリケーションロジックをここに追加_しないで_ください。If you need shared components in all your pages (like a menu or a toolbar), take a look at the [`<App>`](#custom-app) component instead.** 1503 | 1504 | `ctx`オブジェクトは、すべての[`getInitialProps`](#fetching-data-and-component-lifecycle)フックで受け取るオブジェクトと同等です。さらに加えて: 1505 | 1506 | - `renderPage` (`Function`)は実際のReactのレンダリングロジック(同期的)を実行するコールバックです。It's useful to decorate this function in order to support server-rendering wrappers like Aphrodite's [`renderStatic`](https://github.com/Khan/aphrodite#server-side-rendering). 1507 | 1508 | #### Customizing `renderPage` 1509 | 1510 | 🚧 It should be noted that the only reason you should be customizing `renderPage` is for usage with css-in-js libraries 1511 | that need to wrap the application to properly work with server-rendering. 🚧 1512 | 1513 | - It takes as argument an options object for further customization: 1514 | 1515 | ```js 1516 | import Document from 'next/document' 1517 | 1518 | class MyDocument extends Document { 1519 | static async getInitialProps(ctx) { 1520 | const originalRenderPage = ctx.renderPage 1521 | 1522 | ctx.renderPage = () => 1523 | originalRenderPage({ 1524 | // useful for wrapping the whole react tree 1525 | enhanceApp: App => App, 1526 | // useful for wrapping in a per-page basis 1527 | enhanceComponent: Component => Component, 1528 | }) 1529 | 1530 | // Run the parent `getInitialProps` using `ctx` that now includes our custom `renderPage` 1531 | const initialProps = await Document.getInitialProps(ctx) 1532 | 1533 | return initialProps 1534 | } 1535 | } 1536 | 1537 | export default MyDocument 1538 | ``` 1539 | 1540 | ### エラーハンドリングのカスタマイズ 1541 | 1542 | ステータスコードが404もしくは500のエラーは、`error.js`というデフォルトのコンポーネントによってクライアントとサーバーサイドの両方でハンドリングされます。もしデフォルトのエラーコンポーネントをオーバーライドしたいのなら、`_error.js`をpagesフォルダーの中に定義して下さい: 1543 | 1544 | ⚠️ The `pages/_error.js` component is only used in production. In development you get an error with call stack to know where the error originated from. ⚠️ 1545 | 1546 | ```jsx 1547 | import React from 'react' 1548 | 1549 | function Error({ statusCode }) { 1550 | return ( 1551 | <p> 1552 | {statusCode 1553 | ?`An error ${statusCode} occurred on server` 1554 | : 'An error occurred on client'} 1555 | </p> 1556 | ) 1557 | } 1558 | 1559 | Error.getInitialProps = ({ res, err }) => { 1560 | const statusCode = res ? res.statusCode : err ? err.statusCode : 404 1561 | return { statusCode } 1562 | } 1563 | 1564 | export default Error 1565 | ``` 1566 | 1567 | ### 組み込みのエラーページを再利用する 1568 | 1569 | 組み込みのエラーページをレンダリングしたいのならば、`next/error`を使用すれば可能です: 1570 | 1571 | ```jsx 1572 | import React from 'react' 1573 | import Error from 'next/error' 1574 | import fetch from 'isomorphic-unfetch' 1575 | 1576 | const Page = ({ errorCode, stars }) => { 1577 | if (errorCode) { 1578 | return <Error statusCode={errorCode} /> 1579 | } 1580 | 1581 | return <div>Next stars: {stars}</div> 1582 | } 1583 | 1584 | Page.getInitialProps = async () => { 1585 | const res = await fetch('https://api.github.com/repos/zeit/next.js') 1586 | const errorCode = res.statusCode > 200 ?res.statusCode : false 1587 | const json = await res.json() 1588 | 1589 | return { errorCode, stars: json.stargazers_count } 1590 | } 1591 | 1592 | export default Page 1593 | ``` 1594 | 1595 | > If you have created a custom error page you have to import your own `_error` component from `./_error` instead of `next/error`. 1596 | 1597 | The Error component also takes `title` as a property if you want to pass in a text message along with a `statusCode`. 1598 | 1599 | ### Custom configuration 1600 | 1601 | For custom advanced behavior of Next.js, you can create a `next.config.js` in the root of your project directory (next to `pages/` and `package.json`). 1602 | 1603 | Note: `next.config.js` is a regular Node.js module, not a JSON file. It gets used by the Next server and build phases, and not included in the browser build. 1604 | 1605 | ```js 1606 | // next.config.js 1607 | module.exports = { 1608 | /* config options here */ 1609 | } 1610 | ``` 1611 | 1612 | Or use a function: 1613 | 1614 | ```js 1615 | module.exports = (phase, { defaultConfig }) => { 1616 | return { 1617 | /* config options here */ 1618 | } 1619 | } 1620 | ``` 1621 | 1622 | `phase` is the current context in which the configuration is loaded. You can see all phases here: [constants](https://github.com/zeit/next.js/tree/canary/packages/next/next-server/lib/constants.ts) 1623 | Phases can be imported from `next/constants`: 1624 | 1625 | ```js 1626 | const { PHASE_DEVELOPMENT_SERVER } = require('next/constants') 1627 | module.exports = (phase, { defaultConfig }) => { 1628 | if (phase === PHASE_DEVELOPMENT_SERVER) { 1629 | return { 1630 | /* development only config options here */ 1631 | } 1632 | } 1633 | 1634 | return { 1635 | /* config options for all phases except development here */ 1636 | } 1637 | } 1638 | ``` 1639 | 1640 | #### Setting a custom build directory 1641 | 1642 | You can specify a name to use for a custom build directory. For example, the following config will create a `build` folder instead of a `.next` folder. If no configuration is specified then next will create a `.next` folder. 1643 | 1644 | ```js 1645 | // next.config.js 1646 | module.exports = { 1647 | distDir: 'build', 1648 | } 1649 | ``` 1650 | 1651 | #### Disabling etag generation 1652 | 1653 | You can disable etag generation for HTML pages depending on your cache strategy. If no configuration is specified then Next will generate etags for every page. 1654 | 1655 | ```js 1656 | // next.config.js 1657 | module.exports = { 1658 | generateEtags: false, 1659 | } 1660 | ``` 1661 | 1662 | #### Configuring the onDemandEntries 1663 | 1664 | Next exposes some options that give you some control over how the server will dispose or keep in memories pages built: 1665 | 1666 | ```js 1667 | module.exports = { 1668 | onDemandEntries: { 1669 | // period (in ms) where the server will keep pages in the buffer 1670 | maxInactiveAge: 25 * 1000, 1671 | // number of pages that should be kept simultaneously without being disposed 1672 | pagesBufferLength: 2, 1673 | }, 1674 | } 1675 | ``` 1676 | 1677 | This is development-only feature. If you want to cache SSR pages in production, please see [SSR-caching](https://github.com/zeit/next.js/tree/canary/examples/ssr-caching) example. 1678 | 1679 | #### Configuring extensions looked for when resolving pages in `pages` 1680 | 1681 | Aimed at modules like [`@next/mdx`](https://github.com/zeit/next.js/tree/canary/packages/next-mdx), that add support for pages ending with `.mdx`. `pageExtensions` allows you to configure the extensions looked for in the `pages` directory when resolving pages. 1682 | 1683 | ```js 1684 | // next.config.js 1685 | module.exports = { 1686 | pageExtensions: ['mdx', 'jsx', 'js'], 1687 | } 1688 | ``` 1689 | 1690 | #### Configuring the build ID 1691 | 1692 | Next.js uses a constant generated at build time to identify which version of your application is being served. This can cause problems in multi-server deployments when `next build` is ran on every server. In order to keep a static build id between builds you can provide the `generateBuildId` function: 1693 | 1694 | ```js 1695 | // next.config.js 1696 | module.exports = { 1697 | generateBuildId: async () => { 1698 | // For example get the latest git commit hash here 1699 | return 'my-build-id' 1700 | }, 1701 | } 1702 | ``` 1703 | 1704 | To fall back to the default of generating a unique id return `null` from the function: 1705 | 1706 | ```js 1707 | module.exports = { 1708 | generateBuildId: async () => { 1709 | // When process.env.YOUR_BUILD_ID is undefined we fall back to the default 1710 | if (process.env.YOUR_BUILD_ID) { 1711 | return process.env.YOUR_BUILD_ID 1712 | } 1713 | 1714 | return null 1715 | }, 1716 | } 1717 | ``` 1718 | 1719 | #### Configuring next process script 1720 | 1721 | You can pass any node arguments to `next` CLI command. 1722 | 1723 | ```bash 1724 | NODE_OPTIONS="--throw-deprecation" next 1725 | NODE_OPTIONS="-r esm" next 1726 | NODE_OPTIONS="--inspect" next 1727 | ``` 1728 | 1729 | ### Customizing webpack config 1730 | 1731 | <details> 1732 | <summary><b>例</b></summary> 1733 | <ul> 1734 | <li><a href="/examples/with-webpack-bundle-analyzer">Custom webpack bundle analyzer</a></li> 1735 | </ul> 1736 | </details> 1737 | 1738 | Some commonly asked for features are available as modules: 1739 | 1740 | - [@zeit/next-css](https://github.com/zeit/next-plugins/tree/master/packages/next-css) 1741 | - [@zeit/next-sass](https://github.com/zeit/next-plugins/tree/master/packages/next-sass) 1742 | - [@zeit/next-less](https://github.com/zeit/next-plugins/tree/master/packages/next-less) 1743 | - [@zeit/next-preact](https://github.com/zeit/next-plugins/tree/master/packages/next-preact) 1744 | - [@next/mdx](https://github.com/zeit/next.js/tree/canary/packages/next-mdx) 1745 | 1746 | > **Warning:** The `webpack` function is executed twice, once for the server and once for the client. This allows you to distinguish between client and server configuration using the `isServer` property. 1747 | 1748 | Multiple configurations can be combined together with function composition. For example: 1749 | 1750 | ```js 1751 | const withMDX = require('@next/mdx') 1752 | const withSass = require('@zeit/next-sass') 1753 | 1754 | module.exports = withMDX( 1755 | withSass({ 1756 | webpack(config, options) { 1757 | // Further custom configuration here 1758 | return config 1759 | }, 1760 | }) 1761 | ) 1762 | ``` 1763 | 1764 | In order to extend our usage of `webpack`, you can define a function that extends its config via `next.config.js`. 1765 | 1766 | ```js 1767 | // next.config.js is not transformed by Babel. So you can only use javascript features supported by your version of Node.js. 1768 | 1769 | module.exports = { 1770 | webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => { 1771 | // Note: we provide webpack above so you should not `require` it 1772 | // Perform customizations to webpack config 1773 | // Important: return the modified config 1774 | 1775 | // Example using webpack option 1776 | config.plugins.push(new webpack.IgnorePlugin(/\/__tests__\//)) 1777 | return config 1778 | }, 1779 | webpackDevMiddleware: config => { 1780 | // Perform customizations to webpack dev middleware config 1781 | // Important: return the modified config 1782 | return config 1783 | }, 1784 | } 1785 | ``` 1786 | 1787 | The second argument to `webpack` is an object containing properties useful when customizing its configuration: 1788 | 1789 | - `buildId` - `String` the build id used as a unique identifier between builds 1790 | - `dev` - `Boolean` shows if the compilation is done in development mode 1791 | - `isServer` - `Boolean` shows if the resulting configuration will be used for server side (`true`), or client side compilation (`false`) 1792 | - `defaultLoaders` - `Object` Holds loader objects Next.js uses internally, so that you can use them in custom configuration 1793 | - `babel` - `Object` the `babel-loader` configuration for Next.js 1794 | 1795 | Example usage of `defaultLoaders.babel`: 1796 | 1797 | ```js 1798 | // Example next.config.js for adding a loader that depends on babel-loader 1799 | // This source was taken from the @next/mdx plugin source: 1800 | // https://github.com/zeit/next.js/tree/canary/packages/next-mdx 1801 | module.exports = { 1802 | webpack: (config, options) => { 1803 | config.module.rules.push({ 1804 | test: /\.mdx/, 1805 | use: [ 1806 | options.defaultLoaders.babel, 1807 | { 1808 | loader: '@mdx-js/loader', 1809 | options: pluginOptions.options, 1810 | }, 1811 | ], 1812 | }) 1813 | 1814 | return config 1815 | }, 1816 | } 1817 | ``` 1818 | 1819 | ### Customizing babel config 1820 | 1821 | <details> 1822 | <summary><b>例</b></summary> 1823 | <ul> 1824 | <li><a href="/examples/with-custom-babel-config">Custom babel configuration</a></li> 1825 | </ul> 1826 | </details> 1827 | 1828 | In order to extend our usage of `babel`, you can simply define a `.babelrc` file at the root of your app. This file is optional. 1829 | 1830 | If found, we're going to consider it the _source of truth_, therefore it needs to define what next needs as well, which is the `next/babel` preset. 1831 | 1832 | This is designed so that you are not surprised by modifications we could make to the babel configurations. 1833 | 1834 | Here's an example `.babelrc` file: 1835 | 1836 | ```json 1837 | { 1838 | "presets": ["next/babel"], 1839 | "plugins": [] 1840 | } 1841 | ``` 1842 | 1843 | The `next/babel` preset includes everything needed to transpile React applications. This includes: 1844 | 1845 | - preset-env 1846 | - preset-react 1847 | - preset-typescript 1848 | - plugin-proposal-class-properties 1849 | - plugin-proposal-object-rest-spread 1850 | - plugin-transform-runtime 1851 | - styled-jsx 1852 | 1853 | These presets / plugins **should not** be added to your custom `.babelrc`. Instead, you can configure them on the `next/babel` preset: 1854 | 1855 | ```json 1856 | { 1857 | "presets": [ 1858 | [ 1859 | "next/babel", 1860 | { 1861 | "preset-env": {}, 1862 | "transform-runtime": {}, 1863 | "styled-jsx": {}, 1864 | "class-properties": {} 1865 | } 1866 | ] 1867 | ], 1868 | "plugins": [] 1869 | } 1870 | ``` 1871 | 1872 | The `modules` option on `"preset-env"` should be kept to `false` otherwise webpack code splitting is disabled. 1873 | 1874 | ### Exposing configuration to the server / client side 1875 | 1876 | There is a common need in applications to provide configuration values. 1877 | 1878 | Next.js supports 2 ways of providing configuration: 1879 | 1880 | - Build-time configuration 1881 | - Runtime configuration 1882 | 1883 | #### Build-time configuration 1884 | 1885 | The way build-time configuration works is by inlining the provided values into the Javascript bundle. 1886 | 1887 | You can add the `env` key in `next.config.js`: 1888 | 1889 | ```js 1890 | // next.config.js 1891 | module.exports = { 1892 | env: { 1893 | customKey: 'value', 1894 | }, 1895 | } 1896 | ``` 1897 | 1898 | This will allow you to use `process.env.customKey` in your code. For example: 1899 | 1900 | ```jsx 1901 | // pages/index.js 1902 | function Index() { 1903 | return <h1>The value of customKey is: {process.env.customKey}</h1> 1904 | } 1905 | 1906 | export default Index 1907 | ``` 1908 | 1909 | > **Warning:** Note that it is not possible to destructure process.env variables due to the webpack `DefinePlugin` replacing process.env.XXXX inline at build time. 1910 | 1911 | ```js 1912 | // Will not work 1913 | const { CUSTOM_KEY, CUSTOM_SECRET } = process.env 1914 | AuthMethod({ key: CUSTOM_KEY, secret: CUSTOM_SECRET }) 1915 | 1916 | // Will work as replaced inline 1917 | AuthMethod({ key: process.env.CUSTOM_KEY, secret: process.env.CUSTOM_SECRET }) 1918 | ``` 1919 | 1920 | #### Runtime configuration 1921 | 1922 | > **Warning:** Note that this option is not available when using `target: 'serverless'` 1923 | 1924 | > **Warning:** Generally you want to use build-time configuration to provide your configuration. 1925 | > The reason for this is that runtime configuration adds rendering / initialization overhead and is **incompatible with [automatic static optimization](#automatic-static-optimization)**. 1926 | 1927 | The `next/config` module gives your app access to the `publicRuntimeConfig` and `serverRuntimeConfig` stored in your `next.config.js`. 1928 | 1929 | Place any server-only runtime config under a `serverRuntimeConfig` property. 1930 | 1931 | Anything accessible to both client and server-side code should be under `publicRuntimeConfig`. 1932 | 1933 | > **Note**: A page that relies on `publicRuntimeConfig` **must** use `getInitialProps` to opt-out of [automatic static optimization](#automatic-static-optimization). 1934 | > You can also de-optimize your entire application by creating a [Custom `<App>`](#custom-app) with `getInitialProps`. 1935 | 1936 | ```js 1937 | // next.config.js 1938 | module.exports = { 1939 | serverRuntimeConfig: { 1940 | // Will only be available on the server side 1941 | mySecret: 'secret', 1942 | secondSecret: process.env.SECOND_SECRET, // Pass through env variables 1943 | }, 1944 | publicRuntimeConfig: { 1945 | // Will be available on both server and client 1946 | staticFolder: '/static', 1947 | }, 1948 | } 1949 | ``` 1950 | 1951 | ```js 1952 | // pages/index.js 1953 | import getConfig from 'next/config' 1954 | // Only holds serverRuntimeConfig and publicRuntimeConfig from next.config.js nothing else. 1955 | const { serverRuntimeConfig, publicRuntimeConfig } = getConfig() 1956 | 1957 | console.log(serverRuntimeConfig.mySecret) // Will only be available on the server side 1958 | console.log(publicRuntimeConfig.staticFolder) // Will be available on both server and client 1959 | 1960 | function MyImage() { 1961 | return ( 1962 | <div> 1963 | <img src={`${publicRuntimeConfig.staticFolder}/logo.png`} alt="logo" /> 1964 | </div> 1965 | ) 1966 | } 1967 | 1968 | export default MyImage 1969 | ``` 1970 | 1971 | ### Starting the server on alternative hostname 1972 | 1973 | To start the development server using a different default hostname you can use `--hostname hostname_here` or `-H hostname_here` option with next dev. This will start a TCP server listening for connections on the provided host. 1974 | 1975 | ### CDN support with Asset Prefix 1976 | 1977 | To set up a CDN, you can set up the `assetPrefix` setting and configure your CDN's origin to resolve to the domain that Next.js is hosted on. 1978 | 1979 | ```js 1980 | const isProd = process.env.NODE_ENV === 'production' 1981 | module.exports = { 1982 | // You may only need to add assetPrefix in the production. 1983 | assetPrefix: isProd ?'https://cdn.mydomain.com' : '', 1984 | } 1985 | ``` 1986 | 1987 | Note: Next.js will automatically use that prefix in the scripts it loads, but this has no effect whatsoever on `/static`. If you want to serve those assets over the CDN, you'll have to introduce the prefix yourself. One way of introducing a prefix that works inside your components and varies by environment is documented [in this example](https://github.com/zeit/next.js/tree/master/examples/with-universal-configuration-build-time). 1988 | 1989 | If your CDN is on a separate domain and you would like assets to be requested using a [CORS aware request](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes) you can set a config option for that. 1990 | 1991 | ```js 1992 | // next.config.js 1993 | module.exports = { 1994 | crossOrigin: 'anonymous', 1995 | } 1996 | ``` 1997 | 1998 | ## Automatic Static Optimization 1999 | 2000 | Next.js automatically determines that a page is static (can be prerendered) if it has no blocking data requirements. 2001 | This determination is made by the absence of `getInitialProps` in the page. 2002 | 2003 | If `getInitialProps` is present, Next.js will not statically optimize the page. 2004 | Instead, Next.js will use its default behavior and render the page on-demand, per-request (meaning Server-Side Rendering). 2005 | 2006 | If `getInitialProps` is absent, Next.js will **statically optimize** your page automatically by prerendering it to static HTML. During prerendering, the router's `query` object will be empty since we do not have `query` information to provide during this phase. Any `query` values will be populated client side after hydration. 2007 | 2008 | This feature allows Next.js to emit hybrid applications that contain **both server-rendered and statically generated pages**. 2009 | This ensures Next.js always emits applications that are **fast by default**. 2010 | 2011 | > **Note**: Statically generated pages are still reactive: Next.js will hydrate your application client-side to give it full interactivity. 2012 | 2013 | This feature provides many benefits. 2014 | For example, optimized pages require no server-side computation and can be instantly streamed to the end-user from CDN locations. 2015 | 2016 | The result is an _ultra fast_ loading experience for your users. 2017 | 2018 | `next build` will emit `.html` files for statically optimized pages. 2019 | The result will be a file named `.next/server/static/${BUILD_ID}/about.html` instead of `.next/server/static/${BUILD_ID}/about.js`. 2020 | This behavior is similar for `target: 'serverless'`. 2021 | 2022 | The built-in Next.js server (`next start`) and programmatic API (`app.getRequestHandler()`) both support this build output transparently. 2023 | There is no configuration or special handling required. 2024 | 2025 | > **Note**: If you have a [custom `<App>`](#custom-app) with `getInitialProps` then this optimization will be disabled. 2026 | 2027 | > **Note**: If you have a [custom `<Document>`](#custom-document) with `getInitialProps` be sure you check if `ctx.req` is defined before assuming the page is server-side rendered. 2028 | > `ctx.req` will be `undefined` for pages that are prerendered. 2029 | 2030 | ## Automatic Static Optimization Indicator 2031 | 2032 | When a page qualifies for automatic static optimization we show an indicator to let you know. 2033 | This is helpful since the automatic static optimization can be very beneficial and knowing immediately in development if it qualifies can be useful. 2034 | See above for information on the benefits of this optimization. 2035 | 2036 | In some cases this indicator might not be as useful like when working on electron applications. For these cases you can disable the indicator in your `next.config.js` by setting 2037 | 2038 | ```js 2039 | module.exports = { 2040 | devIndicators: { 2041 | autoPrerender: false, 2042 | }, 2043 | } 2044 | ``` 2045 | 2046 | ## Production deployment 2047 | 2048 | To deploy, instead of running `next`, you want to build for production usage ahead of time. Therefore, building and starting are separate commands: 2049 | 2050 | ```bash 2051 | next build 2052 | next start 2053 | ``` 2054 | 2055 | To deploy Next.js with [ZEIT Now](https://zeit.co/now) see the [ZEIT Guide for Deploying Next.js](https://zeit.co/guides/deploying-nextjs-with-now/) or the [Next.js Learn section about deploying on ZEIT Now](https://nextjs.org/learn/basics/deploying-a-nextjs-app/deploying-to-zeit-now). 2056 | 2057 | Next.js can be deployed to other hosting solutions too. Please have a look at the ['Deployment'](https://github.com/zeit/next.js/wiki/Deployment) section of the wiki. 2058 | 2059 | Note: `NODE_ENV` is properly configured by the `next` subcommands, if absent, to maximize performance. if you’re using Next.js [programmatically](#custom-server-and-routing), it’s your responsibility to set `NODE_ENV=production` manually! 2060 | 2061 | Note: we recommend putting `.next`, or your [custom dist folder](https://github.com/zeit/next.js#custom-configuration), in `.gitignore` or `.npmignore`. Otherwise, use `files` or `now.files` to opt-into a whitelist of files you want to deploy, excluding `.next` or your custom dist folder. 2062 | 2063 | ### Compression 2064 | 2065 | Next.js provides [gzip](https://tools.ietf.org/html/rfc6713#section-3) compression to compress rendered content and static files. Compression only works with the `server` target. In general you will want to enable compression on a HTTP proxy like [nginx](https://www.nginx.com/), to offload load from the `Node.js` process. 2066 | 2067 | To disable **compression** in Next.js, set `compress` to `false` in `next.config.js`: 2068 | 2069 | ```js 2070 | // next.config.js 2071 | module.exports = { 2072 | compress: false, 2073 | } 2074 | ``` 2075 | 2076 | ### Serverless deployment 2077 | 2078 | <details> 2079 | <summary><b>例</b></summary> 2080 | <ul> 2081 | <li><a href="https://github.com/zeit/now-examples/tree/master/nextjs">now.sh</a></li> 2082 | <li><a href="https://github.com/TejasQ/anna-artemov.now.sh">anna-artemov.now.sh</a></li> 2083 | <li>We encourage contributing more examples to this section</li> 2084 | </ul> 2085 | </details> 2086 | 2087 | Serverless deployment dramatically improves reliability and scalability by splitting your application into smaller parts (also called [**lambdas**](https://zeit.co/docs/v2/deployments/concepts/lambdas/)). 2088 | In the case of Next.js, each page in the `pages` directory becomes a serverless lambda. 2089 | 2090 | There are [a number of benefits](https://zeit.co/blog/serverless-express-js-lambdas-with-now-2#benefits-of-serverless-express) to serverless. 2091 | The referenced link talks about some of them in the context of Express, but the principles apply universally: 2092 | serverless allows for distributed points of failure, infinite scalability, and is incredibly affordable with a "pay for what you use" model. 2093 | 2094 | To enable **serverless mode** in Next.js, add the `serverless` build `target` in `next.config.js`: 2095 | 2096 | ```js 2097 | // next.config.js 2098 | module.exports = { 2099 | target: 'serverless', 2100 | } 2101 | ``` 2102 | 2103 | The `serverless` target will output a single lambda or [HTML file](#automatic-static-optimization) per page. 2104 | This file is completely standalone and doesn't require any dependencies to run: 2105 | 2106 | - `pages/index.js` => `.next/serverless/pages/index.js` 2107 | - `pages/about.js` => `.next/serverless/pages/about.js` 2108 | - `pages/blog.js` => `.next/serverless/pages/blog.html` 2109 | 2110 | The signature of the Next.js Serverless function is similar to the Node.js HTTP server callback: 2111 | 2112 | ```ts 2113 | export function render(req: http.IncomingMessage, res: http.ServerResponse) => void 2114 | ``` 2115 | 2116 | - [http.IncomingMessage](https://nodejs.org/api/http.html#http_class_http_incomingmessage) 2117 | - [http.ServerResponse](https://nodejs.org/api/http.html#http_class_http_serverresponse) 2118 | - `void` refers to the function not having a return value and is equivalent to JavaScript's `undefined`. Calling the function will finish the request. 2119 | 2120 | The static HTML files are ready to be served as-is. 2121 | You can read more about this feature, including how to opt-out, in the [Automatic Static Optimization section](#automatic-static-optimization). 2122 | 2123 | Using the serverless target, you can deploy Next.js to [ZEIT Now](https://zeit.co/now) with all of the benefits and added ease of control like for example; [custom routes](https://zeit.co/guides/custom-next-js-server-to-routes/) and caching headers. See the [ZEIT Guide for Deploying Next.js with Now](https://zeit.co/guides/deploying-nextjs-with-now/) for more information. 2124 | 2125 | #### One Level Lower 2126 | 2127 | Next.js provides low-level APIs for serverless deployments as hosting platforms have different function signatures. In general you will want to wrap the output of a Next.js serverless build with a compatibility layer. 2128 | 2129 | For example if the platform supports the Node.js [`http.Server`](https://nodejs.org/api/http.html#http_class_http_server) class: 2130 | 2131 | ```js 2132 | const http = require('http') 2133 | const page = require('./.next/serverless/pages/about.js') 2134 | const server = new http.Server((req, res) => page.render(req, res)) 2135 | server.listen(3000, () => console.log('Listening on http://localhost:3000')) 2136 | ``` 2137 | 2138 | For specific platform examples see [the examples section above](#serverless-deployment). 2139 | 2140 | #### Summary 2141 | 2142 | - Low-level API for implementing serverless deployment 2143 | - Every page in the `pages` directory becomes a serverless function (lambda) 2144 | - Creates the smallest possible serverless function (50Kb base zip size) 2145 | - Optimized for fast [cold start](https://zeit.co/blog/serverless-ssr#cold-start) of the function 2146 | - The serverless function has 0 dependencies (they are included in the function bundle) 2147 | - Uses the [http.IncomingMessage](https://nodejs.org/api/http.html#http_class_http_incomingmessage) and [http.ServerResponse](https://nodejs.org/api/http.html#http_class_http_serverresponse) from Node.js 2148 | - opt-in using `target: 'serverless'` in `next.config.js` 2149 | - Does not load `next.config.js` when executing the function, note that this means `publicRuntimeConfig` / `serverRuntimeConfig` are not supported 2150 | 2151 | ## Browser support 2152 | 2153 | Next.js supports IE11 and all modern browsers out of the box using [`@babel/preset-env`](https://new.babeljs.io/docs/en/next/babel-preset-env.html). In order to support IE11 Next.js adds a global `Promise` polyfill. In cases where your own code or any external NPM dependencies you are using requires features not supported by your target browsers you will need to implement polyfills. 2154 | 2155 | The [polyfills](https://github.com/zeit/next.js/tree/canary/examples/with-polyfills) example demonstrates the recommended approach to implement polyfills. 2156 | 2157 | ## TypeScript 2158 | 2159 | IDEのようにNext.jsではTypeScriptを簡単に扱えます。 2160 | 2161 | はじめに、空の`tsconfig.json`ファイルをプロジェクトのroot上に作成します。 2162 | 2163 | ```bash 2164 | touch tsconfig.json 2165 | ``` 2166 | 2167 | 先程作成したファイルは、Next.jsによって自動でデフォルト値をもとに構成されます。([独自の `tsconfig.json` を用いることでのカスタマイズ](https://www.typescriptlang.org/docs/handbook/compiler-options.html)も可能です) 2168 | 2169 | それから、`next dev`(または、`npm run dev`)を実行すると環境構築に必要なパッケージをインストールするようメッセージがでますので、インストールしてセットアップを完了してください。 2170 | 2171 | ```bash 2172 | npm run dev 2173 | 2174 | # You'll see instructions like these: 2175 | # 2176 | # Please install typescript, @types/react, and @types/node by running: 2177 | # 2178 | # yarn add --dev typescript @types/react @types/node 2179 | # 2180 | # ... 2181 | ``` 2182 | 2183 | これで、`.js`から`.tsx`変換をすることで、TypeScriptが提供する利点を活用できる準備ができました。 2184 | 2185 | TypeScriptに関して詳しく知りたい方は、[ドキュメント](https://www.typescriptlang.org/)を確認してください。 2186 | 2187 | > **注意点** : Next.jsがnext-env.d.tsというファイルをプロジェクトのroot上に作成します。 2188 | > これはTypeScriptのコンパイラーが型を確実に選択するようにするためです。 2189 | > このファイルを削除することはできませんが、編集することはできます (ただし、削除する必要はありません) 2190 | 2191 | > **注意点** : Next.jsは、デフォルトではTypeScriptのstrictモードは有効ではありません。 2192 | > したがって、TypeScriptに慣れたら別途 `tsconfig.json` にて設定するとよいでしょう。 2193 | 2194 | ### 型のエクスポート 2195 | 2196 | Next.js では、`NextPage` という型が提供されており、pages ディレクトリの中にあるページで使用することができます。`NextPage` は [`getInitialProps`](#fetching-data-and-component-lifecycle) に対して型情報を提供するため、自分で型定義をすることなく簡単に利用できます。 2197 | 2198 | ```tsx 2199 | import { NextPage } from 'next' 2200 | 2201 | interface Props { 2202 | userAgent?: string 2203 | } 2204 | 2205 | const Page: NextPage<Props> = ({ userAgent }) => ( 2206 | <main>Your user agent: {userAgent}</main> 2207 | ) 2208 | 2209 | Page.getInitialProps = async ({ req }) => { 2210 | const userAgent = req ?req.headers['user-agent'] : navigator.userAgent 2211 | return { userAgent } 2212 | } 2213 | 2214 | export default Page 2215 | ``` 2216 | 2217 | `React.Component` の場合は `NextPageContext` を使います: 2218 | 2219 | ```tsx 2220 | import React from 'react' 2221 | import { NextPageContext } from 'next' 2222 | 2223 | interface Props { 2224 | userAgent?: string 2225 | } 2226 | 2227 | export default class Page extends React.Component<Props> { 2228 | static async getInitialProps({ req }: NextPageContext) { 2229 | const userAgent = req ?req.headers['user-agent'] : navigator.userAgent 2230 | return { userAgent } 2231 | } 2232 | 2233 | render() { 2234 | const { userAgent } = this.props 2235 | return <main>Your user agent: {userAgent}</main> 2236 | } 2237 | } 2238 | ``` 2239 | 2240 | ## AMP のサポート 2241 | 2242 | <details> 2243 | <summary><b>例</b></summary> 2244 | <ul> 2245 | <li><a href="https://github.com/zeit/next.js/tree/canary/examples/amp">amp</a></li> 2246 | </ul> 2247 | </details> 2248 | 2249 | ### AMP サポートの有効化 2250 | 2251 | `export const config = { amp: true }` をページに追記することで、AMP を有効化することができます。 2252 | 2253 | ### AMP ファーストページ 2254 | 2255 | ```js 2256 | // pages/about.js 2257 | export const config = { amp: true } 2258 | 2259 | export default function AboutPage(props) { 2260 | return <h3>My AMP About Page!</h3> 2261 | } 2262 | ``` 2263 | 2264 | ### ハイブリッド AMP ページ 2265 | 2266 | ```js 2267 | // pages/hybrid-about.js 2268 | import { useAmp } from 'next/amp' 2269 | 2270 | export const config = { amp: 'hybrid' } 2271 | 2272 | export default function AboutPage(props) { 2273 | return ( 2274 | <div> 2275 | <h3>My AMP Page</h3> 2276 | {useAmp() ?( 2277 | <amp-img 2278 | width="300" 2279 | height="300" 2280 | src="/my-img.jpg" 2281 | alt="a cool image" 2282 | layout="responsive" 2283 | /> 2284 | ) : ( 2285 | <img width="300" height="300" src="/my-img.jpg" alt="a cool image" /> 2286 | )} 2287 | </div> 2288 | ) 2289 | } 2290 | ``` 2291 | 2292 | ### AMP ページモード 2293 | 2294 | AMP化するには、2つのモードがあります: 2295 | 2296 | - AMP-only (デフォルト) 2297 | - ページには、Next.js および React のクライアント側でのランタイムはありません 2298 | - ページには AMP キャッシュと同じ変換が適用され、[AMP Optimizer](https://github.com/ampproject/amp-toolbox/tree/master/packages/optimizer)によって自動的に最適化されます (最大で、パフォーマンスを42%向上します) 2299 | - ページには、ユーザーがアクセス可能な(最適化された)バージョンと、検索エンジンでインデックス可能な(最適化されていない)バージョンがあります 2300 | - `export const config = { amp: true }`で設定します 2301 | - ハイブリッド 2302 | - 従来のHTML(デフォルト)のレンダリングに加えて、URLの末尾に `?amp=1` を指定することで AMP HTML としてレンダリングすることが可能です 2303 | - AMPバージョンのページでは、 AMP Optimizer による valid な最適化のみが行われるため、検索エンジンでのインデックスが可能です 2304 | - `export const config = { amp: 'hybrid' }` で設定します 2305 | - `next/amp` の `useAmp` を使用することで、AMP-only とハイブリッドモードを区別することができます 2306 | 2307 | どちらのモードも、検索エンジン経由でのアクセスにおいて一貫した高速な UX を提供します。 2308 | 2309 | ### `next export` における AMP の挙動について 2310 | 2311 | `next export` で静的にページを事前レンダリングする際、Next.js はページが AMP をサポートしているかを検出し、結果に応じて挙動を変更します。 2312 | 2313 | ハイブリッド AMP (`pages/about.js`) での出力例は以下です: 2314 | 2315 | - `out/about.html` - クライアントサイドの React ランタイム 2316 | - `out/about.amp.html` - AMP ページ 2317 | 2318 | AMP-only (`pages/about.js`) での出力例は以下です: 2319 | 2320 | - `out/about.html` - 最適化された AMP ページ 2321 | 2322 | エクスポートの際に、ページがハイブリッド AMP ページかどうかを自動的に検出し、AMP バージョンを `page.amp.html` へ出力します。エクスポート中にページがハイブリッドAMPページかどうかを自動的に検出し、AMPバージョンを `page.amp.html`へ出力します。また、自動的に`<link rel="amphtml" href="/page.amp" />` と `<link rel="canonical" href="/" />`タグを埋め込みます。 2323 | 2324 | > **注意**: `next.config.js` で `exportTrailingSlash: true` と記載した場合、出力先がそれぞれのモードにおいて異なります。ハイブリッド AMPページの場合、出力先が `out/page/index.html` と `out/page.amp/index.html` となり、AMP-only ページだと `out/page/index.html` となります。 2325 | 2326 | ### AMP コンポーネントの追加 2327 | 2328 | AMP コミュニティではたくさんの[コンポーネント](https://amp.dev/documentation/components/)が用意されており、AMP ページをよりインタラクティブにします。下記のように `next/head` を使ってAMP Componentsを追加することができます: 2329 | 2330 | ```js 2331 | // pages/hello.js 2332 | import Head from 'next/head' 2333 | 2334 | export const config = { amp: true } 2335 | 2336 | export default function MyAmpPage() { 2337 | return ( 2338 | <div> 2339 | <Head> 2340 | <script 2341 | async 2342 | key="amp-timeago" 2343 | custom-element="amp-timeago" 2344 | src="https://cdn.ampproject.org/v0/amp-timeago-0.1.js" 2345 | /> 2346 | </Head> 2347 | 2348 | <p>Some time: {date.toJSON()}</p> 2349 | <amp-timeago 2350 | width="0" 2351 | height="15" 2352 | datetime={date.toJSON()} 2353 | layout="responsive" 2354 | > 2355 | . 2356 | </amp-timeago> 2357 | </div> 2358 | ) 2359 | } 2360 | ``` 2361 | 2362 | ### AMP バリデーション 2363 | 2364 | 開発中は、[amphtml-validator](https://www.npmjs.com/package/amphtml-validator)によって、自動で AMP ページが検証されます。エラーと警告に関しては、Next.js を起動したターミナルに表示されます。 2365 | 2366 | また、`next export` の際にも AMP に関する検証が行われ、エラーや警告があればターミナルに表示されます。 2367 | 出力が有効な AMP ではなく AMP に関するエラーが起きた場合は、`next export` はステータスコード `1` をもって処理を終了します。 2368 | 2369 | ### TypeScript のサポート 2370 | 2371 | 現在AMPにはTypeScriptの組み込み型はありません。しかし、ロードマップ ([#13791](https://github.com/ampproject/amphtml/issues/13791))にあるため、近い将来実装されるかもしれません。回避策としては、[参考例](https://stackoverflow.com/a/50601125)のように手動で `amp.d.ts` に型を定義することで TypeScript 化を行えます。 2372 | 2373 | ## Static HTML export 2374 | 2375 | <details> 2376 | <summary><b>例</b></summary> 2377 | <ul> 2378 | <li><a href="/examples/with-static-export">Static export</a></li> 2379 | </ul> 2380 | </details> 2381 | 2382 | `next export` is a way to run your Next.js app as a standalone static app without the need for a Node.js server. 2383 | The exported app supports almost every feature of Next.js, including dynamic urls, prefetching, preloading and dynamic imports. 2384 | 2385 | The way `next export` works is by prerendering all pages possible to HTML. It does so based on a mapping of `pathname` key to page object. This mapping is called the `exportPathMap`. 2386 | 2387 | The page object has 2 values: 2388 | 2389 | - `page` - `String` the page inside the `pages` directory to render 2390 | - `query` - `Object` the `query` object passed to `getInitialProps` when prerendering. Defaults to `{}` 2391 | 2392 | ### Usage 2393 | 2394 | Simply develop your app as you normally do with Next.js. Then run: 2395 | 2396 | ``` 2397 | next build 2398 | next export 2399 | ``` 2400 | 2401 | By default `next export` doesn't require any configuration. It will generate a default `exportPathMap` containing the routes to pages inside the `pages` directory. This default mapping is available as `defaultPathMap` in the example below. 2402 | 2403 | If your application has dynamic routes you can add a dynamic `exportPathMap` in `next.config.js`. 2404 | This function is asynchronous and gets the default `exportPathMap` as a parameter. 2405 | 2406 | ```js 2407 | // next.config.js 2408 | module.exports = { 2409 | exportPathMap: async function( 2410 | defaultPathMap, 2411 | { dev, dir, outDir, distDir, buildId } 2412 | ) { 2413 | return { 2414 | '/': { page: '/' }, 2415 | '/about': { page: '/about' }, 2416 | '/readme.md': { page: '/readme' }, 2417 | '/p/hello-nextjs': { page: '/post', query: { title: 'hello-nextjs' } }, 2418 | '/p/learn-nextjs': { page: '/post', query: { title: 'learn-nextjs' } }, 2419 | '/p/deploy-nextjs': { page: '/post', query: { title: 'deploy-nextjs' } }, 2420 | } 2421 | }, 2422 | } 2423 | ``` 2424 | 2425 | The pages will be exported as html files, i.e. `/about` will become `/about.html`. 2426 | 2427 | It is possible to configure Next.js to export pages as `index.html` files and require trailing slashes, i.e. `/about` becomes `/about/index.html` and is routable via `/about/`. 2428 | This was the default behavior prior to Next.js 9. 2429 | You can use the following `next.config.js` to switch back to this behavior: 2430 | 2431 | ```js 2432 | // next.config.js 2433 | module.exports = { 2434 | exportTrailingSlash: true, 2435 | } 2436 | ``` 2437 | 2438 | > **Note**: If the export path is a filename (e.g. `/readme.md`) and is different than `.html`, you may need to set the `Content-Type` header to `text/html` when serving this content. 2439 | 2440 | The second argument is an `object` with: 2441 | 2442 | - `dev` - `true` when `exportPathMap` is being called in development. `false` when running `next export`. In development `exportPathMap` is used to define routes. 2443 | - `dir` - Absolute path to the project directory 2444 | - `outDir` - Absolute path to the `out/` directory (configurable with `-o` or `--outdir`). When `dev` is `true` the value of `outDir` will be `null`. 2445 | - `distDir` - Absolute path to the `.next/` directory (configurable using the `distDir` config key) 2446 | - `buildId` - The `buildId` the export is running for 2447 | 2448 | Then simply run these commands: 2449 | 2450 | ```bash 2451 | next build 2452 | next export 2453 | ``` 2454 | 2455 | For that you may need to add a NPM script to `package.json` like this: 2456 | 2457 | ```json 2458 | { 2459 | "scripts": { 2460 | "build": "next build", 2461 | "export": "npm run build && next export" 2462 | } 2463 | } 2464 | ``` 2465 | 2466 | And run it at once with: 2467 | 2468 | ```bash 2469 | npm run export 2470 | ``` 2471 | 2472 | Then you have a static version of your app in the `out` directory. 2473 | 2474 | > You can also customize the output directory. For that run `next export -h` for the help. 2475 | 2476 | Now you can deploy the `out` directory to any static hosting service. Note that there is an additional step for deploying to GitHub Pages, [documented here](https://github.com/zeit/next.js/wiki/Deploying-a-Next.js-app-into-GitHub-Pages). 2477 | 2478 | For an example, simply visit the `out` directory and run following command to deploy your app to [ZEIT Now](https://zeit.co/now). 2479 | 2480 | ```bash 2481 | now 2482 | ``` 2483 | 2484 | ### Limitation 2485 | 2486 | With `next export`, we build a HTML version of your app. At export time we will run `getInitialProps` of your pages. 2487 | 2488 | The `req` and `res` fields of the `context` object passed to `getInitialProps` are empty objects during export as there is no server running. 2489 | 2490 | > **Note**: If your pages don't have `getInitialProps` you may not need `next export` at all, `next build` is already enough thanks to [automatic static optimization](#automatic-static-optimization). 2491 | 2492 | > You won't be able to render HTML dynamically when static exporting, as we pre-build the HTML files. If you want to do dynamic rendering use `next start` or the custom server API 2493 | 2494 | ## Multi Zones 2495 | 2496 | <details> 2497 | <summary><b>例</b></summary> 2498 | <ul> 2499 | <li><a href="/examples/with-zones">With Zones</a></li> 2500 | </ul> 2501 | </details> 2502 | 2503 | A zone is a single deployment of a Next.js app. Just like that, you can have multiple zones and then you can merge them as a single app. 2504 | 2505 | For an example, you can have two zones like this: 2506 | 2507 | - An app for serving `/blog/**` 2508 | - Another app for serving all other pages 2509 | 2510 | With multi zones support, you can merge both these apps into a single one allowing your customers to browse it using a single URL, but you can develop and deploy both apps independently. 2511 | 2512 | > This is exactly the same concept of microservices, but for frontend apps. 2513 | 2514 | ### How to define a zone 2515 | 2516 | There are no special zones related APIs. You only need to do following: 2517 | 2518 | - Make sure to keep only the pages you need in your app, meaning that an app can't have pages from another app, if app `A` has `/blog` then app `B` shouldn't have it too. 2519 | - Make sure to add an [assetPrefix](https://github.com/zeit/next.js#cdn-support-with-asset-prefix) to avoid conflicts with static files. 2520 | 2521 | ### How to merge them 2522 | 2523 | You can merge zones using any HTTP proxy. 2524 | 2525 | You can use [now dev](https://zeit.co/docs/v2/development/basics) as your local development server. It allows you to easily define routing routes for multiple apps like below: 2526 | 2527 | ```json 2528 | { 2529 | "version": 2, 2530 | "builds": [ 2531 | { "src": "docs/next.config.js", "use": "@now/next" }, 2532 | { "src": "home/next.config.js", "use": "@now/next" } 2533 | ], 2534 | "routes": [ 2535 | { "src": "/docs(.*)", "dest": "docs$1", "continue": true }, 2536 | { "src": "(?!/?docs)(.*)", "dest": "home$1", "continue": true } 2537 | ] 2538 | } 2539 | ``` 2540 | 2541 | For the production deployment, you can use the same configuration and run `now` to do the deployment with [ZEIT Now](https://zeit.co/now). Otherwise you can also configure a proxy server to route using a set of routes like the ones above, e.g deploy the docs app to `https://docs.example.com` and the home app to `https://home.example.com` and then add a proxy server for both apps in `https://example.com`. 2542 | 2543 | ## FAQ 2544 | 2545 | <details> 2546 | <summary>Is this production ready?</summary> 2547 | Next.js has been powering https://zeit.co since its inception. 2548 | 2549 | We’re ecstatic about both the developer experience and end-user performance, so we decided to share it with the community. 2550 | 2551 | </details> 2552 | 2553 | <details> 2554 | <summary>How big is it?</summary> 2555 | 2556 | The client side bundle size should be measured in a per-app basis. 2557 | A small Next main bundle is around 65kb gzipped. 2558 | 2559 | </details> 2560 | 2561 | <details> 2562 | <summary>Is this like `create-react-app`?</summary> 2563 | 2564 | Yes and No. 2565 | 2566 | Yes in that both make your life easier. 2567 | 2568 | No in that it enforces a _structure_ so that we can do more advanced things like: 2569 | 2570 | - Server side rendering 2571 | - Automatic code splitting 2572 | 2573 | In addition, Next.js provides two built-in features that are critical for every single website: 2574 | 2575 | - Routing with lazy component loading: `<Link>` (by importing `next/link`) 2576 | - A way for components to alter `<head>`: `<Head>` (by importing `next/head`) 2577 | 2578 | If you want to create re-usable React components that you can embed in your Next.js app or other React applications, using `create-react-app` is a great idea. You can later `import` it and keep your codebase clean! 2579 | 2580 | </details> 2581 | 2582 | <details> 2583 | <summary>How do I use CSS-in-JS solutions?</summary> 2584 | 2585 | Next.js bundles [styled-jsx](https://github.com/zeit/styled-jsx) supporting scoped css. However you can use any CSS-in-JS solution in your Next app by just including your favorite library [as mentioned before](#css-in-js) in the document. 2586 | 2587 | </details> 2588 | 2589 | <details> 2590 | <summary>What syntactic features are transpiled?How do I change them?</summary> 2591 | 2592 | We track V8. Since V8 has wide support for ES6 and `async` and `await`, we transpile those. Since V8 doesn’t support class decorators, we don’t transpile those. 2593 | 2594 | See the documentation about [customizing the babel config](#customizing-babel-config) and [next/preset](https://github.com/zeit/next.js/tree/canary/packages/next/build/babel/preset.ts) for more information. 2595 | 2596 | </details> 2597 | 2598 | <details> 2599 | <summary>Why a new Router?</summary> 2600 | 2601 | Next.js is special in that: 2602 | 2603 | - Routes don’t need to be known ahead of time 2604 | - Routes are always lazy-loadable 2605 | - Top-level components can define `getInitialProps` that should _block_ the loading of the route (either when server-rendering or lazy-loading) 2606 | 2607 | As a result, we were able to introduce a very simple approach to routing that consists of two pieces: 2608 | 2609 | - Every top level component receives a `url` object to inspect the url or perform modifications to the history 2610 | - A `<Link />` component is used to wrap elements like anchors (`<a/>`) to perform client-side transitions 2611 | 2612 | </details> 2613 | 2614 | <details> 2615 | <summary>How do I define a custom fancy route?</summary> 2616 | 2617 | Next.js provide [dynamic routing](#dynamic-routing) solution out of the box. This allows to use pretty links in url. 2618 | 2619 | You can check an [example](https://github.com/zeit/next.js/tree/canary/examples/dynamic-routing) to see how it works. 2620 | 2621 | </details> 2622 | 2623 | <details> 2624 | <summary>How do I fetch data?</summary> 2625 | 2626 | It’s up to you. `getInitialProps` is an `async` function (or a regular function that returns a `Promise`). It can retrieve data from anywhere. 2627 | 2628 | </details> 2629 | 2630 | <details> 2631 | <summary>Can I use it with GraphQL?</summary> 2632 | 2633 | Yes! Here's an example with [Apollo](https://github.com/zeit/next.js/tree/canary/examples/with-apollo). 2634 | 2635 | </details> 2636 | 2637 | <details> 2638 | <summary>Can I use it with Redux and thunk?</summary> 2639 | 2640 | Yes! Here's an [example](https://github.com/zeit/next.js/tree/canary/examples/with-redux-thunk). 2641 | 2642 | </details> 2643 | 2644 | <details> 2645 | <summary>Can I use it with Redux?</summary> 2646 | 2647 | Yes! Here's an [example](https://github.com/zeit/next.js/tree/canary/examples/with-redux). 2648 | 2649 | </details> 2650 | 2651 | <details> 2652 | <summary>Can I use Next with my favorite Javascript library or toolkit?</summary> 2653 | 2654 | Since our first release we've had **many** example contributions, you can check them out in the [examples](https://github.com/zeit/next.js/tree/canary/examples) directory. 2655 | 2656 | </details> 2657 | 2658 | <details> 2659 | <summary>What is this inspired by?</summary> 2660 | 2661 | Many of the goals we set out to accomplish were the ones listed in [The 7 principles of Rich Web Applications](http://rauchg.com/2014/7-principles-of-rich-web-applications/) by Guillermo Rauch. 2662 | 2663 | The ease-of-use of PHP is a great inspiration. We feel Next.js is a suitable replacement for many scenarios where you otherwise would use PHP to output HTML. 2664 | 2665 | Unlike PHP, we benefit from the ES6 module system and every file exports a **component or function** that can be easily imported for lazy evaluation or testing. 2666 | 2667 | As we were researching options for server-rendering React that didn’t involve a large number of steps, we came across [react-page](https://github.com/facebookarchive/react-page) (now deprecated), a similar approach to Next.js by the creator of React Jordan Walke. 2668 | 2669 | </details> 2670 | 2671 | ## Contributing 2672 | 2673 | Please see our [contributing.md](https://github.com/zeit/next.js/tree/canary/contributing.md). 2674 | 2675 | ## Authors 2676 | 2677 | - Arunoda Susiripala ([@arunoda](https://twitter.com/arunoda)) – [ZEIT](https://zeit.co) 2678 | - Tim Neutkens ([@timneutkens](https://twitter.com/timneutkens)) – [ZEIT](https://zeit.co) 2679 | - Naoyuki Kanezawa ([@nkzawa](https://twitter.com/nkzawa)) – [ZEIT](https://zeit.co) 2680 | - Tony Kovanen ([@tonykovanen](https://twitter.com/tonykovanen)) – [ZEIT](https://zeit.co) 2681 | - Guillermo Rauch ([@rauchg](https://twitter.com/rauchg)) – [ZEIT](https://zeit.co) 2682 | - Dan Zajdband ([@impronunciable](https://twitter.com/impronunciable)) – Knight-Mozilla / Coral Project 2683 | --------------------------------------------------------------------------------