From fe2924c5f41facbf520306a995b23e9e69c955ae Mon Sep 17 00:00:00 2001
From: Tim Neutkens
Date: Mon, 23 Oct 2017 21:36:17 +0200
Subject: [PATCH 001/163] Release 4.1.4-canary.1
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 9e0b84ba6862..d91cd112dd4f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "next",
- "version": "4.1.3",
+ "version": "4.1.4-canary.1",
"description": "Minimalistic framework for server-rendered React applications",
"main": "./dist/server/next.js",
"license": "MIT",
From ba31826d2e4519f19c3b24b428fce8f837d2dff4 Mon Sep 17 00:00:00 2001
From: Tim Neutkens
Date: Mon, 23 Oct 2017 22:13:59 +0200
Subject: [PATCH 002/163] Update deploy keys
---
.travis.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 76067578e1eb..08bb0e04c845 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -30,7 +30,7 @@
email: "leo@zeit.co",
api_key: {
secure:
- "HGFqez0XKG3vWJUmDjC1veVJmdASUYviaAbJCqQi4JbgNs49AelhYk3w4vl7K6wOnS2OUPD7tICKNDpxBhunKmVlEkLQtqSnQZjmi4x2tGufGTka0c9O7qNSFsiQXAzta/97MnhmGnJocFsppNNsS21H2aswNQJo+P2QXvmHvFbwzda6k3NwtOc43K+0rW1NM164UwRjtD38LWF+jvhYyysTrWTFXbYUp2o1Q8kI31pn4pMhhOP3qOnuS1jpOzjk6uZ4g5u4cMeK2eSZ/j8B1PNUBXjBfu75IU0yzvlr3ypN7hYcutDTBn4ISDfFM874FdrFhcGiMy7gMO/iwC5LTUqkBGYJT6sYdWEkKU7HQygKeFkinrkmypFdJf9ufw2EDjVCUDYnC5JbnOwu4d3vFHcg3GU6Oa7g1nrScPnZ+jkoM4ugia/3vhFO7serq4qXEj7Mv5p78mW41gxHUTgf8uqwhiOnqo9Or7UsR7vU/hB3uU0DY/nq5BI3Wt4XANrlTDeMDExjDACIQ1GU089va88NbWyU1XDD2zs+o1Y6OigAkn/yZ8V/z52eYcA5znTxcb4s8P36pKCSEkxyRtpHNf138hDx9qC2Hze1alBDfUC4iRhiZCQN4CXhSxVdb6HjZHNwCyWCO16LZLbnBvCbIMR+0WjnL0KzqsUTOboZHkQ="
+ "br9gLncKeLSoL7iOq0PXFeD1Gp3jRI8QMCSNIrGdZg/MuLeuwYPv36kmMgf7aGIfpjFLtU2/eVrOHSB+T5g1nKgOsqmWsfZE1tQYWph0//ookd/sj+IyxIx8nVLbUV/C4ctYOhX/efotRgNn56w5Av5hWc1IQLmW9mSN8ijrQnM+GzRI8QitiofeY2EP3N1eO8vC8E2oGkOsAdcypiX6lFG908zyWt7X2SD+iOsK2eAHjxoAEUdrxE5a8gTDhcTH6qnmtBs9rCeEKbO3JZjEy5dvccxlX3Nd+2GC1rckayk6o5L/zveTilsUx6Auqqbwn1dT5ffQuYsV4RPofs8IMrhnizc8y+OfUcCCpBJ4ia4w7N8FEP56TnRNTFoFBGJL5Y6NfeT0HHAlClxUWMG9pRGWGN+sskODDQ9FEntGZoqwV396ogs+3YhkxbY0AIr84QOctflsFcPtOgr/CoBeOsjbB+o9+Rlsqwlf3u3B7qhtU9eV6KcMfK4x9qW+2cwTllK+gD8S9wILx5BChkfx99g/7u/Rg1PCym64tTsDOBtqTVC2YCqeYYvjmpw4Vl3ofLrFsoNQnbmb6Q5+JSpOcJ/bEj7P/FuZdlU0fNV28tFhElu5caKhSCJz/avUlXG7NeveW1Ee8gjhURC4V/l4ryacyjA2vcDY/4RRkWtHNr4="
},
skip_cleanup: true,
on: {
@@ -44,7 +44,7 @@
tag: "canary",
api_key: {
secure:
- "HGFqez0XKG3vWJUmDjC1veVJmdASUYviaAbJCqQi4JbgNs49AelhYk3w4vl7K6wOnS2OUPD7tICKNDpxBhunKmVlEkLQtqSnQZjmi4x2tGufGTka0c9O7qNSFsiQXAzta/97MnhmGnJocFsppNNsS21H2aswNQJo+P2QXvmHvFbwzda6k3NwtOc43K+0rW1NM164UwRjtD38LWF+jvhYyysTrWTFXbYUp2o1Q8kI31pn4pMhhOP3qOnuS1jpOzjk6uZ4g5u4cMeK2eSZ/j8B1PNUBXjBfu75IU0yzvlr3ypN7hYcutDTBn4ISDfFM874FdrFhcGiMy7gMO/iwC5LTUqkBGYJT6sYdWEkKU7HQygKeFkinrkmypFdJf9ufw2EDjVCUDYnC5JbnOwu4d3vFHcg3GU6Oa7g1nrScPnZ+jkoM4ugia/3vhFO7serq4qXEj7Mv5p78mW41gxHUTgf8uqwhiOnqo9Or7UsR7vU/hB3uU0DY/nq5BI3Wt4XANrlTDeMDExjDACIQ1GU089va88NbWyU1XDD2zs+o1Y6OigAkn/yZ8V/z52eYcA5znTxcb4s8P36pKCSEkxyRtpHNf138hDx9qC2Hze1alBDfUC4iRhiZCQN4CXhSxVdb6HjZHNwCyWCO16LZLbnBvCbIMR+0WjnL0KzqsUTOboZHkQ="
+ "br9gLncKeLSoL7iOq0PXFeD1Gp3jRI8QMCSNIrGdZg/MuLeuwYPv36kmMgf7aGIfpjFLtU2/eVrOHSB+T5g1nKgOsqmWsfZE1tQYWph0//ookd/sj+IyxIx8nVLbUV/C4ctYOhX/efotRgNn56w5Av5hWc1IQLmW9mSN8ijrQnM+GzRI8QitiofeY2EP3N1eO8vC8E2oGkOsAdcypiX6lFG908zyWt7X2SD+iOsK2eAHjxoAEUdrxE5a8gTDhcTH6qnmtBs9rCeEKbO3JZjEy5dvccxlX3Nd+2GC1rckayk6o5L/zveTilsUx6Auqqbwn1dT5ffQuYsV4RPofs8IMrhnizc8y+OfUcCCpBJ4ia4w7N8FEP56TnRNTFoFBGJL5Y6NfeT0HHAlClxUWMG9pRGWGN+sskODDQ9FEntGZoqwV396ogs+3YhkxbY0AIr84QOctflsFcPtOgr/CoBeOsjbB+o9+Rlsqwlf3u3B7qhtU9eV6KcMfK4x9qW+2cwTllK+gD8S9wILx5BChkfx99g/7u/Rg1PCym64tTsDOBtqTVC2YCqeYYvjmpw4Vl3ofLrFsoNQnbmb6Q5+JSpOcJ/bEj7P/FuZdlU0fNV28tFhElu5caKhSCJz/avUlXG7NeveW1Ee8gjhURC4V/l4ryacyjA2vcDY/4RRkWtHNr4="
},
skip_cleanup: true,
on: {
From 2ec397b3564d5dbca933e8def9cd0801ebd3a2b5 Mon Sep 17 00:00:00 2001
From: Tim Neutkens
Date: Mon, 23 Oct 2017 22:15:26 +0200
Subject: [PATCH 003/163] Release 4.1.4-canary.2
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index d91cd112dd4f..77c0cb6581f8 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "next",
- "version": "4.1.4-canary.1",
+ "version": "4.1.4-canary.2",
"description": "Minimalistic framework for server-rendered React applications",
"main": "./dist/server/next.js",
"license": "MIT",
From 2d3192e4b8e43d4404fcc14058229197df8b9e70 Mon Sep 17 00:00:00 2001
From: Wes Bos
Date: Thu, 26 Oct 2017 15:29:53 -0400
Subject: [PATCH 004/163] Update styled components for React 16 (#3187)
Next 4 only works with React 16, so for this example to work we need an update.
---
examples/with-styled-components/package.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/examples/with-styled-components/package.json b/examples/with-styled-components/package.json
index a5b15b587075..9976e91beb42 100644
--- a/examples/with-styled-components/package.json
+++ b/examples/with-styled-components/package.json
@@ -9,8 +9,8 @@
"dependencies": {
"babel-plugin-styled-components": "^1.1.5",
"next": "latest",
- "react": "^15.6.1",
- "react-dom": "^15.6.1",
+ "react": "^16.0.0",
+ "react-dom": "^16.0.0",
"styled-components": "^2.1.0"
},
"license": "ISC"
From 814b1821e6616621248a2c7a83f5cd352f0c68e9 Mon Sep 17 00:00:00 2001
From: m-allanson
Date: Fri, 27 Oct 2017 12:19:30 +0100
Subject: [PATCH 005/163] Remove extra word (#3193)
---
readme.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/readme.md b/readme.md
index c1b5cd510505..c53082fd3c52 100644
--- a/readme.md
+++ b/readme.md
@@ -62,7 +62,7 @@ npm install --save next react react-dom
```
> Next.js 4 only supports [React 16](https://reactjs.org/blog/2017/09/26/react-v16.0.html).
-> We had to drop React 15 support due to the way how React 16 works and how we use it.
+> We had to drop React 15 support due to the way React 16 works and how we use it.
and add a script to your package.json like this:
From c0eca35810b7c755d15c206ead2e6d97d49ce8ea Mon Sep 17 00:00:00 2001
From: Sebastian
Date: Sat, 28 Oct 2017 05:19:56 -0200
Subject: [PATCH 006/163] with-apollo example using Apollo 2 (#3180)
* Updated dependencies related to Apollo and React.
* Updated libs with Apollo 2 new set of modules.
* Updated to Apollo 2 react integration modules.
* Updated withData to separate apollo state from the app's state.
---
examples/with-apollo/components/PostList.js | 3 ++-
examples/with-apollo/components/PostUpvoter.js | 3 ++-
examples/with-apollo/components/Submit.js | 3 ++-
examples/with-apollo/lib/initApollo.js | 15 +++++++++------
examples/with-apollo/lib/withData.js | 7 ++-----
examples/with-apollo/package.json | 11 +++++++----
6 files changed, 24 insertions(+), 18 deletions(-)
diff --git a/examples/with-apollo/components/PostList.js b/examples/with-apollo/components/PostList.js
index 59efbcfb7911..ecd59292ed36 100644
--- a/examples/with-apollo/components/PostList.js
+++ b/examples/with-apollo/components/PostList.js
@@ -1,4 +1,5 @@
-import { gql, graphql } from 'react-apollo'
+import { graphql } from 'react-apollo'
+import gql from 'graphql-tag'
import ErrorMessage from './ErrorMessage'
import PostUpvoter from './PostUpvoter'
diff --git a/examples/with-apollo/components/PostUpvoter.js b/examples/with-apollo/components/PostUpvoter.js
index 9c77e28f5986..05814bf61cba 100644
--- a/examples/with-apollo/components/PostUpvoter.js
+++ b/examples/with-apollo/components/PostUpvoter.js
@@ -1,5 +1,6 @@
import React from 'react'
-import { gql, graphql } from 'react-apollo'
+import { graphql } from 'react-apollo'
+import gql from 'graphql-tag'
function PostUpvoter ({ upvote, votes, id }) {
return (
diff --git a/examples/with-apollo/components/Submit.js b/examples/with-apollo/components/Submit.js
index 5a780c7eeb3f..792d3b5db059 100644
--- a/examples/with-apollo/components/Submit.js
+++ b/examples/with-apollo/components/Submit.js
@@ -1,4 +1,5 @@
-import { gql, graphql } from 'react-apollo'
+import { graphql } from 'react-apollo'
+import gql from 'graphql-tag'
function Submit ({ createPost }) {
function handleSubmit (e) {
diff --git a/examples/with-apollo/lib/initApollo.js b/examples/with-apollo/lib/initApollo.js
index dfd1976fbefd..5b315f92bd0c 100644
--- a/examples/with-apollo/lib/initApollo.js
+++ b/examples/with-apollo/lib/initApollo.js
@@ -1,4 +1,6 @@
-import { ApolloClient, createNetworkInterface } from 'react-apollo'
+import { ApolloClient } from 'apollo-client'
+import { HttpLink } from 'apollo-link-http'
+import { InMemoryCache } from 'apollo-cache-inmemory'
import fetch from 'isomorphic-fetch'
let apolloClient = null
@@ -10,14 +12,15 @@ if (!process.browser) {
function create (initialState) {
return new ApolloClient({
- initialState,
+ connectToDevTools: process.browser,
ssrMode: !process.browser, // Disables forceFetch on the server (so queries are only run once)
- networkInterface: createNetworkInterface({
+ link: new HttpLink({
uri: 'https://api.graph.cool/simple/v1/cixmkt2ul01q00122mksg82pn', // Server URL (must be absolute)
- opts: { // Additional fetch() options like `credentials` or `headers`
- credentials: 'same-origin'
+ opts: {
+ credentials: 'same-origin' // Additional fetch() options like `credentials` or `headers`
}
- })
+ }),
+ cache: new InMemoryCache().restore(initialState || {}),
})
}
diff --git a/examples/with-apollo/lib/withData.js b/examples/with-apollo/lib/withData.js
index 47207902d13f..10954497d57f 100644
--- a/examples/with-apollo/lib/withData.js
+++ b/examples/with-apollo/lib/withData.js
@@ -48,12 +48,9 @@ export default ComposedComponent => {
Head.rewind()
// Extract query data from the Apollo store
- const state = apollo.getInitialState()
-
serverState = {
apollo: {
- // Only include the Apollo data state
- data: state.data
+ data: apollo.cache.extract()
}
}
}
@@ -66,7 +63,7 @@ export default ComposedComponent => {
constructor (props) {
super(props)
- this.apollo = initApollo(this.props.serverState)
+ this.apollo = initApollo(this.props.serverState.apollo.data)
}
render () {
diff --git a/examples/with-apollo/package.json b/examples/with-apollo/package.json
index 9d48d3a2d50e..2e3bdbe127ef 100644
--- a/examples/with-apollo/package.json
+++ b/examples/with-apollo/package.json
@@ -7,13 +7,16 @@
"start": "next start"
},
"dependencies": {
- "graphql": "^0.9.3",
+ "apollo-client-preset": "^1.0.1",
+ "graphql": "^0.11.7",
+ "graphql-anywhere": "^3.1.0",
+ "graphql-tag": "^2.5.0",
"isomorphic-fetch": "^2.2.1",
"next": "latest",
"prop-types": "^15.5.8",
- "react": "^15.5.4",
- "react-dom": "^15.5.4",
- "react-apollo": "^1.1.3"
+ "react": "^16.0.0",
+ "react-apollo": "^2.0.0",
+ "react-dom": "^16.0.0"
},
"author": "",
"license": "ISC"
From 98b48fb3ec0b2edece70b21fe89de005a6c0f375 Mon Sep 17 00:00:00 2001
From: Remy Sharp
Date: Sat, 28 Oct 2017 08:23:15 +0100
Subject: [PATCH 007/163] Change _error.js example to use `err` prop (#3197)
The `jsonPageRes` isn't always there, whereas `err` is, and when used,
provides a consistent statusCode in the client when compared to the
server.
---
readme.md | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/readme.md b/readme.md
index c53082fd3c52..f6b2ad04a854 100644
--- a/readme.md
+++ b/readme.md
@@ -849,10 +849,8 @@ __Note: React-components outside of `` will not be initialised by the br
import React from 'react'
export default class Error extends React.Component {
- static getInitialProps({ res, jsonPageRes }) {
- const statusCode = res
- ? res.statusCode
- : jsonPageRes ? jsonPageRes.status : null
+ static getInitialProps({ res, err }) {
+ const statusCode = res ? res.statusCode : err ? err.statusCode : null;
return { statusCode }
}
From 78aa068a127fbee53a4f5f73c3c101ea11c00d61 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ismael=20Mart=C3=ADnez?=
Date: Sat, 28 Oct 2017 04:26:00 -0300
Subject: [PATCH 008/163] Upgrade React for examples with next@latest (#3196)
---
examples/root-static-files/package.json | 4 ++--
examples/using-inferno/package.json | 4 ++--
examples/using-preact/package.json | 4 ++--
examples/with-ant-design/package.json | 9 ++++++---
examples/with-antd-mobile/package.json | 4 ++--
examples/with-freactal/package.json | 4 ++--
examples/with-react-toolbox/package.json | 4 ++--
examples/with-react-uwp/package.json | 4 ++--
examples/with-react-with-styles/package.json | 4 ++--
examples/with-redux-code-splitting/package.json | 4 ++--
examples/with-redux-saga/package.json | 4 ++--
examples/with-webpack-bundle-analyzer/package.json | 4 ++--
examples/with-webpack-bundle-size-analyzer/package.json | 4 ++--
13 files changed, 30 insertions(+), 27 deletions(-)
diff --git a/examples/root-static-files/package.json b/examples/root-static-files/package.json
index f0b2e3082f88..f24e181b0141 100644
--- a/examples/root-static-files/package.json
+++ b/examples/root-static-files/package.json
@@ -8,7 +8,7 @@
},
"dependencies": {
"next": "latest",
- "react": "^15.5.4",
- "react-dom": "^15.5.4"
+ "react": "^16.0.0",
+ "react-dom": "^16.0.0"
}
}
diff --git a/examples/using-inferno/package.json b/examples/using-inferno/package.json
index f3d0ff4f95bf..f8a17a703290 100644
--- a/examples/using-inferno/package.json
+++ b/examples/using-inferno/package.json
@@ -12,8 +12,8 @@
"inferno-server": "^1.4.0",
"module-alias": "^2.0.0",
"next": "latest",
- "react": "^15.6.1",
- "react-dom": "^15.6.1"
+ "react": "^16.0.0",
+ "react-dom": "^16.0.0"
},
"license": "MIT"
}
diff --git a/examples/using-preact/package.json b/examples/using-preact/package.json
index 1db87b8f82fd..8c9c613dcdf1 100644
--- a/examples/using-preact/package.json
+++ b/examples/using-preact/package.json
@@ -11,8 +11,8 @@
"next": "latest",
"preact": "^7.2.0",
"preact-compat": "^3.14.0",
- "react": "^15.6.1",
- "react-dom": "^15.6.1"
+ "react": "^16.0.0",
+ "react-dom": "^16.0.0"
},
"license": "ISC",
"devDependencies": {
diff --git a/examples/with-ant-design/package.json b/examples/with-ant-design/package.json
index a98ee6091606..01718bf41714 100644
--- a/examples/with-ant-design/package.json
+++ b/examples/with-ant-design/package.json
@@ -10,8 +10,11 @@
"antd": "^2.10.2",
"babel-plugin-import": "^1.1.1",
"next": "latest",
- "react": "^15.5.4",
- "react-dom": "^15.5.4"
+ "react": "^16.0.0",
+ "react-dom": "^16.0.0"
},
- "license": "ISC"
+ "license": "ISC",
+ "devDependencies": {
+ "babel-plugin-transform-decorators-legacy": "^1.3.4"
+ }
}
diff --git a/examples/with-antd-mobile/package.json b/examples/with-antd-mobile/package.json
index edab58eba28a..572e9c718d1c 100644
--- a/examples/with-antd-mobile/package.json
+++ b/examples/with-antd-mobile/package.json
@@ -5,8 +5,8 @@
"antd-mobile": "1.4.0",
"babel-plugin-import": "^1.2.1",
"next": "latest",
- "react": "^15.6.1",
- "react-dom": "^15.6.1",
+ "react": "^16.0.0",
+ "react-dom": "^16.0.0",
"require-hacker": "^3.0.0",
"svg-sprite-loader": "0.3.1"
},
diff --git a/examples/with-freactal/package.json b/examples/with-freactal/package.json
index f51090ed9d10..e280744809b0 100644
--- a/examples/with-freactal/package.json
+++ b/examples/with-freactal/package.json
@@ -10,8 +10,8 @@
"freactal": "^1.1.1",
"isomorphic-fetch": "^2.2.1",
"next": "latest",
- "react": "^15.6.1",
- "react-dom": "^15.6.1"
+ "react": "^16.0.0",
+ "react-dom": "^16.0.0"
},
"license": "ISC"
}
diff --git a/examples/with-react-toolbox/package.json b/examples/with-react-toolbox/package.json
index 2957e31c1516..ae98870f7b35 100644
--- a/examples/with-react-toolbox/package.json
+++ b/examples/with-react-toolbox/package.json
@@ -10,9 +10,9 @@
"dependencies": {
"classnames": "^2.2.5",
"next": "latest",
- "react": "^15.5.4",
+ "react": "^16.0.0",
"react-addons-css-transition-group": "^15.5.2",
- "react-dom": "^15.5.4",
+ "react-dom": "^16.0.0",
"react-toolbox": "^2.0.0-beta.8"
},
"devDependencies": {
diff --git a/examples/with-react-uwp/package.json b/examples/with-react-uwp/package.json
index e2bbb7d02ca1..c785ada03bb7 100644
--- a/examples/with-react-uwp/package.json
+++ b/examples/with-react-uwp/package.json
@@ -4,8 +4,8 @@
"dependencies": {
"babel-core": "^6.25.0",
"next": "latest",
- "react": "^15.5.4",
- "react-dom": "^15.5.4",
+ "react": "^16.0.0",
+ "react-dom": "^16.0.0",
"react-uwp": "^1.0.9"
},
"scripts": {
diff --git a/examples/with-react-with-styles/package.json b/examples/with-react-with-styles/package.json
index fbb0af3b9176..ad7f956b898d 100644
--- a/examples/with-react-with-styles/package.json
+++ b/examples/with-react-with-styles/package.json
@@ -9,8 +9,8 @@
"dependencies": {
"aphrodite": "^1.2.1",
"next": "latest",
- "react": "^15.6.1",
- "react-dom": "^15.6.1",
+ "react": "^16.0.0",
+ "react-dom": "^16.0.0",
"react-with-styles": "^1.4.0",
"react-with-styles-interface-aphrodite": "^1.2.0"
},
diff --git a/examples/with-redux-code-splitting/package.json b/examples/with-redux-code-splitting/package.json
index 96d2be9dcff4..7baa1b061592 100644
--- a/examples/with-redux-code-splitting/package.json
+++ b/examples/with-redux-code-splitting/package.json
@@ -10,8 +10,8 @@
"fast-redux": "~0.3.0",
"next": "latest",
"next-redux-wrapper": "~1.3.2",
- "react": "~15.6.1",
- "react-dom": "~15.6.1",
+ "react": "^16.0.0",
+ "react-dom": "^16.0.0",
"react-redux": "~5.0.5",
"redux": "~3.7.2",
"redux-devtools-extension": "~2.13.2",
diff --git a/examples/with-redux-saga/package.json b/examples/with-redux-saga/package.json
index cbaa8d27feb5..0414ddf4e183 100644
--- a/examples/with-redux-saga/package.json
+++ b/examples/with-redux-saga/package.json
@@ -13,8 +13,8 @@
"next": "latest",
"next-redux-saga": "1.0.1",
"next-redux-wrapper": "1.2.0",
- "react": "15.6.1",
- "react-dom": "15.6.1",
+ "react": "^16.0.0",
+ "react-dom": "^16.0.0",
"react-redux": "5.0.5",
"redux": "3.7.2",
"redux-saga": "0.15.4"
diff --git a/examples/with-webpack-bundle-analyzer/package.json b/examples/with-webpack-bundle-analyzer/package.json
index 65767abd85f1..11e9315faac7 100644
--- a/examples/with-webpack-bundle-analyzer/package.json
+++ b/examples/with-webpack-bundle-analyzer/package.json
@@ -11,8 +11,8 @@
"next": "latest",
"cross-env": "^5.0.1",
"faker": "^4.1.0",
- "react": "^15.6.1",
- "react-dom": "^15.6.1",
+ "react": "^16.0.0",
+ "react-dom": "^16.0.0",
"webpack-bundle-analyzer": "^2.8.2"
},
"license": "ISC"
diff --git a/examples/with-webpack-bundle-size-analyzer/package.json b/examples/with-webpack-bundle-size-analyzer/package.json
index 4997172f3467..db56f7a0741f 100644
--- a/examples/with-webpack-bundle-size-analyzer/package.json
+++ b/examples/with-webpack-bundle-size-analyzer/package.json
@@ -11,8 +11,8 @@
"cross-env": "^5.0.1",
"faker": "^4.1.0",
"next": "latest",
- "react": "^15.6.1",
- "react-dom": "^15.6.1",
+ "react": "^16.0.0",
+ "react-dom": "^16.0.0",
"webpack-bundle-size-analyzer": "^2.7.0"
},
"license": "ISC"
From 152c2c2af3e61e18833fae104ee3af8ddac3d63c Mon Sep 17 00:00:00 2001
From: Tim Neutkens
Date: Sun, 29 Oct 2017 00:19:48 +0200
Subject: [PATCH 009/163] Make sure NODE_ENV is production for react-dom to
optimize
---
bin/next | 3 +++
bin/next-build | 2 --
bin/next-dev | 2 --
bin/next-export | 2 --
bin/next-start | 2 --
5 files changed, 3 insertions(+), 8 deletions(-)
diff --git a/bin/next b/bin/next
index cd8efe42567d..d79a0123716b 100755
--- a/bin/next
+++ b/bin/next
@@ -55,6 +55,9 @@ if (commands.has(cmd)) {
args = process.argv.slice(2)
}
+const defaultEnv = cmd === 'dev' ? 'development' : 'production'
+process.env.NODE_ENV = process.env.NODE_ENV || defaultEnv
+
const bin = join(__dirname, 'next-' + cmd)
const startProcess = () => {
diff --git a/bin/next-build b/bin/next-build
index fcd1347aa9ac..c9cab0293169 100755
--- a/bin/next-build
+++ b/bin/next-build
@@ -5,8 +5,6 @@ import parseArgs from 'minimist'
import build from '../server/build'
import { printAndExit } from '../lib/utils'
-process.env.NODE_ENV = process.env.NODE_ENV || 'production'
-
const argv = parseArgs(process.argv.slice(2), {
alias: {
h: 'help'
diff --git a/bin/next-dev b/bin/next-dev
index 646708b8c835..bfdfc29c2780 100755
--- a/bin/next-dev
+++ b/bin/next-dev
@@ -7,8 +7,6 @@ import Server from '../server'
import { printAndExit } from '../lib/utils'
import pkgUp from 'pkg-up'
-process.env.NODE_ENV = process.env.NODE_ENV || 'development'
-
const argv = parseArgs(process.argv.slice(2), {
alias: {
h: 'help',
diff --git a/bin/next-export b/bin/next-export
index ad9b10fd39c4..a98f6ae7a7d9 100755
--- a/bin/next-export
+++ b/bin/next-export
@@ -5,8 +5,6 @@ import parseArgs from 'minimist'
import exportApp from '../server/export'
import { printAndExit } from '../lib/utils'
-process.env.NODE_ENV = process.env.NODE_ENV || 'production'
-
const argv = parseArgs(process.argv.slice(2), {
alias: {
h: 'help',
diff --git a/bin/next-start b/bin/next-start
index bfd78567c46c..fd743e3b8255 100755
--- a/bin/next-start
+++ b/bin/next-start
@@ -4,8 +4,6 @@ import { resolve } from 'path'
import parseArgs from 'minimist'
import Server from '../server'
-process.env.NODE_ENV = process.env.NODE_ENV || 'production'
-
const argv = parseArgs(process.argv.slice(2), {
alias: {
h: 'help',
From 72827d25cb5990156436d5fffc4bd3ab7a4bdd38 Mon Sep 17 00:00:00 2001
From: Tim Neutkens
Date: Sun, 29 Oct 2017 00:39:45 +0200
Subject: [PATCH 010/163] Add note about NODE_ENV being set automatically
---
readme.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/readme.md b/readme.md
index f6b2ad04a854..9b895cef4fe2 100644
--- a/readme.md
+++ b/readme.md
@@ -1035,6 +1035,8 @@ Then run `now` and enjoy!
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.
+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!
+
Note: we recommend putting `.next`, or your custom dist folder (Please have a look at ['Custom Config'](https://github.com/zeit/next.js#custom-configuration). You can set a custom folder in config, `.npmignore`, or `.gitignore`. Otherwise, use `files` or `now.files` to opt-into a whitelist of files you want to deploy (and obviously exclude `.next` or your custom dist folder).
## Static HTML export
From 4c18678d54947811f1f557c1396e3a3e7ae120cb Mon Sep 17 00:00:00 2001
From: Remy Sharp
Date: Mon, 30 Oct 2017 14:24:31 +0000
Subject: [PATCH 011/163] Create example of activeClassLink using withRouter
(#3188)
---
examples/active-class-name/README.md | 29 +++++++++++++++++
examples/active-class-name/components/Link.js | 18 +++++++++++
examples/active-class-name/components/Nav.js | 31 +++++++++++++++++++
examples/active-class-name/package.json | 16 ++++++++++
examples/active-class-name/pages/about.js | 8 +++++
examples/active-class-name/pages/index.js | 8 +++++
6 files changed, 110 insertions(+)
create mode 100644 examples/active-class-name/README.md
create mode 100644 examples/active-class-name/components/Link.js
create mode 100644 examples/active-class-name/components/Nav.js
create mode 100644 examples/active-class-name/package.json
create mode 100644 examples/active-class-name/pages/about.js
create mode 100644 examples/active-class-name/pages/index.js
diff --git a/examples/active-class-name/README.md b/examples/active-class-name/README.md
new file mode 100644
index 000000000000..7f8b074e6c2c
--- /dev/null
+++ b/examples/active-class-name/README.md
@@ -0,0 +1,29 @@
+[![Deploy to now](https://deploy.now.sh/static/button.svg)](https://deploy.now.sh/?repo=https://github.com/zeit/next.js/tree/master/examples/active-class-name)
+
+# activeClassName example
+
+## How to use
+
+Download the example [or clone the repo](https://github.com/zeit/next.js):
+
+```bash
+curl https://codeload.github.com/zeit/next.js/tar.gz/master | tar -xz --strip=2 next.js-master/examples/active-class-name
+cd active-class-name
+```
+
+Install it and run:
+
+```bash
+npm install
+npm run dev
+```
+
+Deploy it to the cloud with [now](https://zeit.co/now) ([download](https://zeit.co/download))
+
+```bash
+now
+```
+
+## The idea behind the example
+
+ReactRouter has a convenience property on the `Link` element to allow an author to set the _active_ className on a link. This example replicates that functionality using Next's own `Link`.
diff --git a/examples/active-class-name/components/Link.js b/examples/active-class-name/components/Link.js
new file mode 100644
index 000000000000..6621c72cd6cb
--- /dev/null
+++ b/examples/active-class-name/components/Link.js
@@ -0,0 +1,18 @@
+import { withRouter } from 'next/router';
+import Link from 'next/link';
+import React, { Children } from 'react';
+
+const ActiveLink = ({ router, children, ...props }) => {
+ const child = Children.only(children);
+
+ let className = child.props.className || '';
+ if (router.pathname === props.href && props.activeClassName) {
+ className = `${className} ${props.activeClassName}`.trim();
+ }
+
+ delete props.activeClassName;
+
+ return {React.cloneElement(child, { className })};
+};
+
+export default withRouter(ActiveLink);
diff --git a/examples/active-class-name/components/Nav.js b/examples/active-class-name/components/Nav.js
new file mode 100644
index 000000000000..e6249f5a61e8
--- /dev/null
+++ b/examples/active-class-name/components/Nav.js
@@ -0,0 +1,31 @@
+import Link from './Link';
+import Head from 'next/head';
+
+export default () => (
+
+);
diff --git a/examples/active-class-name/package.json b/examples/active-class-name/package.json
new file mode 100644
index 000000000000..2af6844ef740
--- /dev/null
+++ b/examples/active-class-name/package.json
@@ -0,0 +1,16 @@
+{
+ "name": "active-class-name",
+ "version": "1.0.0",
+ "scripts": {
+ "dev": "next",
+ "build": "next build",
+ "start": "next start"
+ },
+ "author": "Remy Sharp ",
+ "dependencies": {
+ "next": "latest",
+ "react": "^16.0.0",
+ "react-dom": "^16.0.0"
+ },
+ "license": "ISC"
+}
diff --git a/examples/active-class-name/pages/about.js b/examples/active-class-name/pages/about.js
new file mode 100644
index 000000000000..e60976717fe3
--- /dev/null
+++ b/examples/active-class-name/pages/about.js
@@ -0,0 +1,8 @@
+import Nav from '../components/Nav';
+
+export default () => (
+
+
+
Hello, I'm About.js
+
+);
diff --git a/examples/active-class-name/pages/index.js b/examples/active-class-name/pages/index.js
new file mode 100644
index 000000000000..3aa81e8c1a6f
--- /dev/null
+++ b/examples/active-class-name/pages/index.js
@@ -0,0 +1,8 @@
+import Nav from '../components/Nav';
+
+export default () => (
+
+
+
Hello, I'm the home page
+
+);
From 53a2c5a7fc14dd7b6a32ed27080534eefd2362f8 Mon Sep 17 00:00:00 2001
From: Kevin Decker
Date: Mon, 30 Oct 2017 09:57:35 -0500
Subject: [PATCH 012/163] Combine source maps (#3178)
* Propagate source maps through combine assets step
* Use constant development build id
* Move combine assets step before uglify step
This ensures that uglify will catch these changes.
* Move dynamic chunks step before uglify step
This ensures that uglify will catch these changes.
* Use chunk templates for page and dynamic chunks
This is a little more in line with how webpack generates its bootstrap and should have better compatibility with other plugins and source map generation.
* Register combined source map with chunks
This ensures that a sourcemap is fully generated.
* Do not minimize combined map inputs
---
server/build/plugins/combine-assets-plugin.js | 33 ++++----
server/build/plugins/dynamic-chunks-plugin.js | 77 +++++++++++--------
server/build/plugins/pages-plugin.js | 66 ++++++++--------
server/build/webpack.js | 1 +
server/index.js | 12 ++-
server/render.js | 7 +-
6 files changed, 110 insertions(+), 86 deletions(-)
diff --git a/server/build/plugins/combine-assets-plugin.js b/server/build/plugins/combine-assets-plugin.js
index 5093b051ed05..b7bae4a4b9df 100644
--- a/server/build/plugins/combine-assets-plugin.js
+++ b/server/build/plugins/combine-assets-plugin.js
@@ -1,3 +1,5 @@
+import { ConcatSource } from 'webpack-sources'
+
// This plugin combines a set of assets into a single asset
// This should be only used with text assets,
// otherwise the result is unpredictable.
@@ -8,23 +10,28 @@ export default class CombineAssetsPlugin {
}
apply (compiler) {
- compiler.plugin('after-compile', (compilation, callback) => {
- let newSource = ''
- this.input.forEach((name) => {
- const asset = compilation.assets[name]
- if (!asset) return
+ compiler.plugin('compilation', (compilation) => {
+ compilation.plugin('additional-chunk-assets', (chunks) => {
+ const concat = new ConcatSource()
- newSource += `${asset.source()}\n`
+ this.input.forEach((name) => {
+ const asset = compilation.assets[name]
+ if (!asset) return
- // We keep existing assets since that helps when analyzing the bundle
- })
+ concat.add(asset)
- compilation.assets[this.output] = {
- source: () => newSource,
- size: () => newSource.length
- }
+ // We keep existing assets since that helps when analyzing the bundle
+ })
- callback()
+ compilation.additionalChunkAssets.push(this.output)
+ compilation.assets[this.output] = concat
+
+ // Register the combined file as an output of the associated chunks
+ chunks.filter((chunk) => {
+ return chunk.files.reduce((prev, file) => prev || this.input.includes(file), false)
+ })
+ .forEach((chunk) => chunk.files.push(this.output))
+ })
})
}
}
diff --git a/server/build/plugins/dynamic-chunks-plugin.js b/server/build/plugins/dynamic-chunks-plugin.js
index 8f00a9563511..655d44d45aa9 100644
--- a/server/build/plugins/dynamic-chunks-plugin.js
+++ b/server/build/plugins/dynamic-chunks-plugin.js
@@ -1,39 +1,48 @@
-export default class PagesPlugin {
+import { ConcatSource } from 'webpack-sources'
+
+const isImportChunk = /^chunks[/\\].*\.js$/
+const matchChunkName = /^chunks[/\\](.*)$/
+
+class DynamicChunkTemplatePlugin {
+ apply (chunkTemplate) {
+ chunkTemplate.plugin('render', function (modules, chunk) {
+ if (!isImportChunk.test(chunk.name)) {
+ return modules
+ }
+
+ const chunkName = matchChunkName.exec(chunk.name)[1]
+ const source = new ConcatSource()
+
+ source.add(`
+ __NEXT_REGISTER_CHUNK('${chunkName}', function() {
+ `)
+ source.add(modules)
+ source.add(`
+ })
+ `)
+
+ return source
+ })
+ }
+}
+
+export default class DynamicChunksPlugin {
apply (compiler) {
- const isImportChunk = /^chunks[/\\].*\.js$/
- const matchChunkName = /^chunks[/\\](.*)$/
-
- compiler.plugin('after-compile', (compilation, callback) => {
- const chunks = Object
- .keys(compilation.namedChunks)
- .map(key => compilation.namedChunks[key])
- .filter(chunk => isImportChunk.test(chunk.name))
-
- chunks.forEach((chunk) => {
- const asset = compilation.assets[chunk.name]
- if (!asset) return
-
- const chunkName = matchChunkName.exec(chunk.name)[1]
-
- const content = asset.source()
- const newContent = `
- window.__NEXT_REGISTER_CHUNK('${chunkName}', function() {
- ${content}
- })
- `
- // Replace the exisiting chunk with the new content
- compilation.assets[chunk.name] = {
- source: () => newContent,
- size: () => newContent.length
- }
-
- // This is to support, webpack dynamic import support with HMR
- compilation.assets[`chunks/${chunk.id}`] = {
- source: () => newContent,
- size: () => newContent.length
- }
+ compiler.plugin('compilation', (compilation) => {
+ compilation.chunkTemplate.apply(new DynamicChunkTemplatePlugin())
+
+ compilation.plugin('additional-chunk-assets', (chunks) => {
+ chunks = chunks.filter(chunk =>
+ isImportChunk.test(chunk.name) && compilation.assets[chunk.name]
+ )
+
+ chunks.forEach((chunk) => {
+ // This is to support, webpack dynamic import support with HMR
+ const copyFilename = `chunks/${chunk.name}`
+ compilation.additionalChunkAssets.push(copyFilename)
+ compilation.assets[copyFilename] = compilation.assets[chunk.name]
+ })
})
- callback()
})
}
}
diff --git a/server/build/plugins/pages-plugin.js b/server/build/plugins/pages-plugin.js
index 907630e6a825..87ee582ce509 100644
--- a/server/build/plugins/pages-plugin.js
+++ b/server/build/plugins/pages-plugin.js
@@ -1,20 +1,17 @@
+import { ConcatSource } from 'webpack-sources'
import {
IS_BUNDLED_PAGE,
MATCH_ROUTE_NAME
} from '../../utils'
-export default class PagesPlugin {
- apply (compiler) {
- compiler.plugin('after-compile', (compilation, callback) => {
- const pages = Object
- .keys(compilation.namedChunks)
- .map(key => compilation.namedChunks[key])
- .filter(chunk => IS_BUNDLED_PAGE.test(chunk.name))
+class PageChunkTemplatePlugin {
+ apply (chunkTemplate) {
+ chunkTemplate.plugin('render', function (modules, chunk) {
+ if (!IS_BUNDLED_PAGE.test(chunk.name)) {
+ return modules
+ }
- pages.forEach((chunk) => {
- const page = compilation.assets[chunk.name]
- const pageName = MATCH_ROUTE_NAME.exec(chunk.name)[1]
- let routeName = pageName
+ let routeName = MATCH_ROUTE_NAME.exec(chunk.name)[1]
// We need to convert \ into / when we are in windows
// to get the proper route name
@@ -22,26 +19,33 @@ export default class PagesPlugin {
// to have "\" in the filename in unix.
// Anyway if someone did that, he'll be having issues here.
// But that's something we cannot avoid.
- if (/^win/.test(process.platform)) {
- routeName = routeName.replace(/\\/g, '/')
- }
-
- routeName = `/${routeName.replace(/(^|\/)index$/, '')}`
-
- const content = page.source()
- const newContent = `
- window.__NEXT_REGISTER_PAGE('${routeName}', function() {
- var comp = ${content}
- return { page: comp.default }
- })
- `
- // Replace the exisiting chunk with the new content
- compilation.assets[chunk.name] = {
- source: () => newContent,
- size: () => newContent.length
- }
- })
- callback()
+ if (/^win/.test(process.platform)) {
+ routeName = routeName.replace(/\\/g, '/')
+ }
+
+ routeName = `/${routeName.replace(/(^|\/)index$/, '')}`
+
+ const source = new ConcatSource()
+
+ source.add(`
+ __NEXT_REGISTER_PAGE('${routeName}', function() {
+ var comp =
+ `)
+ source.add(modules)
+ source.add(`
+ return { page: comp.default }
+ })
+ `)
+
+ return source
+ })
+ }
+}
+
+export default class PagesPlugin {
+ apply (compiler) {
+ compiler.plugin('compilation', (compilation) => {
+ compilation.chunkTemplate.apply(new PageChunkTemplatePlugin())
})
}
}
diff --git a/server/build/webpack.js b/server/build/webpack.js
index d080b1787ffe..231b6c8e4cd7 100644
--- a/server/build/webpack.js
+++ b/server/build/webpack.js
@@ -149,6 +149,7 @@ export default async function createCompiler (dir, { buildId, dev = false, quiet
output: 'app.js'
}),
new webpack.optimize.UglifyJsPlugin({
+ exclude: ['manifest.js', 'commons.js', 'main.js'],
compress: { warnings: false },
sourceMap: false
})
diff --git a/server/index.js b/server/index.js
index 51a4b851d125..164e6e38a888 100644
--- a/server/index.js
+++ b/server/index.js
@@ -408,7 +408,11 @@ export default class Server {
}
handleBuildId (buildId, res) {
- if (this.dev) return true
+ if (this.dev) {
+ res.setHeader('Cache-Control', 'no-store, must-revalidate')
+ return true
+ }
+
if (buildId !== this.renderOpts.buildId) {
return false
}
@@ -428,13 +432,17 @@ export default class Server {
}
handleBuildHash (filename, hash, res) {
- if (this.dev) return
+ if (this.dev) {
+ res.setHeader('Cache-Control', 'no-store, must-revalidate')
+ return true
+ }
if (hash !== this.buildStats[filename].hash) {
throw new Error(`Invalid Build File Hash(${hash}) for chunk: ${filename}`)
}
res.setHeader('Cache-Control', 'max-age=365000000, immutable')
+ return true
}
send404 (res) {
diff --git a/server/render.js b/server/render.js
index bc0ae6fa989e..699eef4f5259 100644
--- a/server/render.js
+++ b/server/render.js
@@ -96,11 +96,6 @@ async function doRender (req, res, pathname, query, {
}
const docProps = await loadGetInitialProps(Document, { ...ctx, renderPage })
- // While developing, we should not cache any assets.
- // So, we use a different buildId for each page load.
- // With that we can ensure, we have unique URL for assets per every page load.
- // So, it'll prevent issues like this: https://git.io/vHLtb
- const devBuildId = Date.now()
if (res.finished) return
@@ -110,7 +105,7 @@ async function doRender (req, res, pathname, query, {
props,
pathname,
query,
- buildId: dev ? devBuildId : buildId,
+ buildId,
buildStats,
assetPrefix,
nextExport,
From c8059b9f12939ae2290af7017cc93c03e50abe8f Mon Sep 17 00:00:00 2001
From: Tim Neutkens
Date: Tue, 31 Oct 2017 08:58:00 +0100
Subject: [PATCH 013/163] Make sure linting passes
---
examples/active-class-name/components/Link.js | 20 +++++++++----------
examples/active-class-name/components/Nav.js | 13 ++++++------
examples/active-class-name/pages/about.js | 4 ++--
examples/active-class-name/pages/index.js | 4 ++--
4 files changed, 20 insertions(+), 21 deletions(-)
diff --git a/examples/active-class-name/components/Link.js b/examples/active-class-name/components/Link.js
index 6621c72cd6cb..9ac3eaa961a6 100644
--- a/examples/active-class-name/components/Link.js
+++ b/examples/active-class-name/components/Link.js
@@ -1,18 +1,18 @@
-import { withRouter } from 'next/router';
-import Link from 'next/link';
-import React, { Children } from 'react';
+import { withRouter } from 'next/router'
+import Link from 'next/link'
+import React, { Children } from 'react'
const ActiveLink = ({ router, children, ...props }) => {
- const child = Children.only(children);
+ const child = Children.only(children)
- let className = child.props.className || '';
+ let className = child.props.className || ''
if (router.pathname === props.href && props.activeClassName) {
- className = `${className} ${props.activeClassName}`.trim();
+ className = `${className} ${props.activeClassName}`.trim()
}
- delete props.activeClassName;
+ delete props.activeClassName
- return {React.cloneElement(child, { className })};
-};
+ return {React.cloneElement(child, { className })}
+}
-export default withRouter(ActiveLink);
+export default withRouter(ActiveLink)
diff --git a/examples/active-class-name/components/Nav.js b/examples/active-class-name/components/Nav.js
index e6249f5a61e8..93befbfa0509 100644
--- a/examples/active-class-name/components/Nav.js
+++ b/examples/active-class-name/components/Nav.js
@@ -1,5 +1,4 @@
-import Link from './Link';
-import Head from 'next/head';
+import Link from './Link'
export default () => (
-);
+)
diff --git a/examples/active-class-name/pages/about.js b/examples/active-class-name/pages/about.js
index e60976717fe3..38affab6ad7c 100644
--- a/examples/active-class-name/pages/about.js
+++ b/examples/active-class-name/pages/about.js
@@ -1,8 +1,8 @@
-import Nav from '../components/Nav';
+import Nav from '../components/Nav'
export default () => (
Hello, I'm About.js
-);
+)
diff --git a/examples/active-class-name/pages/index.js b/examples/active-class-name/pages/index.js
index 3aa81e8c1a6f..e24fd8da2d67 100644
--- a/examples/active-class-name/pages/index.js
+++ b/examples/active-class-name/pages/index.js
@@ -1,8 +1,8 @@
-import Nav from '../components/Nav';
+import Nav from '../components/Nav'
export default () => (
Hello, I'm the home page
-);
+)
From 190853b4ff271d5955648986e72a9fbd2d008b98 Mon Sep 17 00:00:00 2001
From: Li Weinan
Date: Wed, 1 Nov 2017 05:52:51 +0800
Subject: [PATCH 014/163] Support de-deduping head tags by setting key (#3170)
* Support de-deduping head tags by setting key
* move dedupe logic to `unique` function
* fix head tag deduping logic
* remove console.log
* use `toContain` assertions
* update de-duping head tags section in README
---
lib/head.js | 5 +++++
readme.md | 20 ++++++++++++++++++++
server/document.js | 2 +-
test/integration/basic/pages/head.js | 12 ++++++++++++
test/integration/basic/test/rendering.js | 10 ++++++++++
5 files changed, 48 insertions(+), 1 deletion(-)
diff --git a/lib/head.js b/lib/head.js
index 52c56d6ec794..347333201606 100644
--- a/lib/head.js
+++ b/lib/head.js
@@ -48,11 +48,16 @@ const METATYPES = ['name', 'httpEquiv', 'charSet', 'itemProp', 'property']
// which shouldn't be duplicated, like .
function unique () {
+ const keys = new Set()
const tags = new Set()
const metaTypes = new Set()
const metaCategories = {}
return (h) => {
+ if (h.key) {
+ if (keys.has(h.key)) return false
+ keys.add(h.key)
+ }
switch (h.type) {
case 'title':
case 'base':
diff --git a/readme.md b/readme.md
index 9b895cef4fe2..520d07854798 100644
--- a/readme.md
+++ b/readme.md
@@ -197,6 +197,26 @@ export default () =>
```
+To avoid duplicate tags in your `` you can use the `key` property, which will make sure the tag is only rendered once:
+
+```jsx
+import Head from 'next/head'
+export default () => (
+
+
+ My page title
+
+
+
+
+
+
Hello world!
+
+)
+```
+
+In this case only the second `` is rendered.
+
_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_
### Fetching data and component lifecycle
diff --git a/server/document.js b/server/document.js
index c33ffc9bdfb4..9af596c214ca 100644
--- a/server/document.js
+++ b/server/document.js
@@ -88,7 +88,7 @@ export class Head extends Component {
{this.getPreloadDynamicChunks()}
{this.getPreloadMainLinks()}
- {(head || []).map((h, i) => React.cloneElement(h, { key: i }))}
+ {(head || []).map((h, i) => React.cloneElement(h, { key: h.key || i }))}
{styles || null}
{this.props.children}
diff --git a/test/integration/basic/pages/head.js b/test/integration/basic/pages/head.js
index a9b13c876232..95463be16c93 100644
--- a/test/integration/basic/pages/head.js
+++ b/test/integration/basic/pages/head.js
@@ -3,8 +3,20 @@ import Head from 'next/head'
export default () =>
+ {/* this will not render */}
+
+ {/* this will get rendered */}
+
+
+ {/* the following 2 links tag will be rendered both */}
+
+
+
+ {/* only one tag will be rendered as they have the same key */}
+
+
I can haz meta tags
diff --git a/test/integration/basic/test/rendering.js b/test/integration/basic/test/rendering.js
index 4ea7a37c2fc5..21a85c6e2ff5 100644
--- a/test/integration/basic/test/rendering.js
+++ b/test/integration/basic/test/rendering.js
@@ -28,6 +28,16 @@ export default function ({ app }, suiteName, render) {
expect(html.includes('I can haz meta tags')).toBeTruthy()
})
+ test('header helper dedupes tags', async () => {
+ const html = await (render('/head'))
+ expect(html).toContain('')
+ expect(html).not.toContain('')
+ expect(html).toContain('')
+ expect(html).toContain('')
+ expect(html).toContain('')
+ expect(html).not.toContain('')
+ })
+
test('renders styled jsx', async () => {
const $ = await get$('/styled-jsx')
const styleId = $('#blue-box').attr('class')
From 6089377c6bf7615ca3be5ca859fe168b763f6880 Mon Sep 17 00:00:00 2001
From: Thomas Kolar
Date: Wed, 1 Nov 2017 19:53:45 +0100
Subject: [PATCH 015/163] Fix/Update react-with-styles & aphrodite example
(#3224)
* chore(package): Update dependencies for aphrodite and react-with-styles
* refactor: Update example to current version of react-with-styles
---
examples/with-react-with-styles/package.json | 6 +++---
examples/with-react-with-styles/withStyles.js | 6 +++---
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/examples/with-react-with-styles/package.json b/examples/with-react-with-styles/package.json
index ad7f956b898d..5a2e7109f737 100644
--- a/examples/with-react-with-styles/package.json
+++ b/examples/with-react-with-styles/package.json
@@ -7,12 +7,12 @@
"start": "next start"
},
"dependencies": {
- "aphrodite": "^1.2.1",
+ "aphrodite": "^1.2.5",
"next": "latest",
"react": "^16.0.0",
"react-dom": "^16.0.0",
- "react-with-styles": "^1.4.0",
- "react-with-styles-interface-aphrodite": "^1.2.0"
+ "react-with-styles": "^2.2.0",
+ "react-with-styles-interface-aphrodite": "^3.1.1"
},
"license": "MIT"
}
diff --git a/examples/with-react-with-styles/withStyles.js b/examples/with-react-with-styles/withStyles.js
index 1093d5e35a64..76c424abffcd 100644
--- a/examples/with-react-with-styles/withStyles.js
+++ b/examples/with-react-with-styles/withStyles.js
@@ -1,9 +1,9 @@
import ThemedStyleSheet from 'react-with-styles/lib/ThemedStyleSheet'
import aphroditeInterface from 'react-with-styles-interface-aphrodite'
-import { css, withStyles, ThemeProvider } from 'react-with-styles'
+import { css, withStyles } from 'react-with-styles'
import MyDefaultTheme from './defaultTheme'
-ThemedStyleSheet.registerDefaultTheme(MyDefaultTheme)
+ThemedStyleSheet.registerTheme(MyDefaultTheme)
ThemedStyleSheet.registerInterface(aphroditeInterface)
-export { css, withStyles, ThemeProvider, ThemedStyleSheet }
+export { css, withStyles, ThemedStyleSheet }
From a450502a0d44184ae06c48be68d86ef1163c33ad Mon Sep 17 00:00:00 2001
From: Jerome Fitzgerald
Date: Sat, 4 Nov 2017 06:24:16 -0400
Subject: [PATCH 016/163] [fix] with-apollo: Cannot read property 'data'
(#3226)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* [fix] with-apollo: Cannot read property 'data'
When we create the initial serverState, we need to create the
eventual construct of the Apollo Data to reside within
Later in the constructor this allows for the initApollo to either
be generated from SSR, or to init from scratch.
Fixes
> Cannot read property 'data' of undefined
> TypeError: Cannot read property 'data' of undefined
* [refactor] with-apollo: reduce init `serverState`
No need to explicitly set `data` as empty.
This trims up 4 lines. 😀️
---
examples/with-apollo/lib/withData.js | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/examples/with-apollo/lib/withData.js b/examples/with-apollo/lib/withData.js
index 10954497d57f..65aa9fba7c37 100644
--- a/examples/with-apollo/lib/withData.js
+++ b/examples/with-apollo/lib/withData.js
@@ -17,7 +17,8 @@ export default ComposedComponent => {
}
static async getInitialProps (ctx) {
- let serverState = {}
+ // Initial serverState with apollo (empty)
+ let serverState = { apollo: { } }
// Evaluate the composed component's getInitialProps()
let composedInitialProps = {}
From 31ba48ada29e5910db7537bb62c2b5975ee4c0ff Mon Sep 17 00:00:00 2001
From: Bu Kinoshita
Date: Sat, 4 Nov 2017 10:04:26 -0400
Subject: [PATCH 017/163] Upgrade styled-jsx to version 2.1.2 (#3231)
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 77c0cb6581f8..6247db69737b 100644
--- a/package.json
+++ b/package.json
@@ -91,7 +91,7 @@
"send": "0.16.1",
"source-map-support": "0.4.18",
"strip-ansi": "4.0.0",
- "styled-jsx": "2.1.1",
+ "styled-jsx": "2.1.2",
"touch": "3.1.0",
"unfetch": "3.0.0",
"url": "0.11.0",
From b41d177609d3211278ac1ae6a059fbfbc47951ee Mon Sep 17 00:00:00 2001
From: Leonardo Quixada
Date: Sat, 4 Nov 2017 12:05:16 -0200
Subject: [PATCH 018/163] Dropped isomorphic-fetch in examples in favor of
isomorphic-unfetch. (#3230)
---
examples/data-fetch/package.json | 2 +-
examples/data-fetch/pages/index.js | 2 +-
examples/data-fetch/pages/preact.js | 2 +-
examples/with-apollo-and-redux/lib/initApollo.js | 2 +-
examples/with-apollo-and-redux/package.json | 2 +-
examples/with-apollo-auth/lib/init-apollo.js | 2 +-
examples/with-apollo-auth/package.json | 2 +-
examples/with-apollo/lib/initApollo.js | 2 +-
examples/with-apollo/package.json | 2 +-
examples/with-firebase-authentication/package.json | 2 +-
examples/with-firebase-authentication/pages/index.js | 2 +-
examples/with-freactal/githubApi.js | 2 +-
examples/with-freactal/package.json | 2 +-
examples/with-i18next/package.json | 2 +-
examples/with-i18next/tools/translationHelpers.js | 2 +-
examples/with-redux-saga/package.json | 2 +-
examples/with-redux-saga/saga.js | 2 +-
examples/with-relay-modern/lib/createRelayEnvironment.js | 2 +-
examples/with-relay-modern/package.json | 2 +-
examples/with-socket.io/package.json | 2 +-
examples/with-socket.io/pages/index.js | 2 +-
examples/with-static-export/next.config.js | 2 +-
examples/with-static-export/package.json | 2 +-
examples/with-static-export/pages/index.js | 2 +-
examples/with-static-export/pages/post.js | 2 +-
readme.md | 2 +-
26 files changed, 26 insertions(+), 26 deletions(-)
diff --git a/examples/data-fetch/package.json b/examples/data-fetch/package.json
index 1cfc9e390728..2c4ab668eed9 100644
--- a/examples/data-fetch/package.json
+++ b/examples/data-fetch/package.json
@@ -7,7 +7,7 @@
"start": "next start"
},
"dependencies": {
- "isomorphic-fetch": "^2.2.1",
+ "isomorphic-unfetch": "^2.0.0",
"next": "latest",
"react": "^16.0.0",
"react-dom": "^16.0.0"
diff --git a/examples/data-fetch/pages/index.js b/examples/data-fetch/pages/index.js
index b78fc0315644..3c8eb4d38392 100644
--- a/examples/data-fetch/pages/index.js
+++ b/examples/data-fetch/pages/index.js
@@ -1,7 +1,7 @@
import React from 'react'
import Link from 'next/link'
-import 'isomorphic-fetch'
+import 'isomorphic-unfetch'
export default class MyPage extends React.Component {
static async getInitialProps () {
diff --git a/examples/data-fetch/pages/preact.js b/examples/data-fetch/pages/preact.js
index 439514cfdb95..dc3455ef8a43 100644
--- a/examples/data-fetch/pages/preact.js
+++ b/examples/data-fetch/pages/preact.js
@@ -1,7 +1,7 @@
import React from 'react'
import Link from 'next/link'
-import 'isomorphic-fetch'
+import 'isomorphic-unfetch'
export default class MyPage extends React.Component {
static async getInitialProps () {
diff --git a/examples/with-apollo-and-redux/lib/initApollo.js b/examples/with-apollo-and-redux/lib/initApollo.js
index d7f8c1991b42..eab7a6acb68b 100644
--- a/examples/with-apollo-and-redux/lib/initApollo.js
+++ b/examples/with-apollo-and-redux/lib/initApollo.js
@@ -1,5 +1,5 @@
import { ApolloClient, createNetworkInterface } from 'react-apollo'
-import fetch from 'isomorphic-fetch'
+import fetch from 'isomorphic-unfetch'
let apolloClient = null
diff --git a/examples/with-apollo-and-redux/package.json b/examples/with-apollo-and-redux/package.json
index 97e945237b3d..b95393470d09 100644
--- a/examples/with-apollo-and-redux/package.json
+++ b/examples/with-apollo-and-redux/package.json
@@ -8,7 +8,7 @@
},
"dependencies": {
"graphql": "^0.9.3",
- "isomorphic-fetch": "^2.2.1",
+ "isomorphic-unfetch": "^2.0.0",
"next": "latest",
"prop-types": "^15.5.8",
"react": "^16.0.0",
diff --git a/examples/with-apollo-auth/lib/init-apollo.js b/examples/with-apollo-auth/lib/init-apollo.js
index 700020342b1b..77fcff8bce48 100644
--- a/examples/with-apollo-auth/lib/init-apollo.js
+++ b/examples/with-apollo-auth/lib/init-apollo.js
@@ -1,5 +1,5 @@
import { ApolloClient, createNetworkInterface } from 'react-apollo'
-import fetch from 'isomorphic-fetch'
+import fetch from 'isomorphic-unfetch'
let apolloClient = null
diff --git a/examples/with-apollo-auth/package.json b/examples/with-apollo-auth/package.json
index c03fedca90e3..423f13e0ac6e 100644
--- a/examples/with-apollo-auth/package.json
+++ b/examples/with-apollo-auth/package.json
@@ -12,7 +12,7 @@
"dependencies": {
"cookie": "^0.3.1",
"graphql": "^0.9.3",
- "isomorphic-fetch": "^2.2.1",
+ "isomorphic-unfetch": "^2.0.0",
"next": "latest",
"prop-types": "^15.5.10",
"react": "^15.5.4",
diff --git a/examples/with-apollo/lib/initApollo.js b/examples/with-apollo/lib/initApollo.js
index 5b315f92bd0c..b5d7861e82d4 100644
--- a/examples/with-apollo/lib/initApollo.js
+++ b/examples/with-apollo/lib/initApollo.js
@@ -1,7 +1,7 @@
import { ApolloClient } from 'apollo-client'
import { HttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
-import fetch from 'isomorphic-fetch'
+import fetch from 'isomorphic-unfetch'
let apolloClient = null
diff --git a/examples/with-apollo/package.json b/examples/with-apollo/package.json
index 2e3bdbe127ef..0aa1a1100f18 100644
--- a/examples/with-apollo/package.json
+++ b/examples/with-apollo/package.json
@@ -11,7 +11,7 @@
"graphql": "^0.11.7",
"graphql-anywhere": "^3.1.0",
"graphql-tag": "^2.5.0",
- "isomorphic-fetch": "^2.2.1",
+ "isomorphic-unfetch": "^2.0.0",
"next": "latest",
"prop-types": "^15.5.8",
"react": "^16.0.0",
diff --git a/examples/with-firebase-authentication/package.json b/examples/with-firebase-authentication/package.json
index 81a9a979670e..e2e632a34b6a 100644
--- a/examples/with-firebase-authentication/package.json
+++ b/examples/with-firebase-authentication/package.json
@@ -12,7 +12,7 @@
"express-session": "^1.15.2",
"firebase": "^3.7.5",
"firebase-admin": "^4.2.0",
- "isomorphic-fetch": "2.2.1",
+ "isomorphic-unfetch": "2.0.0",
"next": "latest",
"react": "^16.0.0",
"react-dom": "^16.0.0",
diff --git a/examples/with-firebase-authentication/pages/index.js b/examples/with-firebase-authentication/pages/index.js
index 7d26d1ae7f01..fc4975aa95ed 100644
--- a/examples/with-firebase-authentication/pages/index.js
+++ b/examples/with-firebase-authentication/pages/index.js
@@ -1,6 +1,6 @@
import React, { Component } from 'react'
import firebase from 'firebase'
-import 'isomorphic-fetch'
+import 'isomorphic-unfetch'
import clientCredentials from '../credentials/client'
export default class Index extends Component {
diff --git a/examples/with-freactal/githubApi.js b/examples/with-freactal/githubApi.js
index 516740bf57c0..df8412fcf47a 100644
--- a/examples/with-freactal/githubApi.js
+++ b/examples/with-freactal/githubApi.js
@@ -1,5 +1,5 @@
/* global fetch */
-import 'isomorphic-fetch'
+import 'isomorphic-unfetch'
const API_BASE_URL = 'https://api.github.com'
diff --git a/examples/with-freactal/package.json b/examples/with-freactal/package.json
index e280744809b0..4ed9c27412fc 100644
--- a/examples/with-freactal/package.json
+++ b/examples/with-freactal/package.json
@@ -8,7 +8,7 @@
},
"dependencies": {
"freactal": "^1.1.1",
- "isomorphic-fetch": "^2.2.1",
+ "isomorphic-unfetch": "^2.0.0",
"next": "latest",
"react": "^16.0.0",
"react-dom": "^16.0.0"
diff --git a/examples/with-i18next/package.json b/examples/with-i18next/package.json
index fef7b33ef7d5..96337414e72f 100644
--- a/examples/with-i18next/package.json
+++ b/examples/with-i18next/package.json
@@ -8,7 +8,7 @@
},
"dependencies": {
"i18next": "^7.1.3",
- "isomorphic-fetch": "^2.2.1",
+ "isomorphic-unfetch": "^2.0.0",
"next": "latest",
"react": "^16.0.0",
"react-dom": "^16.0.0",
diff --git a/examples/with-i18next/tools/translationHelpers.js b/examples/with-i18next/tools/translationHelpers.js
index cdadf0b336ac..52c0870fadb1 100644
--- a/examples/with-i18next/tools/translationHelpers.js
+++ b/examples/with-i18next/tools/translationHelpers.js
@@ -1,5 +1,5 @@
/* global fetch */
-import 'isomorphic-fetch'
+import 'isomorphic-unfetch'
/**
* Fetch translation file(s).
diff --git a/examples/with-redux-saga/package.json b/examples/with-redux-saga/package.json
index 0414ddf4e183..223463939c7e 100644
--- a/examples/with-redux-saga/package.json
+++ b/examples/with-redux-saga/package.json
@@ -9,7 +9,7 @@
},
"dependencies": {
"es6-promise": "4.1.1",
- "isomorphic-fetch": "2.2.1",
+ "isomorphic-unfetch": "2.0.0",
"next": "latest",
"next-redux-saga": "1.0.1",
"next-redux-wrapper": "1.2.0",
diff --git a/examples/with-redux-saga/saga.js b/examples/with-redux-saga/saga.js
index f9f8089271b9..b917c3affcc3 100644
--- a/examples/with-redux-saga/saga.js
+++ b/examples/with-redux-saga/saga.js
@@ -3,7 +3,7 @@
import {delay} from 'redux-saga'
import {all, call, put, take, takeLatest} from 'redux-saga/effects'
import es6promise from 'es6-promise'
-import 'isomorphic-fetch'
+import 'isomorphic-unfetch'
import {actionTypes, failure, loadDataSuccess, tickClock} from './actions'
diff --git a/examples/with-relay-modern/lib/createRelayEnvironment.js b/examples/with-relay-modern/lib/createRelayEnvironment.js
index ce93bd2d3992..c1da6aa5bfcb 100644
--- a/examples/with-relay-modern/lib/createRelayEnvironment.js
+++ b/examples/with-relay-modern/lib/createRelayEnvironment.js
@@ -1,5 +1,5 @@
import { Environment, Network, RecordSource, Store } from 'relay-runtime'
-import fetch from 'isomorphic-fetch'
+import fetch from 'isomorphic-unfetch'
let relayEnvironment = null
diff --git a/examples/with-relay-modern/package.json b/examples/with-relay-modern/package.json
index 06ff36b901f0..d1420feaf77a 100644
--- a/examples/with-relay-modern/package.json
+++ b/examples/with-relay-modern/package.json
@@ -15,7 +15,7 @@
"dependencies": {
"dotenv": "^4.0.0",
"dotenv-webpack": "^1.5.4",
- "isomorphic-fetch": "^2.2.1",
+ "isomorphic-unfetch": "^2.0.0",
"next": "^3.0.3",
"react": "^15.6.1",
"react-dom": "^15.6.1",
diff --git a/examples/with-socket.io/package.json b/examples/with-socket.io/package.json
index 958ec79ffe67..0aa86fe4a56c 100644
--- a/examples/with-socket.io/package.json
+++ b/examples/with-socket.io/package.json
@@ -3,7 +3,7 @@
"version": "1.0.0",
"dependencies": {
"express": "^4.15.2",
- "isomorphic-fetch": "^2.2.1",
+ "isomorphic-unfetch": "^2.0.0",
"next": "latest",
"react": "^16.0.0",
"react-dom": "^16.0.0",
diff --git a/examples/with-socket.io/pages/index.js b/examples/with-socket.io/pages/index.js
index 80251f54c986..acfcdd795a45 100644
--- a/examples/with-socket.io/pages/index.js
+++ b/examples/with-socket.io/pages/index.js
@@ -1,6 +1,6 @@
import { Component } from 'react'
import io from 'socket.io-client'
-import fetch from 'isomorphic-fetch'
+import fetch from 'isomorphic-unfetch'
class HomePage extends Component {
// fetch old messages data from the server
diff --git a/examples/with-static-export/next.config.js b/examples/with-static-export/next.config.js
index b4768999ff58..ab0ac1cf2a87 100644
--- a/examples/with-static-export/next.config.js
+++ b/examples/with-static-export/next.config.js
@@ -1,4 +1,4 @@
-const fetch = require('isomorphic-fetch')
+const fetch = require('isomorphic-unfetch')
module.exports = {
async exportPathMap () {
diff --git a/examples/with-static-export/package.json b/examples/with-static-export/package.json
index e7f4ec6c396c..56ef1e9efb2b 100644
--- a/examples/with-static-export/package.json
+++ b/examples/with-static-export/package.json
@@ -2,7 +2,7 @@
"main": "server.js",
"dependencies": {
"express": "^4.15.3",
- "isomorphic-fetch": "^2.2.1",
+ "isomorphic-unfetch": "^2.0.0",
"next": "beta",
"react": "^15.5.4",
"react-dom": "^15.5.4",
diff --git a/examples/with-static-export/pages/index.js b/examples/with-static-export/pages/index.js
index 5f2af5740b9f..800e7d9add3d 100644
--- a/examples/with-static-export/pages/index.js
+++ b/examples/with-static-export/pages/index.js
@@ -1,6 +1,6 @@
import { Component } from 'react'
import Head from 'next/head'
-import fetch from 'isomorphic-fetch'
+import fetch from 'isomorphic-unfetch'
import Post from '../components/post'
diff --git a/examples/with-static-export/pages/post.js b/examples/with-static-export/pages/post.js
index fde37ba8fb7a..72ec1ccb8df8 100644
--- a/examples/with-static-export/pages/post.js
+++ b/examples/with-static-export/pages/post.js
@@ -1,7 +1,7 @@
import { Component } from 'react'
import Link from 'next/link'
import Head from 'next/head'
-import fetch from 'isomorphic-fetch'
+import fetch from 'isomorphic-unfetch'
export default class extends Component {
static async getInitialProps ({ query }) {
diff --git a/readme.md b/readme.md
index 520d07854798..a827f46fc96d 100644
--- a/readme.md
+++ b/readme.md
@@ -893,7 +893,7 @@ If you want to render the built-in error page you can by using `next/error`:
```jsx
import React from 'react'
import Error from 'next/error'
-import fetch from 'isomorphic-fetch'
+import fetch from 'isomorphic-unfetch'
export default class Page extends React.Component {
static async getInitialProps() {
From a35e747e24dd43687ab6e6a8efaf684298135638 Mon Sep 17 00:00:00 2001
From: Leandro Ardissone
Date: Sat, 4 Nov 2017 11:06:16 -0300
Subject: [PATCH 019/163] Added Sentry.io example (#3215)
* Added Sentry example
* Code style fixes
* Fixes docs + removed demo DSN + send error to comp
---
examples/with-sentry/README.md | 33 +++++++++++++++++
examples/with-sentry/components/withSentry.js | 35 +++++++++++++++++++
examples/with-sentry/package.json | 16 +++++++++
examples/with-sentry/pages/index.js | 25 +++++++++++++
4 files changed, 109 insertions(+)
create mode 100644 examples/with-sentry/README.md
create mode 100644 examples/with-sentry/components/withSentry.js
create mode 100644 examples/with-sentry/package.json
create mode 100644 examples/with-sentry/pages/index.js
diff --git a/examples/with-sentry/README.md b/examples/with-sentry/README.md
new file mode 100644
index 000000000000..7d15975cb743
--- /dev/null
+++ b/examples/with-sentry/README.md
@@ -0,0 +1,33 @@
+[![Deploy to now](https://deploy.now.sh/static/button.svg)](https://deploy.now.sh/?repo=https://github.com/zeit/next.js/tree/master/examples/with-sentry)
+
+# Sentry example
+
+## How to use
+
+Download the example [or clone the repo](https://github.com/zeit/next.js):
+
+Install it and run:
+
+**npm**
+```bash
+npm install
+npm run dev
+```
+
+**yarn**
+```bash
+npm install
+npm run dev
+```
+
+Deploy it to the cloud with [now](https://zeit.co/now) ([download](https://zeit.co/download))
+
+```bash
+now
+```
+
+## About example
+
+This example show you how to add Sentry to catch errors in next.js
+
+You will need a Sentry DSN for your project. You can get it from the Settings of your Project, in **Client Keys (DSN)**, and copy the string labeled **DSN (Public)**.
\ No newline at end of file
diff --git a/examples/with-sentry/components/withSentry.js b/examples/with-sentry/components/withSentry.js
new file mode 100644
index 000000000000..4ffdb78d3cd7
--- /dev/null
+++ b/examples/with-sentry/components/withSentry.js
@@ -0,0 +1,35 @@
+import React from 'react'
+import Raven from 'raven-js'
+
+const SENTRY_DSN = ''
+
+function withSentry (Child) {
+ return class WrappedComponent extends React.Component {
+ static getInitialProps (context) {
+ if (Child.getInitialProps) {
+ return Child.getInitialProps(context)
+ }
+ return {}
+ }
+ constructor (props) {
+ super(props)
+ this.state = {
+ error: null
+ }
+ Raven.config(
+ SENTRY_DSN
+ ).install()
+ }
+
+ componentDidCatch (error, errorInfo) {
+ this.setState({ error })
+ Raven.captureException(error, { extra: errorInfo })
+ }
+
+ render () {
+ return
+ }
+ }
+}
+
+export default withSentry
diff --git a/examples/with-sentry/package.json b/examples/with-sentry/package.json
new file mode 100644
index 000000000000..58f674561f8e
--- /dev/null
+++ b/examples/with-sentry/package.json
@@ -0,0 +1,16 @@
+{
+ "name": "with-sentry",
+ "version": "1.0.0",
+ "scripts": {
+ "dev": "next",
+ "build": "next build",
+ "start": "next start"
+ },
+ "dependencies": {
+ "next": "latest",
+ "raven-js": "^3.19.1",
+ "react": "^16.0.0",
+ "react-dom": "^16.0.0"
+ },
+ "license": "ISC"
+}
diff --git a/examples/with-sentry/pages/index.js b/examples/with-sentry/pages/index.js
new file mode 100644
index 000000000000..ef09c0180fc3
--- /dev/null
+++ b/examples/with-sentry/pages/index.js
@@ -0,0 +1,25 @@
+import React from 'react'
+import withSentry from '../components/withSentry'
+
+class Index extends React.Component {
+ static getInitialProps (context) {
+ const { isServer } = context
+ return { isServer }
+ }
+
+ onClickHandler () {
+ throw new Error('woops')
+ }
+
+ render () {
+ return (
+
+
Index page
+
+
+
+ )
+ }
+}
+
+export default withSentry(Index)
From e1d9ae27f048c44b108cd9c9691a98590abe0e93 Mon Sep 17 00:00:00 2001
From: Juan Gallo
Date: Sun, 5 Nov 2017 13:20:24 -0300
Subject: [PATCH 020/163] only-client-render-external-dependencies example
(#3229)
---
.../README.md | 27 +++++++++++
.../package.json | 16 +++++++
.../pages/chart.js | 44 +++++++++++++++++
.../pages/index.js | 47 +++++++++++++++++++
4 files changed, 134 insertions(+)
create mode 100644 examples/only-client-render-external-dependencies/README.md
create mode 100644 examples/only-client-render-external-dependencies/package.json
create mode 100644 examples/only-client-render-external-dependencies/pages/chart.js
create mode 100644 examples/only-client-render-external-dependencies/pages/index.js
diff --git a/examples/only-client-render-external-dependencies/README.md b/examples/only-client-render-external-dependencies/README.md
new file mode 100644
index 000000000000..2530b5890b26
--- /dev/null
+++ b/examples/only-client-render-external-dependencies/README.md
@@ -0,0 +1,27 @@
+# Hello World example
+
+## Only client render for external dependencies
+
+Download the example [or clone the repo](https://github.com/zeit/next.js):
+
+```bash
+curl https://codeload.github.com/zeit/next.js/tar.gz/master | tar -xz --strip=2 next.js-master/examples/only-client-render-external-dependencies
+cd only-client-render-external-dependencies
+```
+
+Install it and run:
+
+```bash
+npm install
+npm run dev
+```
+
+Deploy it to the cloud with [now](https://zeit.co/now) ([download](https://zeit.co/download))
+
+```bash
+now
+```
+
+## The idea behind the example
+
+This example shows how to use an external dependency that only allows client-render.
\ No newline at end of file
diff --git a/examples/only-client-render-external-dependencies/package.json b/examples/only-client-render-external-dependencies/package.json
new file mode 100644
index 000000000000..267515f1f70b
--- /dev/null
+++ b/examples/only-client-render-external-dependencies/package.json
@@ -0,0 +1,16 @@
+{
+ "name": "only-client-render-external-dependencies",
+ "version": "1.0.0",
+ "scripts": {
+ "dev": "next",
+ "build": "next build",
+ "start": "next start"
+ },
+ "dependencies": {
+ "next": "latest",
+ "react": "^16.0.0",
+ "react-dom": "^16.0.0",
+ "recharts": "^1.0.0-beta.0"
+ },
+ "license": "ISC"
+}
diff --git a/examples/only-client-render-external-dependencies/pages/chart.js b/examples/only-client-render-external-dependencies/pages/chart.js
new file mode 100644
index 000000000000..296ef9b003af
--- /dev/null
+++ b/examples/only-client-render-external-dependencies/pages/chart.js
@@ -0,0 +1,44 @@
+import React from 'react'
+let LineChart
+let Line
+class Chart extends React.Component {
+ constructor () {
+ super();
+ this.state = {
+ chart: false,
+ data: [
+ {name: 'Page A', uv: 4000, pv: 2400, amt: 2400},
+ {name: 'Page B', uv: 3000, pv: 1398, amt: 2210},
+ {name: 'Page C', uv: 2000, pv: 9800, amt: 2290},
+ {name: 'Page D', uv: 2780, pv: 3908, amt: 2000},
+ {name: 'Page E', uv: 1890, pv: 4800, amt: 2181},
+ {name: 'Page F', uv: 2390, pv: 3800, amt: 2500},
+ {name: 'Page G', uv: 3490, pv: 4300, amt: 2100},
+ ]
+ }
+ }
+
+ componentDidMount() {
+ LineChart = require('recharts').LineChart;
+ Line = require('recharts').Line;
+
+ this.setState({
+ chart: true
+ })
+ }
+
+ render () {
+ return (
+
)
diff --git a/examples/custom-server-express/pages/posts.js b/examples/custom-server-express/pages/posts.js
new file mode 100644
index 000000000000..c88605635eb3
--- /dev/null
+++ b/examples/custom-server-express/pages/posts.js
@@ -0,0 +1,17 @@
+import React, { Component } from 'react'
+
+export default class extends Component {
+ static getInitialProps ({ query: { id } }) {
+ return { postId: id }
+ }
+
+ render () {
+ return
+
My blog post #{this.props.postId}
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ tempor incididunt ut labore et dolore magna aliqua.
+
+
+ }
+}
diff --git a/examples/custom-server-express/server.js b/examples/custom-server-express/server.js
index 098eb4f353bb..208bfe97fd8c 100644
--- a/examples/custom-server-express/server.js
+++ b/examples/custom-server-express/server.js
@@ -18,6 +18,10 @@ app.prepare()
return app.render(req, res, '/a', req.query)
})
+ server.get('/posts/:id', (req, res) => {
+ return app.render(req, res, '/posts', { id: req.params.id })
+ })
+
server.get('*', (req, res) => {
return handle(req, res)
})
From c0581a40ccb149d1ddfbf09ee94dfc2b38746c2b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nghi=E1=BB=87p?=
Date: Wed, 15 Nov 2017 15:55:41 +0700
Subject: [PATCH 034/163] Update README.md for with-shallow-routing example
(#3285)
---
examples/with-shallow-routing/README.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/examples/with-shallow-routing/README.md b/examples/with-shallow-routing/README.md
index 328ac3e8f0ae..05abbd31747a 100644
--- a/examples/with-shallow-routing/README.md
+++ b/examples/with-shallow-routing/README.md
@@ -7,8 +7,8 @@
Download the example [or clone the repo](https://github.com/zeit/next.js):
```bash
-curl https://codeload.github.com/zeit/next.js/tar.gz/master | tar -xz --strip=2 next.js-master/examples/hello-world
-cd hello-world
+curl https://codeload.github.com/zeit/next.js/tar.gz/master | tar -xz --strip=2 next.js-master/examples/with-shallow-routing
+cd with-shallow-routing
```
Install it and run:
@@ -28,4 +28,4 @@ now
With shallow routing, we could change the URL without actually running the `getInitialProps` every time you change the URL.
-We do this passing the `shallow: true` option to `Router.push` or `Router.replace`.
\ No newline at end of file
+We do this passing the `shallow: true` option to `Router.push` or `Router.replace`.
From 636c428a052a3833d6d543b6ff4f1fc55f4406c4 Mon Sep 17 00:00:00 2001
From: Elliot Hesp
Date: Wed, 15 Nov 2017 09:35:30 +0000
Subject: [PATCH 035/163] Update deprecated firebase method (#3277)
getToken is now deprecated, you'll get the following message if using the previous code:
firebase.User.prototype.getToken is deprecated. Please use firebase.User.prototype.getIdToken instead.
---
examples/with-firebase-authentication/pages/index.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/examples/with-firebase-authentication/pages/index.js b/examples/with-firebase-authentication/pages/index.js
index fc4975aa95ed..849736dac977 100644
--- a/examples/with-firebase-authentication/pages/index.js
+++ b/examples/with-firebase-authentication/pages/index.js
@@ -33,7 +33,7 @@ export default class Index extends Component {
firebase.auth().onAuthStateChanged(user => {
if (user) {
this.setState({ user: user })
- return user.getToken()
+ return user.getIdToken()
.then((token) => {
// eslint-disable-next-line no-undef
return fetch('/api/login', {
From 03aae1f9fc843927cc4ba2dbe13537304506a36a Mon Sep 17 00:00:00 2001
From: Tim Neutkens
Date: Wed, 15 Nov 2017 13:22:41 +0100
Subject: [PATCH 036/163] Release 4.2.0-canary.1
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 44446eea404e..97fa2b331f56 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "next",
- "version": "4.1.4-canary.2",
+ "version": "4.2.0-canary.1",
"description": "Minimalistic framework for server-rendered React applications",
"main": "./dist/server/next.js",
"license": "MIT",
From 7c9d3500912e009e9f635cc2f31fb149d62d51ad Mon Sep 17 00:00:00 2001
From: "Anders D. Johnson"
Date: Wed, 15 Nov 2017 22:35:42 -0600
Subject: [PATCH 037/163] docs(readme): add missing period (#3295)
---
readme.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/readme.md b/readme.md
index c6ae6f2652f4..25d41160eee1 100644
--- a/readme.md
+++ b/readme.md
@@ -162,7 +162,7 @@ It's possible to use any existing CSS-in-JS solution. The simplest one is inline
export default () =>
hi there
```
-To use more sophisticated CSS-in-JS solutions, you typically have to implement style flushing for server-side rendering. We enable this by allowing you to define your own [custom ``](#user-content-custom-document) component that wraps each page
+To use more sophisticated CSS-in-JS solutions, you typically have to implement style flushing for server-side rendering. We enable this by allowing you to define your own [custom ``](#user-content-custom-document) component that wraps each page.
### Static file serving (e.g.: images)
From abe0aebcc0e5308f92086c30a8dc6942da4de064 Mon Sep 17 00:00:00 2001
From: Thomas Vogel
Date: Thu, 16 Nov 2017 11:18:25 +0100
Subject: [PATCH 038/163] updated with-apollo example to update option API
(#3296)
---
examples/with-apollo/components/PostList.js | 11 ++++++-----
examples/with-apollo/components/Submit.js | 12 ++++--------
2 files changed, 10 insertions(+), 13 deletions(-)
diff --git a/examples/with-apollo/components/PostList.js b/examples/with-apollo/components/PostList.js
index ecd59292ed36..8d939ae9a369 100644
--- a/examples/with-apollo/components/PostList.js
+++ b/examples/with-apollo/components/PostList.js
@@ -67,7 +67,7 @@ function PostList ({ data: { loading, error, allPosts, _allPostsMeta }, loadMore
return
Loading
}
-const allPosts = gql`
+export const allPosts = gql`
query allPosts($first: Int!, $skip: Int!) {
allPosts(orderBy: createdAt_DESC, first: $first, skip: $skip) {
id
@@ -81,15 +81,16 @@ const allPosts = gql`
}
}
`
+export const allPostsQueryVars = {
+ skip: 0,
+ first: POSTS_PER_PAGE
+}
// The `graphql` wrapper executes a GraphQL query and makes the results
// available on the `data` prop of the wrapped component (PostList)
export default graphql(allPosts, {
options: {
- variables: {
- skip: 0,
- first: POSTS_PER_PAGE
- }
+ variables: allPostsQueryVars
},
props: ({ data }) => ({
data,
diff --git a/examples/with-apollo/components/Submit.js b/examples/with-apollo/components/Submit.js
index 792d3b5db059..527ff33cdc92 100644
--- a/examples/with-apollo/components/Submit.js
+++ b/examples/with-apollo/components/Submit.js
@@ -1,5 +1,6 @@
import { graphql } from 'react-apollo'
import gql from 'graphql-tag'
+import {allPosts, allPostsQueryVars} from './PostList'
function Submit ({ createPost }) {
function handleSubmit (e) {
@@ -65,14 +66,9 @@ export default graphql(createPost, {
props: ({ mutate }) => ({
createPost: (title, url) => mutate({
variables: { title, url },
- updateQueries: {
- allPosts: (previousResult, { mutationResult }) => {
- const newPost = mutationResult.data.createPost
- return Object.assign({}, previousResult, {
- // Append the new post
- allPosts: [newPost, ...previousResult.allPosts]
- })
- }
+ update: (proxy, { data: { createPost } }) => {
+ const data = proxy.readQuery({ query: allPosts, variables: allPostsQueryVars })
+ proxy.writeQuery({ query: allPosts, data: {allPosts: [createPost, ...data.allPosts]}, variables: allPostsQueryVars })
}
})
})
From c6d9ab7563eb7e876521e1f2e1f0c5a006cf8467 Mon Sep 17 00:00:00 2001
From: "Tage A. L. K"
Date: Fri, 17 Nov 2017 08:23:52 +0100
Subject: [PATCH 039/163] with-apollo-auth updated for Apollo 2.0 (#3278)
* Updated for Apollo 2.0
* Updated for commit: ccb188a
* Simplified serverState
Updated with danistefanovic's comment. Looks better.
* Revert "Simplified serverState"
This reverts commit 1b543a35909dcfe401c753cb2f71760180087057.
* Simplified server
Updated with Statedanistefanovic's comment.
---
examples/with-apollo-auth/lib/initApollo.js | 32 ++++++-----
examples/with-apollo-auth/lib/withData.js | 61 +++++++++++----------
examples/with-apollo-auth/package.json | 6 +-
3 files changed, 54 insertions(+), 45 deletions(-)
diff --git a/examples/with-apollo-auth/lib/initApollo.js b/examples/with-apollo-auth/lib/initApollo.js
index 77fcff8bce48..05f39f3df469 100644
--- a/examples/with-apollo-auth/lib/initApollo.js
+++ b/examples/with-apollo-auth/lib/initApollo.js
@@ -1,4 +1,7 @@
-import { ApolloClient, createNetworkInterface } from 'react-apollo'
+import { ApolloClient } from 'apollo-client'
+import { createHttpLink } from 'apollo-link-http'
+import { InMemoryCache } from 'apollo-cache-inmemory'
+import { setContext } from 'apollo-link-context'
import fetch from 'isomorphic-unfetch'
let apolloClient = null
@@ -9,25 +12,26 @@ if (!process.browser) {
}
function create (initialState, { getToken }) {
- const networkInterface = createNetworkInterface({
- uri: 'https://api.graph.cool/simple/v1/cj3h80ffbllm20162alevpcby'
+ const httpLink = createHttpLink({
+ uri: 'https://api.graph.cool/simple/v1/cj5geu3slxl7t0127y8sity9r',
+ credentials: 'same-origin'
})
- networkInterface.use([{
- applyMiddleware (req, next) {
- if (!req.options.headers) {
- req.options.headers = {} // Create the header object if needed.
+ const authLink = setContext((_, { headers }) => {
+ const token = getToken()
+ return {
+ headers: {
+ ...headers,
+ authorization: token ? `Bearer ${token}` : null
}
- const token = getToken()
- req.options.headers.authorization = token ? `Bearer ${token}` : null
- next()
}
- }])
+ })
return new ApolloClient({
- initialState,
+ connectToDevTools: process.browser,
ssrMode: !process.browser, // Disables forceFetch on the server (so queries are only run once)
- networkInterface
+ link: authLink.concat(httpLink),
+ cache: new InMemoryCache().restore(initialState || {})
})
}
@@ -44,4 +48,4 @@ export default function initApollo (initialState, options) {
}
return apolloClient
-}
+}
\ No newline at end of file
diff --git a/examples/with-apollo-auth/lib/withData.js b/examples/with-apollo-auth/lib/withData.js
index c12f2f4e2095..fcec71ba6bcc 100644
--- a/examples/with-apollo-auth/lib/withData.js
+++ b/examples/with-apollo-auth/lib/withData.js
@@ -2,13 +2,14 @@ import React from 'react'
import cookie from 'cookie'
import PropTypes from 'prop-types'
import { ApolloProvider, getDataFromTree } from 'react-apollo'
+import Head from 'next/head'
import initApollo from './initApollo'
-function parseCookies (ctx = {}, options = {}) {
+function parseCookies(context = {}, options = {}) {
return cookie.parse(
- ctx.req && ctx.req.headers.cookie
- ? ctx.req.headers.cookie
+ context.req && context.req.headers.cookie
+ ? context.req.headers.cookie
: document.cookie,
options
)
@@ -21,7 +22,7 @@ export default ComposedComponent => {
serverState: PropTypes.object.isRequired
}
- static async getInitialProps (context) {
+ static async getInitialProps(context) {
let serverState = {}
// Setup a server-side one-time-use apollo client for initial props and
@@ -46,30 +47,32 @@ export default ComposedComponent => {
}
// Provide the `url` prop data in case a graphql query uses it
- const url = {query: context.query, pathname: context.pathname}
-
- // Run all graphql queries
- const app = (
-
-
-
- )
- await getDataFromTree(app, {
- router: {
- query: context.query,
- pathname: context.pathname,
- asPath: context.asPath
- }
- })
+ const url = { query: context.query, pathname: context.pathname }
+ try {
+ // Run all GraphQL queries
+ const app = (
+
+
+
+ )
+ await getDataFromTree(app, {
+ router: {
+ query: context.query,
+ pathname: context.pathname,
+ asPath: context.asPath
+ }
+ })
+ } catch (error) {
+ // Prevent Apollo Client GraphQL errors from crashing SSR.
+ // Handle them in components via the data.error prop:
+ // http://dev.apollodata.com/react/api-queries.html#graphql-query-data-error
+ }
+ // getDataFromTree does not call componentWillUnmount
+ // head side effect therefore need to be cleared manually
+ Head.rewind()
// Extract query data from the Apollo's store
- const state = apollo.getInitialState()
-
- serverState = {
- apollo: { // Make sure to only include Apollo's data state
- data: state.data
- }
- }
+ serverState = apollo.cache.extract()
}
return {
@@ -78,7 +81,7 @@ export default ComposedComponent => {
}
}
- constructor (props) {
+ constructor(props) {
super(props)
// Note: Apollo should never be used on the server side beyond the initial
// render within `getInitialProps()` above (since the entire prop tree
@@ -89,7 +92,7 @@ export default ComposedComponent => {
})
}
- render () {
+ render() {
return (
@@ -97,4 +100,4 @@ export default ComposedComponent => {
)
}
}
-}
+}
\ No newline at end of file
diff --git a/examples/with-apollo-auth/package.json b/examples/with-apollo-auth/package.json
index 683f548b1751..c7a22a8e8fac 100644
--- a/examples/with-apollo-auth/package.json
+++ b/examples/with-apollo-auth/package.json
@@ -10,13 +10,15 @@
"test": "NODE_ENV=test ava"
},
"dependencies": {
+ "apollo-client-preset": "1.0.2",
+ "apollo-link-context": "1.0.0",
"cookie": "^0.3.1",
- "graphql": "^0.9.3",
+ "graphql": "0.11.7",
"isomorphic-unfetch": "^2.0.0",
"next": "latest",
"prop-types": "^15.5.10",
"react": "^16.0.0",
- "react-apollo": "^1.1.3",
+ "react-apollo": "2.0.0",
"react-dom": "^16.0.0"
},
"devDependencies": {
From 20af8cdabece57de21d9cbcdba7361a09bf66fbb Mon Sep 17 00:00:00 2001
From: Kenneth Auchenberg
Date: Mon, 20 Nov 2017 06:51:46 -0800
Subject: [PATCH 040/163] Add option to pass --inspect flag to enable
server-side debugging (#3294)
* Add option to pass --inspect flag
* Re-add shebang's
* Tweak spacing
* Use global 'node' when spawning process
---
bin/next | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/bin/next b/bin/next
index d79a0123716b..e189cad78339 100755
--- a/bin/next
+++ b/bin/next
@@ -27,13 +27,18 @@ const commands = new Set([
])
let cmd = process.argv[2]
-let args
+let args = []
+let nodeArgs = []
if (new Set(['--version', '-v']).has(cmd)) {
console.log(`next.js v${pkg.version}`)
process.exit(0)
}
+if (new Set(process.argv).has('--inspect')) {
+ nodeArgs.push('--inspect')
+}
+
if (new Set(['--help', '-h']).has(cmd)) {
console.log(`
Usage
@@ -61,7 +66,7 @@ process.env.NODE_ENV = process.env.NODE_ENV || defaultEnv
const bin = join(__dirname, 'next-' + cmd)
const startProcess = () => {
- const proc = spawn(bin, args, { stdio: 'inherit', customFds: [0, 1, 2] })
+ const proc = spawn('node', [...nodeArgs, ...[bin], ...args], { stdio: 'inherit', customFds: [0, 1, 2] })
proc.on('close', (code, signal) => {
if (code !== null) {
process.exit(code)
From f0eacf66eac95db0aea40d502e0d2f049d9be3c7 Mon Sep 17 00:00:00 2001
From: Max Scher
Date: Thu, 23 Nov 2017 04:46:33 -0800
Subject: [PATCH 041/163] Add data node to serverState declaration (#3321)
The serverState variable definition did not include the data node, which
may cause parsing errors on the client-side.
- add data: { } on line 23 within the apollo: { } object
---
examples/with-apollo/lib/withData.js | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/examples/with-apollo/lib/withData.js b/examples/with-apollo/lib/withData.js
index 65aa9fba7c37..396cb3106a12 100644
--- a/examples/with-apollo/lib/withData.js
+++ b/examples/with-apollo/lib/withData.js
@@ -18,7 +18,11 @@ export default ComposedComponent => {
static async getInitialProps (ctx) {
// Initial serverState with apollo (empty)
- let serverState = { apollo: { } }
+ let serverState = {
+ apollo: {
+ data: { }
+ }
+ }
// Evaluate the composed component's getInitialProps()
let composedInitialProps = {}
From fc335ac36c790eae7432f74417bc3c759008ff5e Mon Sep 17 00:00:00 2001
From: Lucas Rosa
Date: Thu, 23 Nov 2017 07:48:34 -0500
Subject: [PATCH 042/163] Add example with tailwind css (#3317)
* Add Tailwind css example
* Fix read me
* Add create-next-app setup to read me
---
examples/with-tailwindcss/README.md | 68 ++
examples/with-tailwindcss/components/head.js | 37 +
examples/with-tailwindcss/components/nav.js | 60 ++
examples/with-tailwindcss/package.json | 23 +
examples/with-tailwindcss/pages/_document.js | 26 +
examples/with-tailwindcss/pages/index.js | 13 +
examples/with-tailwindcss/styles/button.css | 3 +
.../styles/config/postcss.config.js | 10 +
.../styles/config/tailwind.config.js | 775 ++++++++++++++++++
examples/with-tailwindcss/styles/index.css | 55 ++
10 files changed, 1070 insertions(+)
create mode 100644 examples/with-tailwindcss/README.md
create mode 100644 examples/with-tailwindcss/components/head.js
create mode 100644 examples/with-tailwindcss/components/nav.js
create mode 100644 examples/with-tailwindcss/package.json
create mode 100644 examples/with-tailwindcss/pages/_document.js
create mode 100644 examples/with-tailwindcss/pages/index.js
create mode 100644 examples/with-tailwindcss/styles/button.css
create mode 100644 examples/with-tailwindcss/styles/config/postcss.config.js
create mode 100644 examples/with-tailwindcss/styles/config/tailwind.config.js
create mode 100644 examples/with-tailwindcss/styles/index.css
diff --git a/examples/with-tailwindcss/README.md b/examples/with-tailwindcss/README.md
new file mode 100644
index 000000000000..c20bc17066ec
--- /dev/null
+++ b/examples/with-tailwindcss/README.md
@@ -0,0 +1,68 @@
+[![Deploy to now](https://deploy.now.sh/static/button.svg)](https://deploy.now.sh/?repo=https://github.com/zeit/next.js/tree/master/examples/with-tailwindcss)
+
+# Tailwind CSS example
+
+This is an example of how you can include a global stylesheet in a next.js webapp.
+
+## How to use
+
+If you like [create-next-app](https://github.com/segmentio/create-next-app) and/or [yarn](https://yarnpkg.com/en/docs/cli/create) simply run:
+
+```bash
+yarn create next-app --example with-tailwindcss my-app
+cd my-app
+```
+
+*Otherwise:*
+
+Download the example [or clone the repo](https://github.com/zeit/next.js):
+
+```bash
+curl https://codeload.github.com/zeit/next.js/tar.gz/master | tar -xz --strip=2 next.js-master/examples/with-tailwindcss
+cd with-tailwindcss
+```
+
+**Running**
+
+To get this example running you just need to
+
+ yarn install .
+ yarn dev
+
+Visit [http://localhost:3000](http://localhost:3000) and try to modify `styles/index.css`.
+
+Deploy it to the cloud with [now](https://zeit.co/now) ([download](https://zeit.co/download))
+
+```bash
+now
+```
+
+### Extras
+
+In the `package.json` you'll see some extra commands.
+
+* `yarn dev:css`
+ * used by `yarn dev` generate css bundle and watch css files for changes
+ * includes css imported into `index.css`
+ * will **not** autoreload browser when css changes
+* `yarn build:css`
+ * used by `yarn build` to generate css bundle
+
+These can be used manually but using the usual commands will run them anyways.
+
+## The idea behind the example
+
+This setup is a basic starting point for using tailwind css and next. Along with tailwind, this example
+also uses some other postcss plugins for imports, autoprefixing, and stripping whitespace/comments. The imports simply
+allow for an easy way to split up css files but still get one bundled css file in `static/css/bundle.css`.
+Changing stylesheets does not trigger auto-reloads. Setting up auto-reloads was avoided
+because the next.js read me does not recommend doing so. Although, that can easily be done with
+some webpack loaders. If you are curious about using loaders with next look at this
+[example](https://github.com/zeit/next.js/tree/canary/examples/with-global-stylesheet).
+
+This project shows how you can set it up. Have a look at:
+* pages/_document.js
+* styles/config/postcss.config.js
+* styles/config/tailwind.config.js
+* styles/index.css
+* styles/button.css
diff --git a/examples/with-tailwindcss/components/head.js b/examples/with-tailwindcss/components/head.js
new file mode 100644
index 000000000000..aea67fa28742
--- /dev/null
+++ b/examples/with-tailwindcss/components/head.js
@@ -0,0 +1,37 @@
+import NextHead from 'next/head'
+import { string } from 'prop-types'
+
+const defaultDescription = ''
+const defaultOGURL = ''
+const defaultOGImage = ''
+
+const Head = (props) => (
+
+
+ {props.title || ''}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+)
+
+Head.propTypes = {
+ title: string,
+ description: string,
+ url: string,
+ ogImage: string
+}
+
+export default Head
diff --git a/examples/with-tailwindcss/components/nav.js b/examples/with-tailwindcss/components/nav.js
new file mode 100644
index 000000000000..d089475f8b08
--- /dev/null
+++ b/examples/with-tailwindcss/components/nav.js
@@ -0,0 +1,60 @@
+import Head from './head'
+import Link from 'next/link'
+
+const links = [
+ { href: 'https://github.com/segmentio/create-next-app', label: 'Github' }
+].map(link => {
+ link.key = `nav-link-${link.href}-${link.label}`
+ return link
+})
+
+const Nav = () => (
+
+)
+
+export default Nav
diff --git a/examples/with-tailwindcss/package.json b/examples/with-tailwindcss/package.json
new file mode 100644
index 000000000000..93d7d74b6a4d
--- /dev/null
+++ b/examples/with-tailwindcss/package.json
@@ -0,0 +1,23 @@
+{
+ "name": "with-tailwindcss",
+ "version": "1.0.0",
+ "scripts": {
+ "dev": "next & yarn dev:css",
+ "dev:css": "postcss styles/index.css --watch -c styles/config/postcss.config.js -o static/css/bundle.css",
+ "build": "next build & yarn build:css",
+ "build:css": "postcss styles/index.css -c styles/config/postcss.config.js -o static/css/bundle.css",
+ "start": "next start"
+ },
+ "dependencies": {
+ "next": "^4.1.3",
+ "react": "^16.0.0",
+ "react-dom": "^16.0.0"
+ },
+ "devDependencies": {
+ "autoprefixer": "^7.1.6",
+ "cssnano": "^3.10.0",
+ "postcss-cli": "^4.1.1",
+ "postcss-easy-import": "^3.0.0",
+ "tailwindcss": "^0.2.2"
+ }
+}
diff --git a/examples/with-tailwindcss/pages/_document.js b/examples/with-tailwindcss/pages/_document.js
new file mode 100644
index 000000000000..13150ab31426
--- /dev/null
+++ b/examples/with-tailwindcss/pages/_document.js
@@ -0,0 +1,26 @@
+import Document, { Head, Main, NextScript } from 'next/document'
+
+class MyDocument extends Document {
+ static getInitialProps({ renderPage }) {
+ const { html, head, errorHtml, chunks } = renderPage()
+
+ return { html, head, errorHtml, chunks }
+ }
+
+ render() {
+ return (
+
+
+
+
+
+ {this.props.customValue}
+
+
+
+
+ )
+ }
+}
+
+export default MyDocument;
diff --git a/examples/with-tailwindcss/pages/index.js b/examples/with-tailwindcss/pages/index.js
new file mode 100644
index 000000000000..9a488c3ade5c
--- /dev/null
+++ b/examples/with-tailwindcss/pages/index.js
@@ -0,0 +1,13 @@
+import Link from 'next/link'
+import Head from '../components/head'
+import Nav from '../components/nav'
+
+export default () => (
+
+
+
+
+
Next.js + Tailwind css
+
+
+)
diff --git a/examples/with-tailwindcss/styles/button.css b/examples/with-tailwindcss/styles/button.css
new file mode 100644
index 000000000000..33edf0bb0bd2
--- /dev/null
+++ b/examples/with-tailwindcss/styles/button.css
@@ -0,0 +1,3 @@
+.btn-blue {
+ @apply .bg-blue .text-white .font-bold .py-2 .px-4 .rounded;
+}
diff --git a/examples/with-tailwindcss/styles/config/postcss.config.js b/examples/with-tailwindcss/styles/config/postcss.config.js
new file mode 100644
index 000000000000..e5bffd93b10c
--- /dev/null
+++ b/examples/with-tailwindcss/styles/config/postcss.config.js
@@ -0,0 +1,10 @@
+var tailwindcss = require('tailwindcss');
+
+module.exports = {
+ plugins: [
+ require('postcss-easy-import'),
+ tailwindcss('./styles/config/tailwind.config.js'),
+ require('autoprefixer'),
+ require('cssnano'),
+ ]
+}
diff --git a/examples/with-tailwindcss/styles/config/tailwind.config.js b/examples/with-tailwindcss/styles/config/tailwind.config.js
new file mode 100644
index 000000000000..78ad7c5970a1
--- /dev/null
+++ b/examples/with-tailwindcss/styles/config/tailwind.config.js
@@ -0,0 +1,775 @@
+/*
+
+Tailwind - The Utility-First CSS Framework
+
+A project by Adam Wathan (@adamwathan), Jonathan Reinink (@reinink),
+David Hemphill (@davidhemphill) and Steve Schoger (@steveschoger).
+
+Welcome to the Tailwind config file. This is where you can customize
+Tailwind specifically for your project. Don't be intimidated by the
+length of this file. It's really just a big JavaScript object and
+we've done our very best to explain each section.
+
+View the full documentation at https://tailwindcss.com.
+
+
+|-------------------------------------------------------------------------------
+| The default config
+|-------------------------------------------------------------------------------
+|
+| This variable contains the default Tailwind config. You don't have
+| to use it, but it can sometimes be helpful to have available. For
+| example, you may choose to merge your custom configuration
+| values with some of the Tailwind defaults.
+|
+*/
+
+var defaultConfig = require('tailwindcss/defaultConfig')()
+
+
+/*
+|-------------------------------------------------------------------------------
+| Colors https://tailwindcss.com/docs/colors
+|-------------------------------------------------------------------------------
+|
+| Here you can specify the colors used in your project. To get you started,
+| we've provided a generous palette of great looking colors that are perfect
+| for prototyping, but don't hesitate to change them for your project. You
+| own these colors, nothing will break if you change everything about them.
+|
+| We've used literal color names ("red", "blue", etc.) for the default
+| palette, but if you'd rather use functional names like "primary" and
+| "secondary", or even a numeric scale like "100" and "200", go for it.
+|
+*/
+
+var colors = {
+ 'transparent': 'transparent',
+
+ 'black': '#222b2f',
+ 'grey-darkest': '#364349',
+ 'grey-darker': '#596a73',
+ 'grey-dark': '#70818a',
+ 'grey': '#9babb4',
+ 'grey-light': '#dae4e9',
+ 'grey-lighter': '#f3f7f9',
+ 'grey-lightest': '#fafcfc',
+ 'white': '#ffffff',
+
+ 'red-darkest': '#420806',
+ 'red-darker': '#6a1b19',
+ 'red-dark': '#cc1f1a',
+ 'red': '#e3342f',
+ 'red-light': '#ef5753',
+ 'red-lighter': '#f9acaa',
+ 'red-lightest': '#fcebea',
+
+ 'orange-darkest': '#542605',
+ 'orange-darker': '#7f4012',
+ 'orange-dark': '#de751f',
+ 'orange': '#f6993f',
+ 'orange-light': '#faad63',
+ 'orange-lighter': '#fcd9b6',
+ 'orange-lightest': '#fff5eb',
+
+ 'yellow-darkest': '#453411',
+ 'yellow-darker': '#684f1d',
+ 'yellow-dark': '#f2d024',
+ 'yellow': '#ffed4a',
+ 'yellow-light': '#fff382',
+ 'yellow-lighter': '#fff9c2',
+ 'yellow-lightest': '#fcfbeb',
+
+ 'green-darkest': '#032d19',
+ 'green-darker': '#0b4228',
+ 'green-dark': '#1f9d55',
+ 'green': '#38c172',
+ 'green-light': '#51d88a',
+ 'green-lighter': '#a2f5bf',
+ 'green-lightest': '#e3fcec',
+
+ 'teal-darkest': '#0d3331',
+ 'teal-darker': '#174e4b',
+ 'teal-dark': '#38a89d',
+ 'teal': '#4dc0b5',
+ 'teal-light': '#64d5ca',
+ 'teal-lighter': '#a0f0ed',
+ 'teal-lightest': '#e8fffe',
+
+ 'blue-darkest': '#05233b',
+ 'blue-darker': '#103d60',
+ 'blue-dark': '#2779bd',
+ 'blue': '#3490dc',
+ 'blue-light': '#6cb2eb',
+ 'blue-lighter': '#bcdefa',
+ 'blue-lightest': '#eff8ff',
+
+ 'indigo-darkest': '#191e38',
+ 'indigo-darker': '#2f365f',
+ 'indigo-dark': '#5661b3',
+ 'indigo': '#6574cd',
+ 'indigo-light': '#7886d7',
+ 'indigo-lighter': '#b2b7ff',
+ 'indigo-lightest': '#e6e8ff',
+
+ 'purple-darkest': '#1f133f',
+ 'purple-darker': '#352465',
+ 'purple-dark': '#794acf',
+ 'purple': '#9561e2',
+ 'purple-light': '#a779e9',
+ 'purple-lighter': '#d6bbfc',
+ 'purple-lightest': '#f3ebff',
+
+ 'pink-darkest': '#45051e',
+ 'pink-darker': '#72173a',
+ 'pink-dark': '#eb5286',
+ 'pink': '#f66d9b',
+ 'pink-light': '#fa7ea8',
+ 'pink-lighter': '#ffbbca',
+ 'pink-lightest': '#ffebef',
+}
+
+module.exports = {
+
+ /*
+ |-----------------------------------------------------------------------------
+ | Colors https://tailwindcss.com/docs/colors
+ |-----------------------------------------------------------------------------
+ |
+ | The color palette defined above is also assigned to the "colors" key of
+ | your Tailwind config. This makes it easy to access them in your CSS
+ | using Tailwind's config helper. For example:
+ |
+ | .error { color: config('colors.red') }
+ |
+ */
+
+ colors: colors,
+
+
+ /*
+ |-----------------------------------------------------------------------------
+ | Screens https://tailwindcss.com/docs/responsive-design
+ |-----------------------------------------------------------------------------
+ |
+ | Screens in Tailwind are translated to CSS media queries. They define the
+ | responsive breakpoints for your project. By default Tailwind takes a
+ | "mobile first" approach, where each screen size represents a minimum
+ | viewport width. Feel free to have as few or as many screens as you
+ | want, naming them in whatever way you'd prefer for your project.
+ |
+ | Tailwind also allows for more complex screen definitions, which can be
+ | useful in certain situations. Be sure to see the full responsive
+ | documentation for a complete list of options.
+ |
+ | Class name: .{screen}:{utility}
+ |
+ */
+
+ screens: {
+ 'sm': '576px',
+ 'md': '768px',
+ 'lg': '992px',
+ 'xl': '1200px',
+ },
+
+
+ /*
+ |-----------------------------------------------------------------------------
+ | Fonts https://tailwindcss.com/docs/fonts
+ |-----------------------------------------------------------------------------
+ |
+ | Here is where you define your project's font stack, or font families.
+ | Keep in mind that Tailwind doesn't actually load any fonts for you.
+ | If you're using custom fonts you'll need to import them prior to
+ | defining them here.
+ |
+ | By default we provide a native font stack that works remarkably well on
+ | any device or OS you're using, since it just uses the default fonts
+ | provided by the platform.
+ |
+ | Class name: .font-{name}
+ |
+ */
+
+ fonts: {
+ 'sans': [
+ '-apple-system',
+ 'BlinkMacSystemFont',
+ 'Segoe UI',
+ 'Roboto',
+ 'Oxygen',
+ 'Ubuntu',
+ 'Cantarell',
+ 'Fira Sans',
+ 'Droid Sans',
+ 'Helvetica Neue',
+ 'sans-serif',
+ ],
+ 'serif': [
+ 'Constantia',
+ 'Lucida Bright',
+ 'Lucidabright',
+ 'Lucida Serif',
+ 'Lucida',
+ 'DejaVu Serif',
+ 'Bitstream Vera Serif',
+ 'Liberation Serif',
+ 'Georgia',
+ 'serif',
+ ],
+ 'mono': [
+ 'Menlo',
+ 'Monaco',
+ 'Consolas',
+ 'Liberation Mono',
+ 'Courier New',
+ 'monospace',
+ ]
+ },
+
+
+ /*
+ |-----------------------------------------------------------------------------
+ | Text sizes https://tailwindcss.com/docs/text-sizing
+ |-----------------------------------------------------------------------------
+ |
+ | Here is where you define your text sizes. Name these in whatever way
+ | makes the most sense to you. We use size names by default, but
+ | you're welcome to use a numeric scale or even something else
+ | entirely.
+ |
+ | By default Tailwind uses the "rem" unit type for most measurements.
+ | This allows you to set a root font size which all other sizes are
+ | then based on. That said, you are free to use whatever units you
+ | prefer, be it rems, ems, pixels or other.
+ |
+ | Class name: .text-{size}
+ |
+ */
+
+ textSizes: {
+ 'xs': '.75rem', // 12px
+ 'sm': '.875rem', // 14px
+ 'base': '1rem', // 16px
+ 'lg': '1.125rem', // 18px
+ 'xl': '1.25rem', // 20px
+ '2xl': '1.5rem', // 24px
+ '3xl': '1.875rem', // 30px
+ '4xl': '2.25rem', // 36px
+ '5xl': '3rem', // 48px
+ },
+
+
+ /*
+ |-----------------------------------------------------------------------------
+ | Font weights https://tailwindcss.com/docs/font-weight
+ |-----------------------------------------------------------------------------
+ |
+ | Here is where you define your font weights. We've provided a list of
+ | common font weight names with their respective numeric scale values
+ | to get you started. It's unlikely that your project will require
+ | all of these, so we recommend removing those you don't need.
+ |
+ | Class name: .font-{weight}
+ |
+ */
+
+ fontWeights: {
+ 'hairline': 100,
+ 'thin': 200,
+ 'light': 300,
+ 'normal': 400,
+ 'medium': 500,
+ 'semibold': 600,
+ 'bold': 700,
+ 'extrabold': 800,
+ 'black': 900,
+ },
+
+
+ /*
+ |-----------------------------------------------------------------------------
+ | Leading (line height) https://tailwindcss.com/docs/line-height
+ |-----------------------------------------------------------------------------
+ |
+ | Here is where you define your line height values, or as we call
+ | them in Tailwind, leadings.
+ |
+ | Class name: .leading-{size}
+ |
+ */
+
+ leading: {
+ 'none': 1,
+ 'tight': 1.25,
+ 'normal': 1.5,
+ 'loose': 2,
+ },
+
+
+ /*
+ |-----------------------------------------------------------------------------
+ | Tracking (letter spacing) https://tailwindcss.com/docs/letter-spacing
+ |-----------------------------------------------------------------------------
+ |
+ | Here is where you define your letter spacing values, or as we call
+ | them in Tailwind, tracking.
+ |
+ | Class name: .tracking-{size}
+ |
+ */
+
+ tracking: {
+ 'tight': '-0.05em',
+ 'normal': '0',
+ 'wide': '0.05em',
+ },
+
+
+ /*
+ |-----------------------------------------------------------------------------
+ | Text colors https://tailwindcss.com/docs/text-color
+ |-----------------------------------------------------------------------------
+ |
+ | Here is where you define your text colors. By default these use the
+ | color palette we defined above, however you're welcome to set these
+ | independently if that makes sense for your project.
+ |
+ | Class name: .text-{color}
+ |
+ */
+
+ textColors: colors,
+
+
+ /*
+ |-----------------------------------------------------------------------------
+ | Background colors https://tailwindcss.com/docs/background-color
+ |-----------------------------------------------------------------------------
+ |
+ | Here is where you define your background colors. By default these use
+ | the color palette we defined above, however you're welcome to set
+ | these independently if that makes sense for your project.
+ |
+ | Class name: .bg-{color}
+ |
+ */
+
+ backgroundColors: colors,
+
+
+ /*
+ |-----------------------------------------------------------------------------
+ | Border widths https://tailwindcss.com/docs/border-width
+ |-----------------------------------------------------------------------------
+ |
+ | Here is where you define your border widths. Take note that border
+ | widths require a special "default" value set as well. This is the
+ | width that will be used when you do not specify a border width.
+ |
+ | Class name: .border{-side?}{-width?}
+ |
+ */
+
+ borderWidths: {
+ default: '1px',
+ '0': '0',
+ '2': '2px',
+ '4': '4px',
+ '8': '8px',
+ },
+
+
+ /*
+ |-----------------------------------------------------------------------------
+ | Border colors https://tailwindcss.com/docs/border-color
+ |-----------------------------------------------------------------------------
+ |
+ | Here is where you define your border colors. By default these use the
+ | color palette we defined above, however you're welcome to set these
+ | independently if that makes sense for your project.
+ |
+ | Take note that border colors require a special "default" value set
+ | as well. This is the color that will be used when you do not
+ | specify a border color.
+ |
+ | Class name: .border-{color}
+ |
+ */
+
+ borderColors: Object.assign({ default: colors['grey-light'] }, colors),
+
+
+ /*
+ |-----------------------------------------------------------------------------
+ | Border radius https://tailwindcss.com/docs/border-radius
+ |-----------------------------------------------------------------------------
+ |
+ | Here is where you define your border radius values. If a `default` radius
+ | is provided, it will be made available as the non-suffixed `.rounded`
+ | utility.
+ |
+ | If your scale includes a `0` value to reset already rounded corners, it's
+ | a good idea to put it first so other values are able to override it.
+ |
+ | Class name: .rounded{-side?}{-size?}
+ |
+ */
+
+ borderRadius: {
+ 'none': '0',
+ 'sm': '.125rem',
+ default: '.25rem',
+ 'lg': '.5rem',
+ 'full': '9999px',
+ },
+
+
+ /*
+ |-----------------------------------------------------------------------------
+ | Width https://tailwindcss.com/docs/width
+ |-----------------------------------------------------------------------------
+ |
+ | Here is where you define your width utility sizes. These can be
+ | percentage based, pixels, rems, or any other units. By default
+ | we provide a sensible rem based numeric scale, a percentage
+ | based fraction scale, plus some other common use-cases. You
+ | can, of course, modify these values as needed.
+ |
+ |
+ | It's also worth mentioning that Tailwind automatically escapes
+ | invalid CSS class name characters, which allows you to have
+ | awesome classes like .w-2/3.
+ |
+ | Class name: .w-{size}
+ |
+ */
+
+ width: {
+ 'auto': 'auto',
+ 'px': '1px',
+ '1': '0.25rem',
+ '2': '0.5rem',
+ '3': '0.75rem',
+ '4': '1rem',
+ '6': '1.5rem',
+ '8': '2rem',
+ '10': '2.5rem',
+ '12': '3rem',
+ '16': '4rem',
+ '24': '6rem',
+ '32': '8rem',
+ '48': '12rem',
+ '64': '16rem',
+ '1/2': '50%',
+ '1/3': '33.33333%',
+ '2/3': '66.66667%',
+ '1/4': '25%',
+ '3/4': '75%',
+ '1/5': '20%',
+ '2/5': '40%',
+ '3/5': '60%',
+ '4/5': '80%',
+ '1/6': '16.66667%',
+ '5/6': '83.33333%',
+ 'full': '100%',
+ 'screen': '100vw'
+ },
+
+
+ /*
+ |-----------------------------------------------------------------------------
+ | Height https://tailwindcss.com/docs/height
+ |-----------------------------------------------------------------------------
+ |
+ | Here is where you define your height utility sizes. These can be
+ | percentage based, pixels, rems, or any other units. By default
+ | we provide a sensible rem based numeric scale plus some other
+ | common use-cases. You can, of course, modify these values as
+ | needed.
+ |
+ | Class name: .h-{size}
+ |
+ */
+
+ height: {
+ 'auto': 'auto',
+ 'px': '1px',
+ '1': '0.25rem',
+ '2': '0.5rem',
+ '3': '0.75rem',
+ '4': '1rem',
+ '6': '1.5rem',
+ '8': '2rem',
+ '10': '2.5rem',
+ '12': '3rem',
+ '16': '4rem',
+ '24': '6rem',
+ '32': '8rem',
+ '48': '12rem',
+ '64': '16rem',
+ 'full': '100%',
+ 'screen': '100vh'
+ },
+
+
+ /*
+ |-----------------------------------------------------------------------------
+ | Minimum width https://tailwindcss.com/docs/min-width
+ |-----------------------------------------------------------------------------
+ |
+ | Here is where you define your minimum width utility sizes. These can
+ | be percentage based, pixels, rems, or any other units. We provide a
+ | couple common use-cases by default. You can, of course, modify
+ | these values as needed.
+ |
+ | Class name: .min-w-{size}
+ |
+ */
+
+ minWidth: {
+ '0': '0',
+ 'full': '100%',
+ },
+
+
+ /*
+ |-----------------------------------------------------------------------------
+ | Minimum height https://tailwindcss.com/docs/min-height
+ |-----------------------------------------------------------------------------
+ |
+ | Here is where you define your minimum height utility sizes. These can
+ | be percentage based, pixels, rems, or any other units. We provide a
+ | few common use-cases by default. You can, of course, modify these
+ | values as needed.
+ |
+ | Class name: .min-h-{size}
+ |
+ */
+
+ minHeight: {
+ '0': '0',
+ 'full': '100%',
+ 'screen': '100vh'
+ },
+
+
+ /*
+ |-----------------------------------------------------------------------------
+ | Maximum width https://tailwindcss.com/docs/max-width
+ |-----------------------------------------------------------------------------
+ |
+ | Here is where you define your maximum width utility sizes. These can
+ | be percentage based, pixels, rems, or any other units. By default
+ | we provide a sensible rem based scale and a "full width" size,
+ | which is basically a reset utility. You can, of course,
+ | modify these values as needed.
+ |
+ | Class name: .max-w-{size}
+ |
+ */
+
+ maxWidth: {
+ 'xs': '20rem',
+ 'sm': '30rem',
+ 'md': '40rem',
+ 'lg': '50rem',
+ 'xl': '60rem',
+ '2xl': '70rem',
+ '3xl': '80rem',
+ '4xl': '90rem',
+ '5xl': '100rem',
+ 'full': '100%',
+ },
+
+
+ /*
+ |-----------------------------------------------------------------------------
+ | Maximum height https://tailwindcss.com/docs/max-height
+ |-----------------------------------------------------------------------------
+ |
+ | Here is where you define your maximum height utility sizes. These can
+ | be percentage based, pixels, rems, or any other units. We provide a
+ | couple common use-cases by default. You can, of course, modify
+ | these values as needed.
+ |
+ | Class name: .max-h-{size}
+ |
+ */
+
+ maxHeight: {
+ 'full': '100%',
+ 'screen': '100vh',
+ },
+
+
+ /*
+ |-----------------------------------------------------------------------------
+ | Padding https://tailwindcss.com/docs/padding
+ |-----------------------------------------------------------------------------
+ |
+ | Here is where you define your padding utility sizes. These can be
+ | percentage based, pixels, rems, or any other units. By default we
+ | provide a sensible rem based numeric scale plus a couple other
+ | common use-cases like "1px". You can, of course, modify these
+ | values as needed.
+ |
+ | Class name: .p{side?}-{size}
+ |
+ */
+
+ padding: {
+ 'px': '1px',
+ '0': '0',
+ '1': '0.25rem',
+ '2': '0.5rem',
+ '3': '0.75rem',
+ '4': '1rem',
+ '6': '1.5rem',
+ '8': '2rem',
+ },
+
+
+ /*
+ |-----------------------------------------------------------------------------
+ | Margin https://tailwindcss.com/docs/margin
+ |-----------------------------------------------------------------------------
+ |
+ | Here is where you define your margin utility sizes. These can be
+ | percentage based, pixels, rems, or any other units. By default we
+ | provide a sensible rem based numeric scale plus a couple other
+ | common use-cases like "1px". You can, of course, modify these
+ | values as needed.
+ |
+ | Class name: .m{side?}-{size}
+ |
+ */
+
+ margin: {
+ 'auto': 'auto',
+ 'px': '1px',
+ '0': '0',
+ '1': '0.25rem',
+ '2': '0.5rem',
+ '3': '0.75rem',
+ '4': '1rem',
+ '6': '1.5rem',
+ '8': '2rem',
+ },
+
+
+ /*
+ |-----------------------------------------------------------------------------
+ | Negative margin https://tailwindcss.com/docs/negative-margin
+ |-----------------------------------------------------------------------------
+ |
+ | Here is where you define your negative margin utility sizes. These can
+ | be percentage based, pixels, rems, or any other units. By default we
+ | provide matching values to the padding scale since these utilities
+ | generally get used together. You can, of course, modify these
+ | values as needed.
+ |
+ | Class name: .-m{side?}-{size}
+ |
+ */
+
+ negativeMargin: {
+ 'px': '1px',
+ '0': '0',
+ '1': '0.25rem',
+ '2': '0.5rem',
+ '3': '0.75rem',
+ '4': '1rem',
+ '6': '1.5rem',
+ '8': '2rem',
+ },
+
+
+ /*
+ |-----------------------------------------------------------------------------
+ | Shadows https://tailwindcss.com/docs/shadows
+ |-----------------------------------------------------------------------------
+ |
+ | Here is where you define your shadow utilities. As you can see from
+ | the defaults we provide, it's possible to apply multiple shadows
+ | per utility using comma separation.
+ |
+ | If a `default` shadow is provided, it will be made available as the non-
+ | suffixed `.shadow` utility.
+ |
+ | Class name: .shadow-{size?}
+ |
+ */
+
+ shadows: {
+ default: '0 2px 4px 0 rgba(0,0,0,0.10)',
+ 'md': '0 4px 8px 0 rgba(0,0,0,0.12), 0 2px 4px 0 rgba(0,0,0,0.08)',
+ 'lg': '0 15px 30px 0 rgba(0,0,0,0.11), 0 5px 15px 0 rgba(0,0,0,0.08)',
+ 'inner': 'inset 0 2px 4px 0 rgba(0,0,0,0.06)',
+ 'none': 'none',
+ },
+
+
+ /*
+ |-----------------------------------------------------------------------------
+ | Z-index https://tailwindcss.com/docs/z-index
+ |-----------------------------------------------------------------------------
+ |
+ | Here is where you define your z-index utility values. By default we
+ | provide a sensible numeric scale. You can, of course, modify these
+ | values as needed.
+ |
+ | Class name: .z-{index}
+ |
+ */
+
+ zIndex: {
+ 'auto': 'auto',
+ '0': 0,
+ '10': 10,
+ '20': 20,
+ '30': 30,
+ '40': 40,
+ '50': 50,
+ },
+
+
+ /*
+ |-----------------------------------------------------------------------------
+ | Opacity https://tailwindcss.com/docs/opacity
+ |-----------------------------------------------------------------------------
+ |
+ | Here is where you define your opacity utility values. By default we
+ | provide a sensible numeric scale. You can, of course, modify these
+ | values as needed.
+ |
+ | Class name: .opacity-{name}
+ |
+ */
+
+ opacity: {
+ '0': '0',
+ '25': '.25',
+ '50': '.5',
+ '75': '.75',
+ '100': '1',
+ },
+
+
+ /*
+ |-----------------------------------------------------------------------------
+ | Options https://tailwindcss.com/docs/configuration#options
+ |-----------------------------------------------------------------------------
+ |
+ | Here is where you can set your Tailwind configuration options. For more
+ | details about these options, visit the configuration options documentation.
+ |
+ */
+
+ options: {
+ prefix: '',
+ important: false,
+ },
+
+}
diff --git a/examples/with-tailwindcss/styles/index.css b/examples/with-tailwindcss/styles/index.css
new file mode 100644
index 000000000000..c3b331bb4b6a
--- /dev/null
+++ b/examples/with-tailwindcss/styles/index.css
@@ -0,0 +1,55 @@
+@import "./button.css";
+
+@tailwind preflight;
+@tailwind utilities;
+
+.hero {
+ width: 100%;
+ color: #333;
+}
+
+.title {
+ margin: 0;
+ width: 100%;
+ padding-top: 80px;
+ line-height: 1.15;
+ font-size: 48px;
+}
+
+.title, .description {
+ text-align: center;
+}
+
+.row {
+ max-width: 880px;
+ margin: 80px auto 40px;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-around;
+}
+
+.card {
+ padding: 18px 18px 24px;
+ width: 220px;
+ text-align: left;
+ text-decoration: none;
+ color: #434343;
+ border: 1px solid #9B9B9B;
+}
+
+.card:hover {
+ border-color: #067df7;
+}
+
+.card h3 {
+ margin: 0;
+ color: #067df7;
+ font-size: 18px;
+}
+
+.card p {
+ margin: 0;
+ padding: 12px 0 0;
+ font-size: 13px;
+ color: #333;
+}
From 8eb80342362c545e511c3b0c5416f4542610ca46 Mon Sep 17 00:00:00 2001
From: Saro Vindigni
Date: Thu, 23 Nov 2017 14:02:09 +0100
Subject: [PATCH 043/163] remove relative path to babel-runtime (#3119)
---
server/build/babel/preset.js | 3 ++-
server/build/webpack.js | 4 +++-
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/server/build/babel/preset.js b/server/build/babel/preset.js
index d8f218e11bdc..b2b5fac4fbeb 100644
--- a/server/build/babel/preset.js
+++ b/server/build/babel/preset.js
@@ -1,3 +1,4 @@
+const babelRuntimePath = require.resolve('babel-runtime/package').replace(/[\\/]package\.json$/, '')
const relativeResolve = require('../root-module-relative-path').default(require)
// Resolve styled-jsx plugins
@@ -56,7 +57,7 @@ module.exports = (context, opts = {}) => ({
require.resolve('babel-plugin-module-resolver'),
{
alias: {
- 'babel-runtime': relativeResolve('babel-runtime/package'),
+ 'babel-runtime': babelRuntimePath,
'next/link': relativeResolve('../../../lib/link'),
'next/prefetch': relativeResolve('../../../lib/prefetch'),
'next/css': relativeResolve('../../../lib/css'),
diff --git a/server/build/webpack.js b/server/build/webpack.js
index 9f030b95e04a..ba0ec11b351a 100644
--- a/server/build/webpack.js
+++ b/server/build/webpack.js
@@ -219,6 +219,8 @@ export default async function createCompiler (dir, { buildId, dev = false, quiet
return { content, sourceMap }
}
+ const babelRuntimePath = require.resolve('babel-runtime/package').replace(/[\\/]package\.json$/, '')
+
const transpiled = babelCore.transform(content, {
babelrc: false,
sourceMaps: dev ? 'both' : false,
@@ -233,7 +235,7 @@ export default async function createCompiler (dir, { buildId, dev = false, quiet
require.resolve('babel-plugin-module-resolver'),
{
alias: {
- 'babel-runtime': relativeResolve('babel-runtime/package'),
+ 'babel-runtime': babelRuntimePath,
'next/link': relativeResolve('../../lib/link'),
'next/prefetch': relativeResolve('../../lib/prefetch'),
'next/css': relativeResolve('../../lib/css'),
From 742fa6590c47bd83f2e13d80a423f1a834e54cd9 Mon Sep 17 00:00:00 2001
From: Jonas Budelmann
Date: Fri, 24 Nov 2017 02:05:17 +1300
Subject: [PATCH 044/163] Fix statically exported pages from hanging (#2930)
* fix script loading errors not reported if exported
* fix lint
---
lib/page-loader.js | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/lib/page-loader.js b/lib/page-loader.js
index 99cc99ed7280..81f6b8e63029 100644
--- a/lib/page-loader.js
+++ b/lib/page-loader.js
@@ -69,13 +69,14 @@ export default class PageLoader {
loadScript (route) {
route = this.normalizeRoute(route)
+ let scriptRoute = route
if (__NEXT_DATA__.nextExport) {
- route = route === '/' ? '/index.js' : `${route}/index.js`
+ scriptRoute = route === '/' ? '/index.js' : `${route}/index.js`
}
const script = document.createElement('script')
- const url = `${this.assetPrefix}/_next/${encodeURIComponent(this.buildId)}/page${route}`
+ const url = `${this.assetPrefix}/_next/${encodeURIComponent(this.buildId)}/page${scriptRoute}`
script.src = url
script.type = 'text/javascript'
script.onerror = () => {
From 5ede8c9dc351af94ce88aea9143bef5c347fee78 Mon Sep 17 00:00:00 2001
From: Brian Dombrowski
Date: Thu, 23 Nov 2017 08:05:51 -0500
Subject: [PATCH 045/163] More complete with-apollo-and-redux example with
dynamic post route (#3223)
* More complete with-apollo-and-redux example with dynamic post route
* Removed commented out code
---
.../components/Header.js | 4 ++
.../with-apollo-and-redux/components/Post.js | 41 +++++++++++++++++++
.../components/PostList.js | 3 +-
examples/with-apollo-and-redux/package.json | 5 ++-
.../with-apollo-and-redux/pages/blog/entry.js | 11 +++++
.../with-apollo-and-redux/pages/blog/index.js | 13 ++++++
examples/with-apollo-and-redux/pages/index.js | 3 +-
examples/with-apollo-and-redux/server.js | 40 ++++++++++++++++++
8 files changed, 115 insertions(+), 5 deletions(-)
create mode 100644 examples/with-apollo-and-redux/components/Post.js
create mode 100644 examples/with-apollo-and-redux/pages/blog/entry.js
create mode 100644 examples/with-apollo-and-redux/pages/blog/index.js
create mode 100644 examples/with-apollo-and-redux/server.js
diff --git a/examples/with-apollo-and-redux/components/Header.js b/examples/with-apollo-and-redux/components/Header.js
index 937e5b100da6..2945d0c76a1c 100644
--- a/examples/with-apollo-and-redux/components/Header.js
+++ b/examples/with-apollo-and-redux/components/Header.js
@@ -10,6 +10,10 @@ export default ({ pathname }) => (
About
+
+ Blog
+
+
+
+ ,
+ this.modalRoot
+ )
+ }
+}
diff --git a/examples/with-portals/package.json b/examples/with-portals/package.json
new file mode 100644
index 000000000000..4c6c6a4d3814
--- /dev/null
+++ b/examples/with-portals/package.json
@@ -0,0 +1,12 @@
+{
+ "scripts": {
+ "dev": "next",
+ "build": "next build",
+ "start": "next start"
+ },
+ "dependencies": {
+ "next": "^4.1.4",
+ "react": "^16.2.0",
+ "react-dom": "^16.2.0"
+ }
+}
diff --git a/examples/with-portals/pages/_document.js b/examples/with-portals/pages/_document.js
new file mode 100644
index 000000000000..258292888e11
--- /dev/null
+++ b/examples/with-portals/pages/_document.js
@@ -0,0 +1,17 @@
+import Document, { Head, Main, NextScript } from 'next/document'
+
+export default class extends Document {
+ render () {
+ return (
+
+
+
+
+ {/* here we will mount our modal portal */}
+
+
+
+
+ )
+ }
+}
diff --git a/examples/with-portals/pages/index.js b/examples/with-portals/pages/index.js
new file mode 100644
index 000000000000..bab3b9bfeb84
--- /dev/null
+++ b/examples/with-portals/pages/index.js
@@ -0,0 +1,31 @@
+import { Component } from 'react'
+import dynamic from 'next/dynamic'
+
+// we import and render the modal only client side (because we need a DOM)
+const Modal = dynamic(import('../components/modal'), {
+ ssr: false
+})
+
+export default class extends Component {
+ state = { modal: false };
+
+ toggleModal = () => this.setState(state => ({ modal: !state.modal }))
+
+ render () {
+ return (
+
+
+ {this.state.modal && (
+
+
+ }
+}
diff --git a/examples/with-universal-configuration-runtime/readme.md b/examples/with-universal-configuration-runtime/readme.md
new file mode 100644
index 000000000000..c072e6b63969
--- /dev/null
+++ b/examples/with-universal-configuration-runtime/readme.md
@@ -0,0 +1,30 @@
+[![Deploy to now](https://deploy.now.sh/static/button.svg)](https://deploy.now.sh/?repo=https://github.com/zeit/next.js/tree/master/examples/with-universal-configuration)
+
+# With universal runtime configuration
+
+## How to use
+
+Download the example [or clone the repo](https://github.com/zeit/next.js):
+
+```bash
+curl https://codeload.github.com/zeit/next.js/tar.gz/master | tar -xz --strip=2 next.js-master/examples/with-universal-configuration-runtime
+cd with-universal-configuration-runtime
+```
+
+Install it and run:
+
+```bash
+npm install
+API_URL='https://example.com' npm run dev
+```
+
+Deploy it to the cloud with [now](https://zeit.co/now) ([download](https://zeit.co/download))
+
+```bash
+now
+```
+
+## The idea behind the example
+
+This example show how to set custom environment variables for your application at runtime
+
From 57c6f80d723849ac89891ed5aeb78197c30ec6ed Mon Sep 17 00:00:00 2001
From: Benjamin Atkin
Date: Sat, 2 Dec 2017 09:12:57 -0800
Subject: [PATCH 054/163] use underscore in node_modules in travis config
(#3369)
The cached directory for node_modules has a dash. AFAIK node uses an underscore, not a dash, for node_modules.
Alternatively, remove it from cached directories if the typo isn't causing any problems.
---
.travis.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.travis.yml b/.travis.yml
index b00cb9d96be7..dbb967ebcd05 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -10,7 +10,7 @@
language: "node_js",
node_js: ["6"],
cache: {
- directories: ["node-modules"]
+ directories: ["node_modules"]
},
before_install: [
"rm yarn.lock",
From 8cd6bd3fc3ee7b7eee887092a086cfb1e9c639db Mon Sep 17 00:00:00 2001
From: Tim Neutkens
Date: Sat, 2 Dec 2017 18:13:39 +0100
Subject: [PATCH 055/163] Add check for writeable directory (#3370)
* Add check for writeable directory
Followup of https://github.com/zeit/now-cli/issues/175
* Add link to docs
---
errors/build-dir-not-writeable.md | 30 ++++++++++++++++++++++++++++++
readme.md | 14 +++++++++++++-
server/build/index.js | 8 ++++++++
3 files changed, 51 insertions(+), 1 deletion(-)
create mode 100644 errors/build-dir-not-writeable.md
diff --git a/errors/build-dir-not-writeable.md b/errors/build-dir-not-writeable.md
new file mode 100644
index 000000000000..0f654b50b60f
--- /dev/null
+++ b/errors/build-dir-not-writeable.md
@@ -0,0 +1,30 @@
+# Build directory not writeable
+
+#### Why This Error Occurred
+
+The filesystem does not allow writing to the specified directory. A common cause for this error is starting a [custom server](https://github.com/zeit/next.js#custom-server-and-routing) in development mode on a production server, for example, [now.sh](https://zeit.co) which [doesn't allow you to write to the filesystem after your app is built](https://zeit.co/docs/deployment-types/node#file-system-specifications).
+
+#### Possible Ways to Fix It
+
+When using a custom server with a server file, for example called `server.js`, make sure you update the scripts key in `package.json` to:
+
+```json
+{
+ "scripts": {
+ "dev": "node server.js",
+ "build": "next build",
+ "start": "NODE_ENV=production node server.js"
+ }
+}
+```
+
+and the custom server starts Next in production mode when `NODE_ENV` is `production`
+
+```js
+const dev = process.env.NODE_ENV !== 'production'
+const app = next({ dev })
+```
+
+### Useful Links
+
+- [Custom Server documentation + examples](https://github.com/zeit/next.js#custom-server-and-routing)
diff --git a/readme.md b/readme.md
index 25d41160eee1..e7ecea64f81a 100644
--- a/readme.md
+++ b/readme.md
@@ -669,7 +669,19 @@ export default ({ url }) =>
-Typically you start your next server with `next start`. It's possible, however, to start a server 100% programmatically in order to customize routes, use route patterns, etc
+Typically you start your next server with `next start`. It's possible, however, to start a server 100% programmatically in order to customize routes, use route patterns, etc.
+
+When using a custom server with a server file, for example called `server.js`, make sure you update the scripts key in `package.json` to:
+
+```json
+{
+ "scripts": {
+ "dev": "node server.js",
+ "build": "next build",
+ "start": "NODE_ENV=production node server.js"
+ }
+}
+```
This example makes `/a` resolve to `./pages/b`, and `/b` resolve to `./pages/a`:
diff --git a/server/build/index.js b/server/build/index.js
index ba311bf8978e..10149b32e940 100644
--- a/server/build/index.js
+++ b/server/build/index.js
@@ -10,6 +10,14 @@ import md5File from 'md5-file/promise'
export default async function build (dir, conf = null) {
const buildId = uuid.v4()
const buildDir = join(tmpdir(), uuid.v4())
+
+ try {
+ await fs.access(buildDir, fs.constants.W_OK)
+ } catch (err) {
+ console.error(`> Failed, build directory is not writeable. https://err.sh/zeit/next.js/build-dir-not-writeable`)
+ throw err
+ }
+
const compiler = await webpack(dir, { buildId, buildDir, conf })
try {
From 36f6179a521390943350f27ab04a53789605e6ba Mon Sep 17 00:00:00 2001
From: Tim Neutkens
Date: Sat, 2 Dec 2017 09:52:34 -0800
Subject: [PATCH 056/163] Check if tmpdir is writeable. Not full path
---
server/build/index.js | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/server/build/index.js b/server/build/index.js
index 10149b32e940..8c2261d39dcd 100644
--- a/server/build/index.js
+++ b/server/build/index.js
@@ -9,10 +9,11 @@ import md5File from 'md5-file/promise'
export default async function build (dir, conf = null) {
const buildId = uuid.v4()
- const buildDir = join(tmpdir(), uuid.v4())
+ const tempDir = tmpdir()
+ const buildDir = join(tempDir, uuid.v4())
try {
- await fs.access(buildDir, fs.constants.W_OK)
+ await fs.access(tempDir, fs.constants.W_OK)
} catch (err) {
console.error(`> Failed, build directory is not writeable. https://err.sh/zeit/next.js/build-dir-not-writeable`)
throw err
From cd0e13df01bd04875a5b303301c54680ca72209d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sergio=20Xalambr=C3=AD?=
Date: Sat, 2 Dec 2017 20:44:38 -0300
Subject: [PATCH 057/163] Add example of Nodemon on a custom server (#3374)
---
examples/custom-server-nodemon/README.md | 29 +++++++++++++++++++
examples/custom-server-nodemon/nodemon.json | 3 ++
examples/custom-server-nodemon/package.json | 15 ++++++++++
examples/custom-server-nodemon/pages/a.js | 3 ++
examples/custom-server-nodemon/pages/b.js | 3 ++
examples/custom-server-nodemon/pages/index.js | 9 ++++++
.../custom-server-nodemon/server/index.js | 28 ++++++++++++++++++
7 files changed, 90 insertions(+)
create mode 100644 examples/custom-server-nodemon/README.md
create mode 100644 examples/custom-server-nodemon/nodemon.json
create mode 100644 examples/custom-server-nodemon/package.json
create mode 100644 examples/custom-server-nodemon/pages/a.js
create mode 100644 examples/custom-server-nodemon/pages/b.js
create mode 100644 examples/custom-server-nodemon/pages/index.js
create mode 100644 examples/custom-server-nodemon/server/index.js
diff --git a/examples/custom-server-nodemon/README.md b/examples/custom-server-nodemon/README.md
new file mode 100644
index 000000000000..91ed60e18e3f
--- /dev/null
+++ b/examples/custom-server-nodemon/README.md
@@ -0,0 +1,29 @@
+[![Deploy to now](https://deploy.now.sh/static/button.svg)](https://deploy.now.sh/?repo=https://github.com/zeit/next.js/tree/master/examples/custom-server-nodemon)
+
+# Custom server with Nodemon example
+
+## How to use
+
+Download the example [or clone the repo](https://github.com/zeit/next.js):
+
+```bash
+curl https://codeload.github.com/zeit/next.js/tar.gz/master | tar -xz --strip=2 next.js-master/examples/custom-server-nodemon
+cd custom-server-nodemon
+```
+
+Install it and run:
+
+```bash
+npm install
+npm run dev
+```
+
+Deploy it to the cloud with [now](https://zeit.co/now) ([download](https://zeit.co/download))
+
+```bash
+now
+```
+
+## The idea behind the example
+
+The example shows how you can apply [Nodemon](https://nodemon.io/) to a custom server to have live reload of the server code without being affected by the Next.js universal code.
diff --git a/examples/custom-server-nodemon/nodemon.json b/examples/custom-server-nodemon/nodemon.json
new file mode 100644
index 000000000000..ab8591fb8558
--- /dev/null
+++ b/examples/custom-server-nodemon/nodemon.json
@@ -0,0 +1,3 @@
+{
+ "watch": ["server/**/*.js"]
+}
diff --git a/examples/custom-server-nodemon/package.json b/examples/custom-server-nodemon/package.json
new file mode 100644
index 000000000000..5d1aa0c0ab99
--- /dev/null
+++ b/examples/custom-server-nodemon/package.json
@@ -0,0 +1,15 @@
+{
+ "scripts": {
+ "dev": "nodemon server/index.js",
+ "build": "next build",
+ "start": "NODE_ENV=production node server/index.js"
+ },
+ "dependencies": {
+ "next": "^4.1.4",
+ "react": "^16.2.0",
+ "react-dom": "^16.2.0"
+ },
+ "devDependencies": {
+ "nodemon": "^1.12.1"
+ }
+}
diff --git a/examples/custom-server-nodemon/pages/a.js b/examples/custom-server-nodemon/pages/a.js
new file mode 100644
index 000000000000..c5359797af81
--- /dev/null
+++ b/examples/custom-server-nodemon/pages/a.js
@@ -0,0 +1,3 @@
+import React from 'react'
+
+export default () =>
a
diff --git a/examples/custom-server-nodemon/pages/b.js b/examples/custom-server-nodemon/pages/b.js
new file mode 100644
index 000000000000..9bde4d9dc56b
--- /dev/null
+++ b/examples/custom-server-nodemon/pages/b.js
@@ -0,0 +1,3 @@
+import React from 'react'
+
+export default () =>
b
diff --git a/examples/custom-server-nodemon/pages/index.js b/examples/custom-server-nodemon/pages/index.js
new file mode 100644
index 000000000000..d044fc1e2c0b
--- /dev/null
+++ b/examples/custom-server-nodemon/pages/index.js
@@ -0,0 +1,9 @@
+import React from 'react'
+import Link from 'next/link'
+
+export default () => (
+
+ )
+ }
+}
diff --git a/examples/with-data-prefetch/pages/index.js b/examples/with-data-prefetch/pages/index.js
new file mode 100644
index 000000000000..11288175cfc6
--- /dev/null
+++ b/examples/with-data-prefetch/pages/index.js
@@ -0,0 +1,25 @@
+import Link from '../components/link'
+
+// we just render a list of 3 articles having 2 with prefetched data
+export default () => (
+
+
+
+)
From e4acd7db591c9cd77d960eab6ec60ab3361062df Mon Sep 17 00:00:00 2001
From: zollero
Date: Wed, 27 Dec 2017 17:40:41 +0800
Subject: [PATCH 096/163] Add the closed parenthesis. (#3506)
---
readme.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/readme.md b/readme.md
index 39046d0fc565..56d5989cbc0c 100644
--- a/readme.md
+++ b/readme.md
@@ -1087,7 +1087,7 @@ Next.js can be deployed to other hosting solutions too. Please have a look at th
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!
-Note: we recommend putting `.next`, or your custom dist folder (Please have a look at ['Custom Config'](https://github.com/zeit/next.js#custom-configuration). You can set a custom folder in config, `.npmignore`, or `.gitignore`. Otherwise, use `files` or `now.files` to opt-into a whitelist of files you want to deploy (and obviously exclude `.next` or your custom dist folder).
+Note: we recommend putting `.next`, or your custom dist folder (Please have a look at ['Custom Config'](https://github.com/zeit/next.js#custom-configuration)). You can set a custom folder in config, `.npmignore`, or `.gitignore`. Otherwise, use `files` or `now.files` to opt-into a whitelist of files you want to deploy (and obviously exclude `.next` or your custom dist folder).
## Static HTML export
From 46b57a6effa5f9c4f5ab043e682970bd5b5ae311 Mon Sep 17 00:00:00 2001
From: Jerome Fitzgerald
Date: Wed, 27 Dec 2017 13:57:57 -0500
Subject: [PATCH 097/163] [refactor] with-apollo-and-redux: 2.0.0 (#3484)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* [refactor] with-apollo-and-redux: 2.0.0
- This ports over `with-apollo` (w/ recent `withRouter` fix and addition
for Post) along with implementing `apollo-cache-redux` #3463
- The `redux` side of things is lacking (it is the *same* as the
original example)
- Created a `routes.js` for use on Server and Client Side (to expand the
PostList functionality)
- SSR is maintained
- Redid the "PostVote" a bit... sorry. 😬️
Possible todo(s):
- Add in API and Clock Examples from `with-redux` to show Apollo and
Redux working together a bit more
- redux-saga (I personally use this, may be too opinionated for the base
example though)
Packages updated:
- apollo-cache-redux
- apollo-client-preset
- graphql
- graphql-anywhere
- graphql-tag
- isomorphic-unfetch
- next-routes
- prop-types
- react
- react-apollo
- react-dom
- redux
* [refactor] fix linting issues
When I run `yarn lint` explicitly these were caught, but not doing a
build proper. Apologies on that!
* [chore] 📦️ package.json: like other examples
* [refactor] +apollo-cache-inmemory, -apollo-cache-redux
Separation of Apollo and Redux. 😄️
We could stand to use a few actual examples of Redux, though this is a
good starting block.
Some other code cleanup as well.
---
examples/with-apollo-and-redux/README.md | 7 +-
.../components/Header.js | 14 +-
.../with-apollo-and-redux/components/Post.js | 81 +-
.../components/PostList.js | 62 +-
.../components/PostUpvoter.js | 56 --
.../components/PostVoteButton.js | 30 +
.../components/PostVoteCount.js | 12 +
.../components/PostVoteDown.js | 41 +
.../components/PostVoteUp.js | 41 +
.../components/Submit.js | 58 +-
.../with-apollo-and-redux/lib/initApollo.js | 22 +-
.../with-apollo-and-redux/lib/initRedux.js | 11 +-
.../with-apollo-and-redux/lib/reducers.js | 2 +-
.../with-apollo-and-redux/lib/withData.js | 66 +-
examples/with-apollo-and-redux/package.json | 14 +-
examples/with-apollo-and-redux/pages/about.js | 4 +-
.../with-apollo-and-redux/pages/blog/entry.js | 7 +-
.../with-apollo-and-redux/pages/blog/index.js | 7 +-
examples/with-apollo-and-redux/pages/index.js | 7 +-
examples/with-apollo-and-redux/routes.js | 8 +
examples/with-apollo-and-redux/server.js | 10 +-
yarn.lock | 813 ++----------------
22 files changed, 397 insertions(+), 976 deletions(-)
delete mode 100644 examples/with-apollo-and-redux/components/PostUpvoter.js
create mode 100644 examples/with-apollo-and-redux/components/PostVoteButton.js
create mode 100644 examples/with-apollo-and-redux/components/PostVoteCount.js
create mode 100644 examples/with-apollo-and-redux/components/PostVoteDown.js
create mode 100644 examples/with-apollo-and-redux/components/PostVoteUp.js
create mode 100644 examples/with-apollo-and-redux/routes.js
diff --git a/examples/with-apollo-and-redux/README.md b/examples/with-apollo-and-redux/README.md
index 1e4c151caf92..e218fc916a0b 100644
--- a/examples/with-apollo-and-redux/README.md
+++ b/examples/with-apollo-and-redux/README.md
@@ -35,9 +35,9 @@ now
```
## The idea behind the example
-By default, Apollo Client creates its own internal Redux store to manage queries and their results. If you are already using Redux for the rest of your app, [you can have the client integrate with your existing store instead](http://dev.apollodata.com/react/redux.html), which is what this example does. This example is identical to the [`with-apollo`](https://github.com/zeit/next.js/tree/master/examples/with-apollo) with the exception of this Redux store integration.
+In 2.0.0, Apollo Client severs out-of-the-box support for redux in favor of Apollo's client side state management. This example aims to be an amalgamation of the [`with-apollo`](https://github.com/zeit/next.js/tree/master/examples/with-apollo) and [`with-redux`](https://github.com/zeit/next.js/tree/master/examples/with-redux) examples.
-Note that you can acesss the redux store like you normally would using `react-redux`'s `connect` as per [here](http://dev.apollodata.com/react/redux.html#using-connect). Here's a quick example:
+Note that you can access the redux store like you normally would using `react-redux`'s `connect`. Here's a quick example:
```js
const mapStateToProps = state => ({
@@ -47,5 +47,4 @@ const mapStateToProps = state => ({
export default withData(connect(mapStateToProps, null)(Index));
```
-`connect` must go inside `withData` otherwise `connect` will not be able to find the store.
-
+`connect` must go inside `withData` otherwise `connect` will not be able to find the store.
diff --git a/examples/with-apollo-and-redux/components/Header.js b/examples/with-apollo-and-redux/components/Header.js
index 2945d0c76a1c..bc6b696ab262 100644
--- a/examples/with-apollo-and-redux/components/Header.js
+++ b/examples/with-apollo-and-redux/components/Header.js
@@ -1,19 +1,17 @@
import Link from 'next/link'
+import { withRouter } from 'next/router'
-export default ({ pathname }) => (
+const Header = ({ router: { pathname } }) => (
- Home
+ Home
-
- About
+ About
-
- Blog
+ Blog
-
)
+
+export default withRouter(Header)
diff --git a/examples/with-apollo-and-redux/components/Post.js b/examples/with-apollo-and-redux/components/Post.js
index 545f75708775..e3ae745c010d 100644
--- a/examples/with-apollo-and-redux/components/Post.js
+++ b/examples/with-apollo-and-redux/components/Post.js
@@ -1,40 +1,63 @@
import React from 'react'
-import { gql, graphql } from 'react-apollo'
-import PostUpvoter from './PostUpvoter'
+import { withRouter } from 'next/router'
+import { graphql } from 'react-apollo'
+import gql from 'graphql-tag'
-function Post ({ id, data: { loading, error, Post } }) {
- return (
-
-
-
{Post.title}
-
ID: {Post.id} URL: {Post.url}
-
-
-
- )
+import ErrorMessage from './ErrorMessage'
+import PostVoteUp from './PostVoteUp'
+import PostVoteDown from './PostVoteDown'
+import PostVoteCount from './PostVoteCount'
+
+function Post ({ id, data: { error, Post } }) {
+ if (error) return
+ if (Post) {
+ return (
+
+
+
{Post.title}
+
ID: {Post.id} URL: {Post.url}
+
+
+
+
+
+
+
+
+ )
+ }
+ return
Loading
}
const post = gql`
- query post($id: ID!) {
- Post(id: $id) {
- id
- title
- votes
- url
- createdAt
- }
+ query post($id: ID!) {
+ Post(id: $id) {
+ id
+ title
+ votes
+ url
+ createdAt
}
+ }
`
// The `graphql` wrapper executes a GraphQL query and makes the results
-// available on the `data` prop of the wrapped component (PostList)
-// Tip: ownProps is parent component's props
-export default graphql(post, {
- options: (ownProps) => {
- return {
- variables: {
- id: ownProps.id
- }
+// available on the `data` prop of the wrapped component (Post)
+const ComponentWithMutation = graphql(post, {
+ options: ({ router: { query } }) => ({
+ variables: {
+ id: query.id
}
- }
+ }),
+ props: ({ data }) => ({
+ data
+ })
})(Post)
+
+export default withRouter(ComponentWithMutation)
diff --git a/examples/with-apollo-and-redux/components/PostList.js b/examples/with-apollo-and-redux/components/PostList.js
index f3cdedf509e1..b46340a9fc9a 100644
--- a/examples/with-apollo-and-redux/components/PostList.js
+++ b/examples/with-apollo-and-redux/components/PostList.js
@@ -1,28 +1,56 @@
-import { gql, graphql } from 'react-apollo'
+import { graphql } from 'react-apollo'
+import gql from 'graphql-tag'
+import { Router } from '../routes'
import ErrorMessage from './ErrorMessage'
-import PostUpvoter from './PostUpvoter'
-import Link from 'next/link'
+import PostVoteUp from './PostVoteUp'
+import PostVoteDown from './PostVoteDown'
+import PostVoteCount from './PostVoteCount'
const POSTS_PER_PAGE = 10
-function PostList ({ data: { loading, error, allPosts, _allPostsMeta }, loadMorePosts }) {
+function handleClick (event, id) {
+ event.preventDefault()
+ // With route name and params
+ // Router.pushRoute('blog/entry', { id: id })
+ // With route URL
+ Router.pushRoute(`/blog/${id}`)
+}
+
+function PostList ({
+ data: { loading, error, allPosts, _allPostsMeta },
+ loadMorePosts
+}) {
if (error) return
if (allPosts && allPosts.length) {
const areMorePosts = allPosts.length < _allPostsMeta.count
return (
)
diff --git a/test/integration/custom-server/server.js b/test/integration/custom-server/server.js
index 3c58563c8eb7..8547f14a1a9e 100644
--- a/test/integration/custom-server/server.js
+++ b/test/integration/custom-server/server.js
@@ -11,7 +11,7 @@ const handleNextRequests = app.getRequestHandler()
app.prepare().then(() => {
const server = micro((req, res) => {
if (/setAssetPrefix/.test(req.url)) {
- app.setAssetPrefix('https://cdn.com/myapp')
+ app.setAssetPrefix(`http://127.0.0.1:${port}`)
} else {
// This is to support multi-zones support in localhost
// and may be in staging deployments
diff --git a/test/integration/custom-server/test/index.test.js b/test/integration/custom-server/test/index.test.js
index dcab619f7a6c..e476d7666463 100644
--- a/test/integration/custom-server/test/index.test.js
+++ b/test/integration/custom-server/test/index.test.js
@@ -3,11 +3,13 @@
import { join } from 'path'
import getPort from 'get-port'
import clone from 'clone'
+import cheerio from 'cheerio'
import {
initNextServerScript,
killApp,
renderViaHTTP
} from 'next-test-utils'
+import webdriver from 'next-webdriver'
const appDir = join(__dirname, '../')
let appPort
@@ -29,23 +31,51 @@ describe('Custom Server', () => {
describe('with dynamic assetPrefix', () => {
it('should set the assetPrefix dynamically', async () => {
- const normalUsage = await renderViaHTTP(appPort, '/')
- expect(normalUsage).not.toMatch(/cdn\.com\/myapp/)
+ const normalUsage = await renderViaHTTP(appPort, '/asset')
+ expect(normalUsage).not.toMatch(/127\.0\.0\.1/)
- const dynamicUsage = await renderViaHTTP(appPort, '/?setAssetPrefix=1')
- expect(dynamicUsage).toMatch(/cdn\.com\/myapp/)
+ const dynamicUsage = await renderViaHTTP(appPort, '/asset?setAssetPrefix=1')
+ expect(dynamicUsage).toMatch(/127\.0\.0\.1/)
})
it('should set the assetPrefix to a given request', async () => {
for (let lc = 0; lc < 1000; lc++) {
const [normalUsage, dynamicUsage] = await Promise.all([
- await renderViaHTTP(appPort, '/'),
- await renderViaHTTP(appPort, '/?setAssetPrefix=1')
+ await renderViaHTTP(appPort, '/asset'),
+ await renderViaHTTP(appPort, '/asset?setAssetPrefix=1')
])
- expect(normalUsage).not.toMatch(/cdn\.com\/myapp/)
- expect(dynamicUsage).toMatch(/cdn\.com\/myapp/)
+ expect(normalUsage).not.toMatch(/127\.0\.0\.1/)
+ expect(dynamicUsage).toMatch(/127\.0\.0\.1/)
}
})
+
+ it('should support next/asset in server side', async () => {
+ const $normal = cheerio.load(await renderViaHTTP(appPort, '/asset'))
+ expect($normal('img').attr('src')).toBe('/static/myimage.png')
+
+ const $dynamic = cheerio.load(await renderViaHTTP(appPort, '/asset?setAssetPrefix=1'))
+ expect($dynamic('img').attr('src')).toBe(`http://127.0.0.1:${context.appPort}/static/myimage.png`)
+ })
+
+ it('should support next/asset in client side', async() => {
+ const browser = await webdriver(context.appPort, '/')
+ await browser
+ .elementByCss('#go-asset').click()
+ .waitForElementByCss('#asset-page')
+
+ expect(await browser.elementByCss('img').getAttribute('src'))
+ .toBe(`http://localhost:${context.appPort}/static/myimage.png`)
+ browser.close()
+
+ const browser2 = await webdriver(context.appPort, '/?setAssetPrefix=1')
+ await browser2
+ .elementByCss('#go-asset').click()
+ .waitForElementByCss('#asset-page')
+
+ expect(await browser2.elementByCss('img').getAttribute('src'))
+ .toBe(`http://127.0.0.1:${context.appPort}/static/myimage.png`)
+ browser2.close()
+ })
})
})
From c01de960f40db0e2268bead6a1f36737e421363a Mon Sep 17 00:00:00 2001
From: Tim Neutkens
Date: Sat, 3 Feb 2018 00:14:40 +0100
Subject: [PATCH 146/163] Upgrade react-hot-loader (#3665)
---
package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/package.json b/package.json
index 1e1f7b423dd2..075ba58b5283 100644
--- a/package.json
+++ b/package.json
@@ -89,7 +89,7 @@
"pkg-up": "2.0.0",
"prop-types": "15.6.0",
"prop-types-exact": "1.1.1",
- "react-hot-loader": "4.0.0-beta.14",
+ "react-hot-loader": "4.0.0-beta.18",
"recursive-copy": "2.0.6",
"resolve": "1.5.0",
"send": "0.16.1",
From d103345aa1e687b8ab904465ad41c45511c6c063 Mon Sep 17 00:00:00 2001
From: John Polacek
Date: Sat, 3 Feb 2018 10:11:16 -0600
Subject: [PATCH 147/163] Fix typos in gh-pages example README (#3669)
---
examples/gh-pages/README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/examples/gh-pages/README.md b/examples/gh-pages/README.md
index a9b040b2640f..1f09950f3fd5 100644
--- a/examples/gh-pages/README.md
+++ b/examples/gh-pages/README.md
@@ -34,11 +34,11 @@ npm run deploy
Test it:
-Reaplce 'github-user-name' and 'github-projet-name'
+Replace 'github-user-name' and 'github-project-name'
```bash
-https://github-user-name.github.io/github-projet-name/
+https://github-user-name.github.io/github-project-name/
```
From 7afc008aa7318125a9eb7d6cc8ce10d3f7057a13 Mon Sep 17 00:00:00 2001
From: Chris
Date: Sat, 3 Feb 2018 08:11:47 -0800
Subject: [PATCH 148/163] Example: Passing data from server through API (#2594)
* Add example on how to pass data through js api during SSR
Requested in #1117
* Use content negotiation instead of a separate route
* Codereview feedback
* Move security related test cases into a its own file.
* Removes the unused renderScript function
* Add a nerv example. (#3573)
* Add a nerv example.
* Fix for indentation/style
* Fix for name
---
examples/pass-server-data/README.md | 50 +++++++++++++++++++
examples/pass-server-data/data/item.json | 5 ++
.../pass-server-data/operations/get-item.js | 12 +++++
examples/pass-server-data/package.json | 16 ++++++
examples/pass-server-data/pages/index.js | 8 +++
examples/pass-server-data/pages/item.js | 33 ++++++++++++
examples/pass-server-data/server.js | 39 +++++++++++++++
examples/using-nerv/README.md | 44 ++++++++++++++++
examples/using-nerv/next.config.js | 16 ++++++
examples/using-nerv/package.json | 21 ++++++++
examples/using-nerv/pages/about.js | 5 ++
examples/using-nerv/pages/index.js | 6 +++
examples/using-nerv/server.js | 29 +++++++++++
.../integration/production/test/index.test.js | 39 ++-------------
test/integration/production/test/security.js | 45 +++++++++++++++++
15 files changed, 333 insertions(+), 35 deletions(-)
create mode 100644 examples/pass-server-data/README.md
create mode 100644 examples/pass-server-data/data/item.json
create mode 100644 examples/pass-server-data/operations/get-item.js
create mode 100644 examples/pass-server-data/package.json
create mode 100644 examples/pass-server-data/pages/index.js
create mode 100644 examples/pass-server-data/pages/item.js
create mode 100644 examples/pass-server-data/server.js
create mode 100644 examples/using-nerv/README.md
create mode 100644 examples/using-nerv/next.config.js
create mode 100644 examples/using-nerv/package.json
create mode 100644 examples/using-nerv/pages/about.js
create mode 100644 examples/using-nerv/pages/index.js
create mode 100644 examples/using-nerv/server.js
create mode 100644 test/integration/production/test/security.js
diff --git a/examples/pass-server-data/README.md b/examples/pass-server-data/README.md
new file mode 100644
index 000000000000..8943155ab7cd
--- /dev/null
+++ b/examples/pass-server-data/README.md
@@ -0,0 +1,50 @@
+[![Deploy to now](https://deploy.now.sh/static/button.svg)](https://deploy.now.sh/?repo=https://github.com/zeit/next.js/tree/master/examples/pass-server-data)
+
+# Pass Server Data Directly to a Next.js Page during SSR
+
+## How to use
+
+Download the example [or clone the repo](https://github.com/zeit/next.js):
+
+```bash
+curl https://codeload.github.com/zeit/next.js/tar.gz/master | tar -xz --strip=2 next.js-master/examples/pass-server-data
+cd pass-server-data
+```
+
+Install it and run:
+
+```bash
+npm install
+npm run dev
+```
+
+Deploy it to the cloud with [now](https://zeit.co/now) ([download](https://zeit.co/download))
+
+```bash
+now
+```
+
+## The idea behind the example
+
+If you already have a custom server which has local data (for instance cached data from an API call, or data read
+from a file at startup) that you wish to make available in the Next.js page, you can pass that data in the query
+parameter of `nextApp.render()`.
+
+This is not the only way to pass data. You could also expose an endpoint and make a `fetch()` call to localhost, or you could
+import server-side code with `eval` (necessary to prevent webpack from trying to package your server code). However both
+solutions leave something to be desired in either performance or elegance.
+
+This example shows the express server at `server.js` reading in a file at load time with static data (this could also have been
+data cached from an API call) in `operations/get-item.js`. It has two routes: a home page, and an item page. The item page uses
+data from the get-item operation, passed as a query parameter in `routes/item.js`.
+
+We use this data in `pages/item.js` if rendered server-side, or make a fetch request if rendered client-side.
+The server knows whether or not to use next.js to render the route based on the Accept header, which will be
+`application/json` when we fetch client-side.
+
+Take a look at the following files:
+
+* server.js
+* routes/item.js
+* pages/item.js
+* operations/get-item.js
diff --git a/examples/pass-server-data/data/item.json b/examples/pass-server-data/data/item.json
new file mode 100644
index 000000000000..a0782820e5cf
--- /dev/null
+++ b/examples/pass-server-data/data/item.json
@@ -0,0 +1,5 @@
+{
+ "title": "Now",
+ "subtitle": "Realtime global deployments",
+ "seller": "Zeit"
+}
diff --git a/examples/pass-server-data/operations/get-item.js b/examples/pass-server-data/operations/get-item.js
new file mode 100644
index 000000000000..60125db39387
--- /dev/null
+++ b/examples/pass-server-data/operations/get-item.js
@@ -0,0 +1,12 @@
+const fs = require('fs')
+
+// In this case, data read from the fs, but it could also be a cached API result.
+const data = fs.readFileSync('./data/item.json', 'utf8')
+const parsedData = JSON.parse(data)
+
+function getItem () {
+ console.log('Requested Item Data:', data)
+ return parsedData
+}
+
+module.exports = { getItem }
diff --git a/examples/pass-server-data/package.json b/examples/pass-server-data/package.json
new file mode 100644
index 000000000000..7259805caa62
--- /dev/null
+++ b/examples/pass-server-data/package.json
@@ -0,0 +1,16 @@
+{
+ "name": "pass-server-data",
+ "version": "1.0.0",
+ "scripts": {
+ "dev": "node server.js",
+ "build": "next build",
+ "start": "NODE_ENV=production node server.js"
+ },
+ "dependencies": {
+ "express": "^4.14.0",
+ "isomorphic-fetch": "^2.2.1",
+ "next": "latest",
+ "react": "^15.4.2",
+ "react-dom": "^15.4.2"
+ }
+}
diff --git a/examples/pass-server-data/pages/index.js b/examples/pass-server-data/pages/index.js
new file mode 100644
index 000000000000..7d706c4437a5
--- /dev/null
+++ b/examples/pass-server-data/pages/index.js
@@ -0,0 +1,8 @@
+import React from 'react'
+import Link from 'next/link'
+
+export default () => (
+
+)
diff --git a/examples/pass-server-data/pages/item.js b/examples/pass-server-data/pages/item.js
new file mode 100644
index 000000000000..bea6748ea918
--- /dev/null
+++ b/examples/pass-server-data/pages/item.js
@@ -0,0 +1,33 @@
+import {Component} from 'react'
+import Link from 'next/link'
+import fetch from 'isomorphic-fetch'
+
+export default class extends Component {
+ static async getInitialProps ({ req, query }) {
+ const isServer = !!req
+
+ console.log('getInitialProps called:', isServer ? 'server' : 'client')
+
+ if (isServer) {
+ // When being rendered server-side, we have access to our data in query that we put there in routes/item.js,
+ // saving us an http call. Note that if we were to try to require('../operations/get-item') here,
+ // it would result in a webpack error.
+ return { item: query.itemData }
+ } else {
+ // On the client, we should fetch the data remotely
+ const res = await fetch('/_data/item', {headers: {'Accept': 'application/json'}})
+ const json = await res.json()
+ return { item: json }
+ }
+ }
+
+ render () {
+ return (
+