From 25dbcce60b0b2996ba355e6842112c6748a3026b Mon Sep 17 00:00:00 2001 From: Arana Jhonny Date: Sun, 30 Apr 2017 10:29:37 -0400 Subject: [PATCH 01/82] fix #1833, update all examples. (#1834) --- examples/svg-components/package.json | 2 +- examples/with-pretty-url-routing/package.json | 2 +- examples/with-shallow-routing/package.json | 2 +- examples/with-webpack-bundle-analyzer/package.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/svg-components/package.json b/examples/svg-components/package.json index c744ec88..1bbd46bf 100644 --- a/examples/svg-components/package.json +++ b/examples/svg-components/package.json @@ -7,7 +7,7 @@ "start": "next start" }, "dependencies": { - "next": "beta" + "next": "latest" }, "devDependencies": { "babel-plugin-inline-react-svg": "^0.2.0" diff --git a/examples/with-pretty-url-routing/package.json b/examples/with-pretty-url-routing/package.json index 3080fbb7..6eb1c5d0 100644 --- a/examples/with-pretty-url-routing/package.json +++ b/examples/with-pretty-url-routing/package.json @@ -6,7 +6,7 @@ }, "dependencies": { "express": "^4.15.2", - "next": "^2.0.0", + "next": "latest", "next-url-prettifier": "^1.0.2", "prop-types": "^15.5.6", "react": "^15.4.2", diff --git a/examples/with-shallow-routing/package.json b/examples/with-shallow-routing/package.json index 5f52e996..95ac6a1c 100644 --- a/examples/with-shallow-routing/package.json +++ b/examples/with-shallow-routing/package.json @@ -7,7 +7,7 @@ "start": "next start" }, "dependencies": { - "next": "next@beta", + "next": "latest", "react": "^15.4.2", "react-dom": "^15.4.2" }, diff --git a/examples/with-webpack-bundle-analyzer/package.json b/examples/with-webpack-bundle-analyzer/package.json index 5b7ed9f5..2d15a47e 100644 --- a/examples/with-webpack-bundle-analyzer/package.json +++ b/examples/with-webpack-bundle-analyzer/package.json @@ -8,7 +8,7 @@ "bundle:view": "webpack-bundle-analyzer .next/stats.json" }, "dependencies": { - "next": "beta", + "next": "latest", "react": "^15.4.2", "react-dom": "^15.4.2", "webpack-bundle-analyzer": "^2.3.0" From 03bfaecf49fa2a50d2059950552932c8100934c5 Mon Sep 17 00:00:00 2001 From: Brendan Houle Date: Sun, 30 Apr 2017 10:30:29 -0400 Subject: [PATCH 02/82] Add root static files example (#1835) --- examples/root-static-files/README.md | 29 +++++++++++++++++ examples/root-static-files/package.json | 12 +++++++ examples/root-static-files/pages/index.js | 7 ++++ examples/root-static-files/server.js | 30 ++++++++++++++++++ examples/root-static-files/static/favicon.ico | Bin 0 -> 1086 bytes examples/root-static-files/static/robots.txt | 2 ++ examples/root-static-files/static/sitemap.xml | 6 ++++ 7 files changed, 86 insertions(+) create mode 100644 examples/root-static-files/README.md create mode 100644 examples/root-static-files/package.json create mode 100644 examples/root-static-files/pages/index.js create mode 100644 examples/root-static-files/server.js create mode 100644 examples/root-static-files/static/favicon.ico create mode 100644 examples/root-static-files/static/robots.txt create mode 100644 examples/root-static-files/static/sitemap.xml diff --git a/examples/root-static-files/README.md b/examples/root-static-files/README.md new file mode 100644 index 00000000..adcc63cc --- /dev/null +++ b/examples/root-static-files/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) + +# Root static files 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 +cd custom-server +``` + +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 demonstrates how to serve files such as /robots.txt and /sitemap.xml from the root. diff --git a/examples/root-static-files/package.json b/examples/root-static-files/package.json new file mode 100644 index 00000000..7c5f57b9 --- /dev/null +++ b/examples/root-static-files/package.json @@ -0,0 +1,12 @@ +{ + "scripts": { + "dev": "node server.js", + "build": "next build", + "start": "NODE_ENV=production node server.js" + }, + "dependencies": { + "next": "latest", + "react": "^15.5.4", + "react-dom": "^15.5.4" + } +} diff --git a/examples/root-static-files/pages/index.js b/examples/root-static-files/pages/index.js new file mode 100644 index 00000000..2bcdac86 --- /dev/null +++ b/examples/root-static-files/pages/index.js @@ -0,0 +1,7 @@ +export default () => ( + +) diff --git a/examples/root-static-files/server.js b/examples/root-static-files/server.js new file mode 100644 index 00000000..7f26bd60 --- /dev/null +++ b/examples/root-static-files/server.js @@ -0,0 +1,30 @@ +const { createServer } = require('http') +const { parse } = require('url') +const next = require('next') +const { join } = require('path') + +const dev = process.env.NODE_ENV !== 'production' +const app = next({ dev }) +const handle = app.getRequestHandler() + +app.prepare() +.then(() => { + createServer((req, res) => { + const parsedUrl = parse(req.url, true) + const rootStaticFiles = [ + '/robots.txt', + '/sitemap.xml', + '/favicon.ico' + ] + if (rootStaticFiles.indexOf(parsedUrl.pathname) > -1) { + const path = join(__dirname, 'static', parsedUrl.pathname) + app.serveStatic(req, res, path) + } else { + handle(req, res, parsedUrl) + } + }) + .listen(3000, (err) => { + if (err) throw err + console.log('> Ready on http://localhost:3000') + }) +}) diff --git a/examples/root-static-files/static/favicon.ico b/examples/root-static-files/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..cdeb3a7c87ee1ce2441729b62fb48f80dd4dad52 GIT binary patch literal 1086 zcmc(aF%AGA3 + + + http://www.example.com/foo.html + + From 8d59de4d7aeab0fb29b43f04aa63c07983c9babb Mon Sep 17 00:00:00 2001 From: Craig Ramey Date: Sun, 30 Apr 2017 10:31:03 -0400 Subject: [PATCH 03/82] example curl pointed to with-styled-components, supposed to be with-flow (#1832) --- examples/with-flow/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/with-flow/README.md b/examples/with-flow/README.md index 480f6012..f3d4dc31 100644 --- a/examples/with-flow/README.md +++ b/examples/with-flow/README.md @@ -6,7 +6,7 @@ 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-styled-components +curl https://codeload.github.com/zeit/next.js/tar.gz/master | tar -xz --strip=2 next.js-master/examples/with-flow cd with-flow ``` @@ -27,4 +27,4 @@ now This example shows how you can use Flow, with the transform-flow-strip-types babel plugin stripping flow type annotations from your output code. -![with-flow](with-flow.gif) \ No newline at end of file +![with-flow](with-flow.gif) From fa45cb8aa29ea714cb4da484599ca45bacf89ca2 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Sun, 30 Apr 2017 07:31:15 -0700 Subject: [PATCH 04/82] chore(package): update nyc to version 10.3.0 (#1830) https://greenkeeper.io/ --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9020e232..d59d3906 100644 --- a/package.json +++ b/package.json @@ -115,7 +115,7 @@ "lint-staged": "^3.4.0", "node-fetch": "1.6.3", "node-notifier": "5.1.2", - "nyc": "10.2.0", + "nyc": "10.3.0", "react": "15.5.3", "react-dom": "15.5.3", "standard": "9.0.2", From fc0302afb5f9030e2d869480a0211d0de3403e3f Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Sun, 30 Apr 2017 07:31:35 -0700 Subject: [PATCH 05/82] chore(package): update babel-plugin-istanbul to version 4.1.3 (#1829) https://greenkeeper.io/ --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d59d3906..1a57c80f 100644 --- a/package.json +++ b/package.json @@ -97,7 +97,7 @@ "devDependencies": { "babel-eslint": "7.2.3", "babel-jest": "18.0.0", - "babel-plugin-istanbul": "4.1.1", + "babel-plugin-istanbul": "4.1.3", "babel-plugin-transform-remove-strict-mode": "0.0.2", "babel-preset-es2015": "6.24.1", "benchmark": "2.1.4", From 208b3199cb13d6a3d2b5eb2ec0311730de3f1b67 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Sun, 30 Apr 2017 07:31:51 -0700 Subject: [PATCH 06/82] chore(package): update coveralls to version 2.13.1 (#1822) https://greenkeeper.io/ --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1a57c80f..e2abd16b 100644 --- a/package.json +++ b/package.json @@ -103,7 +103,7 @@ "benchmark": "2.1.4", "cheerio": "0.22.0", "chromedriver": "2.29.0", - "coveralls": "2.13.0", + "coveralls": "2.13.1", "cross-env": "4.0.0", "fly": "2.0.5", "fly-babel": "2.1.1", From 1f642dceda060f4a72959ebc28a8961e76936147 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" Date: Sun, 30 Apr 2017 07:32:00 -0700 Subject: [PATCH 07/82] fix(package): update source-map-support to version 0.4.15 (#1826) https://greenkeeper.io/ --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e2abd16b..214aca95 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,7 @@ "prop-types": "15.5.7", "react-hot-loader": "3.0.0-beta.6", "send": "0.15.2", - "source-map-support": "0.4.14", + "source-map-support": "0.4.15", "strip-ansi": "3.0.1", "styled-jsx": "0.5.7", "touch": "1.0.0", From c9d06703620f4702a1e42e42d2e263439da25fd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81tila=20Fassina?= Date: Sun, 30 Apr 2017 16:35:07 +0200 Subject: [PATCH 08/82] with-i18next example (#1496) * examples/with-i18next: create folder and initial settings * examples/with-i18next:abstract url and object keys - finish readme * examples/with-i18next: next@beta is not actually necessary * examples/with-it18next: fix standardjs eslint warnings * examples/with-i18next: review updates --- examples/with-i18next/README.md | 33 +++++++++++++++++++ examples/with-i18next/components/Title.js | 2 ++ examples/with-i18next/package.json | 19 +++++++++++ examples/with-i18next/pages/index.js | 27 +++++++++++++++ .../static/locales/pt/common.json | 3 ++ examples/with-i18next/tools/startI18n.js | 11 +++++++ .../with-i18next/tools/translationHelpers.js | 13 ++++++++ 7 files changed, 108 insertions(+) create mode 100644 examples/with-i18next/README.md create mode 100644 examples/with-i18next/components/Title.js create mode 100644 examples/with-i18next/package.json create mode 100644 examples/with-i18next/pages/index.js create mode 100644 examples/with-i18next/static/locales/pt/common.json create mode 100644 examples/with-i18next/tools/startI18n.js create mode 100644 examples/with-i18next/tools/translationHelpers.js diff --git a/examples/with-i18next/README.md b/examples/with-i18next/README.md new file mode 100644 index 00000000..d5f129f2 --- /dev/null +++ b/examples/with-i18next/README.md @@ -0,0 +1,33 @@ + +# with-i18next 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/with-i18next +cd with-i18next +``` + +Install it and run: + +```bash +npm install +npm run dev +``` + +alternatively +```bash +yarn && yarn 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 add internationalisation through [i18next](https://github.com/i18next/i18next) to your NextJS app. The possibilities and features are documented in the [i18next project](http://i18next.com/translate/) diff --git a/examples/with-i18next/components/Title.js b/examples/with-i18next/components/Title.js new file mode 100644 index 00000000..ed6a37f6 --- /dev/null +++ b/examples/with-i18next/components/Title.js @@ -0,0 +1,2 @@ +import { translate } from 'react-i18next' +export default translate(['common'])((props) => (

{props.t('hello')}

)) diff --git a/examples/with-i18next/package.json b/examples/with-i18next/package.json new file mode 100644 index 00000000..642200c9 --- /dev/null +++ b/examples/with-i18next/package.json @@ -0,0 +1,19 @@ +{ + "name": "with-i18next", + "version": "1.0.0", + "scripts": { + "dev": "next", + "build": "next build", + "start": "next start" + }, + "dependencies": { + "i18next": "^7.1.3", + "isomorphic-fetch": "^2.2.1", + "next": "*", + "react": "^15.4.2", + "react-dom": "^15.4.2", + "react-i18next": "^2.2.1" + }, + "author": "", + "license": "ISC" +} diff --git a/examples/with-i18next/pages/index.js b/examples/with-i18next/pages/index.js new file mode 100644 index 00000000..2d429a86 --- /dev/null +++ b/examples/with-i18next/pages/index.js @@ -0,0 +1,27 @@ +import React, { Component } from 'react' +import { I18nextProvider } from 'react-i18next' +import startI18n from '../tools/startI18n' +import { getTranslation } from '../tools/translationHelpers' +import Title from '../components/Title' + +export default class Homepage extends Component { + static async getInitialProps () { + const translations = await getTranslation('pt', 'common', 'http://localhost:3000/static/locales/') + + return { translations } + } + + constructor (props) { + super(props) + + this.i18n = startI18n(props.translations) + } + + render (props) { + return ( + + + </ I18nextProvider> + ) + } +} diff --git a/examples/with-i18next/static/locales/pt/common.json b/examples/with-i18next/static/locales/pt/common.json new file mode 100644 index 00000000..c8f9b7c0 --- /dev/null +++ b/examples/with-i18next/static/locales/pt/common.json @@ -0,0 +1,3 @@ +{ + "hello": "e ae tche" +} \ No newline at end of file diff --git a/examples/with-i18next/tools/startI18n.js b/examples/with-i18next/tools/startI18n.js new file mode 100644 index 00000000..791d2c93 --- /dev/null +++ b/examples/with-i18next/tools/startI18n.js @@ -0,0 +1,11 @@ +import i18n from 'i18next' + +const startI18n = file => i18n.init({ + fallbackLng: 'pt', + resources: file, + ns: ['common'], + defaultNS: 'common', + debug: false +}) + +export default startI18n diff --git a/examples/with-i18next/tools/translationHelpers.js b/examples/with-i18next/tools/translationHelpers.js new file mode 100644 index 00000000..fcfa9b58 --- /dev/null +++ b/examples/with-i18next/tools/translationHelpers.js @@ -0,0 +1,13 @@ +/* global fetch */ +import 'isomorphic-fetch' + +export async function getTranslation (lang, file, baseUrl) { + const response = await fetch(`${baseUrl}${lang}/${file}.json`) + const json = await response.json() + + return { + [lang]: { + [file]: json + } + } +} From 8fb6a03e482c87a079130c6691f11104203c2142 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com> Date: Sun, 30 Apr 2017 07:35:19 -0700 Subject: [PATCH 09/82] fix(package): update babel-plugin-transform-react-remove-prop-types to version 0.4.2 (#1810) https://greenkeeper.io/ --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 214aca95..205c20e7 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "babel-plugin-transform-es2015-modules-commonjs": "6.24.1", "babel-plugin-transform-object-rest-spread": "6.22.0", "babel-plugin-transform-react-jsx-source": "6.22.0", - "babel-plugin-transform-react-remove-prop-types": "0.4.1", + "babel-plugin-transform-react-remove-prop-types": "0.4.2", "babel-plugin-transform-runtime": "6.22.0", "babel-preset-env": "1.3.3", "babel-preset-react": "6.24.1", From 2e7bc1074d517abea8d9bb5a4db7f800b2293a38 Mon Sep 17 00:00:00 2001 From: spencer <spencer.bigum@gmail.com> Date: Sun, 30 Apr 2017 16:44:24 -0400 Subject: [PATCH 10/82] Update to examples: with-redux (updated) (#1813) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * With-Redux-example-update-request Hello Next.js, I’ve added an additional example to “With-Redux” and updated some of the original code to help illustrate to less inexperienced developers how to implement Redux with Next.js. The example is a simple counter to help reinforce how the client and server renderings work together. In addition I also updated some of the redux boilerplate code to help fully demonstrate how redux can be implemented when using is with Next.js Please contact me at spencer.bigum@gmail.com for further questions or anything else you might need. Thanks, Spencer * fixed listing issues: examples/with-redux * Updated code based on @impronunciable Feedback --- examples/with-redux/README.md | 6 +++- examples/with-redux/components/AddCount.js | 35 ++++++++++++++++++++++ examples/with-redux/components/Page.js | 2 ++ examples/with-redux/pages/index.js | 18 ++++++++--- examples/with-redux/pages/other.js | 21 ++++++++----- examples/with-redux/store.js | 32 ++++++++++++++++++-- 6 files changed, 98 insertions(+), 16 deletions(-) create mode 100644 examples/with-redux/components/AddCount.js diff --git a/examples/with-redux/README.md b/examples/with-redux/README.md index 6b7d6759..71645417 100644 --- a/examples/with-redux/README.md +++ b/examples/with-redux/README.md @@ -28,7 +28,7 @@ now Usually splitting your app state into `pages` feels natural but sometimes you'll want to have global state for your app. This is an example on how you can use redux that also works with our universal rendering approach. This is just a way you can do it but it's not the only one. -In this example we are going to display a digital clock that updates every second. The first render is happening in the server and then the browser will take over. To illustrate this, the server rendered clock will have a different background color than the client one. +In the first example we are going to display a digital clock that updates every second. The first render is happening in the server and then the browser will take over. To illustrate this, the server rendered clock will have a different background color than the client one. ![](http://i.imgur.com/JCxtWSj.gif) @@ -43,3 +43,7 @@ To pass the initial state from the server to the client we pass it as a prop cal The trick here for supporting universal redux is to separate the cases for the client and the server. When we are on the server we want to create a new store every time, otherwise different users data will be mixed up. If we are in the client we want to use always the same store. That's what we accomplish on `store.js` The clock, under `components/Clock.js`, has access to the state using the `connect` function from `react-redux`. In this case Clock is a direct child from the page but it could be deep down the render tree. + +The second example, under `components/AddCount.js`, shows a simple add counter function with a class component implementing a common redux pattern of mapping state and props. Again, the first render is happening in the server and instead of starting the count at 0, it will dispatch an action in redux that starts the count at 1. This continues to highlight how each navigation triggers a server render first and then a client render second, when you navigate between pages. + +For simplicity and readability, Reducers, Actions, and Store creators are all in the same file: `store.js` diff --git a/examples/with-redux/components/AddCount.js b/examples/with-redux/components/AddCount.js new file mode 100644 index 00000000..2bf76f3a --- /dev/null +++ b/examples/with-redux/components/AddCount.js @@ -0,0 +1,35 @@ +import React, {Component} from 'react' +import { connect } from 'react-redux' +import { bindActionCreators } from 'redux' +import { addCount } from '../store' + +class AddCount extends Component { + add = () => { + this.props.addCount() + } + + render () { + const { count } = this.props + return ( + <div> + <style jsx>{` + div { + padding: 0 0 20px 0; + } + `}</style> + <h1>AddCount: <span>{count}</span></h1> + <button onClick={this.add}>Add To Count</button> + </div> + ) + } +} + +const mapStateToProps = ({ count }) => ({ count }) + +const mapDispatchToProps = (dispatch) => { + return { + addCount: bindActionCreators(addCount, dispatch) + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(AddCount) diff --git a/examples/with-redux/components/Page.js b/examples/with-redux/components/Page.js index f7941894..3532e3fb 100644 --- a/examples/with-redux/components/Page.js +++ b/examples/with-redux/components/Page.js @@ -1,12 +1,14 @@ import Link from 'next/link' import { connect } from 'react-redux' import Clock from './Clock' +import AddCount from './AddCount' export default connect(state => state)(({ title, linkTo, lastUpdate, light }) => { return ( <div> <h1>{title}</h1> <Clock lastUpdate={lastUpdate} light={light} /> + <AddCount /> <nav> <Link href={linkTo}><a>Navigate</a></Link> </nav> diff --git a/examples/with-redux/pages/index.js b/examples/with-redux/pages/index.js index 0663cfb7..be66747b 100644 --- a/examples/with-redux/pages/index.js +++ b/examples/with-redux/pages/index.js @@ -1,16 +1,19 @@ import React from 'react' -import { initStore, startClock } from '../store' +import { bindActionCreators } from 'redux' +import { initStore, startClock, addCount, serverRenderClock } from '../store' import withRedux from 'next-redux-wrapper' import Page from '../components/Page' class Counter extends React.Component { static getInitialProps ({ store, isServer }) { - store.dispatch({ type: 'TICK', light: !isServer, ts: Date.now() }) + store.dispatch(serverRenderClock(isServer)) + store.dispatch(addCount()) + return { isServer } } componentDidMount () { - this.timer = this.props.dispatch(startClock()) + this.timer = this.props.startClock() } componentWillUnmount () { @@ -24,4 +27,11 @@ class Counter extends React.Component { } } -export default withRedux(initStore)(Counter) +const mapDispatchToProps = (dispatch) => { + return { + addCount: bindActionCreators(addCount, dispatch), + startClock: bindActionCreators(startClock, dispatch) + } +} + +export default withRedux(initStore, null, mapDispatchToProps)(Counter) diff --git a/examples/with-redux/pages/other.js b/examples/with-redux/pages/other.js index 8152dd13..26bfa708 100644 --- a/examples/with-redux/pages/other.js +++ b/examples/with-redux/pages/other.js @@ -1,20 +1,18 @@ import React from 'react' -import { initStore, startClock } from '../store' +import { bindActionCreators } from 'redux' +import { initStore, startClock, addCount, serverRenderClock } from '../store' import withRedux from 'next-redux-wrapper' import Page from '../components/Page' class Counter extends React.Component { static getInitialProps ({ store, isServer }) { - store.dispatch({ type: 'TICK', light: !isServer, ts: Date.now() }) + store.dispatch(serverRenderClock(isServer)) + store.dispatch(addCount()) return { isServer } } componentDidMount () { - this.timer = this.props.dispatch(startClock()) - } - - componentWillUnmount () { - clearInterval(this.timer) + this.timer = this.props.startClock() } render () { @@ -24,4 +22,11 @@ class Counter extends React.Component { } } -export default withRedux(initStore)(Counter) +const mapDispatchToProps = (dispatch) => { + return { + addCount: bindActionCreators(addCount, dispatch), + startClock: bindActionCreators(startClock, dispatch) + } +} + +export default withRedux(initStore, null, mapDispatchToProps)(Counter) diff --git a/examples/with-redux/store.js b/examples/with-redux/store.js index a15a9f81..71ab2d5e 100644 --- a/examples/with-redux/store.js +++ b/examples/with-redux/store.js @@ -1,17 +1,43 @@ import { createStore, applyMiddleware } from 'redux' import thunkMiddleware from 'redux-thunk' -export const reducer = (state = { lastUpdate: 0, light: false }, action) => { +const exampleInitialState = { + lastUpdate: 0, + light: false, + count: 0 +} + +export const actionTypes = { + ADD: 'ADD', + TICK: 'TICK' +} + +// REDUCERS +export const reducer = (state = exampleInitialState, action) => { switch (action.type) { - case 'TICK': return { lastUpdate: action.ts, light: !!action.light } + case actionTypes.TICK: + return Object.assign({}, state, { lastUpdate: action.ts, light: !!action.light }) + case actionTypes.ADD: + return Object.assign({}, state, { + count: state.count + 1 + }) default: return state } } +// ACTIONS +export const serverRenderClock = (isServer) => dispatch => { + return dispatch({ type: actionTypes.TICK, light: !isServer, ts: Date.now() }) +} + export const startClock = () => dispatch => { return setInterval(() => dispatch({ type: 'TICK', light: true, ts: Date.now() }), 800) } -export const initStore = (initialState) => { +export const addCount = () => dispatch => { + return dispatch({ type: actionTypes.ADD }) +} + +export const initStore = (initialState = exampleInitialState) => { return createStore(reducer, initialState, applyMiddleware(thunkMiddleware)) } From f578089d05150c9e2fa58068ed23906bac099b35 Mon Sep 17 00:00:00 2001 From: Arunoda Susiripala <arunoda.susiripala@gmail.com> Date: Mon, 1 May 2017 16:26:18 -0700 Subject: [PATCH 11/82] Fix page loader page normalization issue (#1844) * Add integration tests for nested componentDidMount * Fix the page loader normalization issue. * Fix a typo in the url. --- lib/page-loader.js | 3 ++- test/integration/basic/lib/cdm.js | 19 ++++++++++++++ .../basic/pages/nested-cdm/index.js | 2 ++ test/integration/basic/pages/with-cdm.js | 2 ++ .../basic/test/client-navigation.js | 26 +++++++++++++++++++ test/integration/basic/test/index.test.js | 5 +++- 6 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 test/integration/basic/lib/cdm.js create mode 100644 test/integration/basic/pages/nested-cdm/index.js create mode 100644 test/integration/basic/pages/with-cdm.js diff --git a/lib/page-loader.js b/lib/page-loader.js index 6ec0c2bc..8a47076f 100644 --- a/lib/page-loader.js +++ b/lib/page-loader.js @@ -19,7 +19,8 @@ export default class PageLoader { throw new Error('Route name should start with a "/"') } - return route.replace(/index$/, '') + if (route === '/') return route + return route.replace(/index$/, '').replace(/\/$/, '') } loadPage (route) { diff --git a/test/integration/basic/lib/cdm.js b/test/integration/basic/lib/cdm.js new file mode 100644 index 00000000..773e705e --- /dev/null +++ b/test/integration/basic/lib/cdm.js @@ -0,0 +1,19 @@ +import React, {Component} from 'react' + +export default class extends Component { + constructor (props) { + super(props) + + this.state = { + mounted: false + } + } + + componentDidMount () { + this.setState({mounted: true}) + } + + render () { + return <p>ComponentDidMount {this.state.mounted ? 'executed on client' : 'not executed'}.</p> + } +} diff --git a/test/integration/basic/pages/nested-cdm/index.js b/test/integration/basic/pages/nested-cdm/index.js new file mode 100644 index 00000000..3613e758 --- /dev/null +++ b/test/integration/basic/pages/nested-cdm/index.js @@ -0,0 +1,2 @@ +import CDM from '../../lib/cdm' +export default CDM diff --git a/test/integration/basic/pages/with-cdm.js b/test/integration/basic/pages/with-cdm.js new file mode 100644 index 00000000..b6724fea --- /dev/null +++ b/test/integration/basic/pages/with-cdm.js @@ -0,0 +1,2 @@ +import CDM from '../lib/cdm' +export default CDM diff --git a/test/integration/basic/test/client-navigation.js b/test/integration/basic/test/client-navigation.js index 2f4a187f..b33d8be6 100644 --- a/test/integration/basic/test/client-navigation.js +++ b/test/integration/basic/test/client-navigation.js @@ -321,5 +321,31 @@ export default (context, render) => { browser.close() }) }) + + describe('with different types of urls', () => { + it('on normal page', async () => { + const browser = await webdriver(context.appPort, '/with-cdm') + const text = await browser.elementByCss('p').text() + + expect(text).toBe('ComponentDidMount executed on client.') + browser.close() + }) + + it('on dir/index page ', async () => { + const browser = await webdriver(context.appPort, '/nested-cdm/index') + const text = await browser.elementByCss('p').text() + + expect(text).toBe('ComponentDidMount executed on client.') + browser.close() + }) + + it('on dir/ page ', async () => { + const browser = await webdriver(context.appPort, '/nested-cdm/') + const text = await browser.elementByCss('p').text() + + expect(text).toBe('ComponentDidMount executed on client.') + browser.close() + }) + }) }) } diff --git a/test/integration/basic/test/index.test.js b/test/integration/basic/test/index.test.js index d7a7d5a1..8ece248a 100644 --- a/test/integration/basic/test/index.test.js +++ b/test/integration/basic/test/index.test.js @@ -42,6 +42,7 @@ describe('Basic Features', () => { renderViaHTTP(context.appPort, '/stateful'), renderViaHTTP(context.appPort, '/stateless'), renderViaHTTP(context.appPort, '/styled-jsx'), + renderViaHTTP(context.appPort, '/with-cdm'), renderViaHTTP(context.appPort, '/nav'), renderViaHTTP(context.appPort, '/nav/about'), @@ -49,7 +50,9 @@ describe('Basic Features', () => { renderViaHTTP(context.appPort, '/nav/self-reload'), renderViaHTTP(context.appPort, '/nav/hash-changes'), renderViaHTTP(context.appPort, '/nav/shallow-routing'), - renderViaHTTP(context.appPort, '/nav/redirect') + renderViaHTTP(context.appPort, '/nav/redirect'), + + renderViaHTTP(context.appPort, '/nested-cdm/index') ]) }) afterAll(() => stopApp(context.server)) From 605e739f97cd7d43b9790fdb94674f0b73d8be99 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com> Date: Mon, 1 May 2017 16:29:55 -0700 Subject: [PATCH 12/82] fix(package): update babel-plugin-transform-react-remove-prop-types to version 0.4.4 (#1845) https://greenkeeper.io/ --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 205c20e7..dd76227f 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "babel-plugin-transform-es2015-modules-commonjs": "6.24.1", "babel-plugin-transform-object-rest-spread": "6.22.0", "babel-plugin-transform-react-jsx-source": "6.22.0", - "babel-plugin-transform-react-remove-prop-types": "0.4.2", + "babel-plugin-transform-react-remove-prop-types": "0.4.4", "babel-plugin-transform-runtime": "6.22.0", "babel-preset-env": "1.3.3", "babel-preset-react": "6.24.1", From cb635dd9a55aa1ddbf83170b1364372e45636048 Mon Sep 17 00:00:00 2001 From: Dieter Luypaert <dieterluypaert@gmail.com> Date: Tue, 2 May 2017 02:42:01 +0200 Subject: [PATCH 13/82] use configured distDir where required (#1816) --- server/index.js | 2 +- server/render.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/server/index.js b/server/index.js index ffa59e64..687091f7 100644 --- a/server/index.js +++ b/server/index.js @@ -131,7 +131,7 @@ export default class Server { return await renderScriptError(req, res, '/_error', error, customFields, this.renderOpts) } - const p = join(this.dir, '.next/bundles/pages/_error.js') + const p = join(this.dir, `${this.dist}/bundles/pages/_error.js`) await this.serveStatic(req, res, p) }, diff --git a/server/render.js b/server/render.js index 60c0a89b..9678993b 100644 --- a/server/render.js +++ b/server/render.js @@ -109,7 +109,8 @@ async function doRender (req, res, pathname, query, { export async function renderScript (req, res, page, opts) { try { - const path = join(opts.dir, '.next', 'bundles', 'pages', page) + const dist = getConfig(opts.dir).distDir + const path = join(opts.dir, dist, 'bundles', 'pages', page) const realPath = await resolvePath(path) await serveStatic(req, res, realPath) } catch (err) { From d1b61afcf803ba664f09fc5dccee83fe9b85ea53 Mon Sep 17 00:00:00 2001 From: David Madner <david.madner@gmx.net> Date: Tue, 2 May 2017 18:12:24 +0200 Subject: [PATCH 14/82] Update README.md (#1851) --- examples/with-redux/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/with-redux/README.md b/examples/with-redux/README.md index 71645417..d0da0e4c 100644 --- a/examples/with-redux/README.md +++ b/examples/with-redux/README.md @@ -32,7 +32,7 @@ In the first example we are going to display a digital clock that updates every ![](http://i.imgur.com/JCxtWSj.gif) -Our page is located at `pages/index.js` so it will map the route `/`. To get the initial data for rendering we are implementing the static method `getInitialProps`, initializing the redux store and dispatching the required actions until we are ready to return the initial state to be rendered. Since the component is wrapped with `next-react-wrapper`, the component is automatically connected to Redux and wrapped with `react-redux Provider`, that allows us to access redux state immediately and send the store down to children components so they can access to the state when required. +Our page is located at `pages/index.js` so it will map the route `/`. To get the initial data for rendering we are implementing the static method `getInitialProps`, initializing the redux store and dispatching the required actions until we are ready to return the initial state to be rendered. Since the component is wrapped with `next-redux-wrapper`, the component is automatically connected to Redux and wrapped with `react-redux Provider`, that allows us to access redux state immediately and send the store down to children components so they can access to the state when required. For safety it is recommended to wrap all pages, no matter if they use Redux or not, so that you should not care about it anymore in all child components. From 87773b98dc08391d023898aea6413d922e80c89b Mon Sep 17 00:00:00 2001 From: Luke Edwards <luke.edwards05@gmail.com> Date: Tue, 2 May 2017 18:27:18 -0700 Subject: [PATCH 15/82] add react production aliases (#1855) --- server/build/webpack.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/server/build/webpack.js b/server/build/webpack.js index 40d44433..85ecd8fa 100644 --- a/server/build/webpack.js +++ b/server/build/webpack.js @@ -298,6 +298,14 @@ export default async function createCompiler (dir, { dev = false, quiet = false, performance: { hints: false } } + if (!dev) { + webpackConfig.resolve.alias = { + 'react': require.resolve('react/dist/react.min.js'), + 'react-dom': require.resolve('react-dom/dist/react-dom.min.js'), + 'react-dom/server': require.resolve('react-dom/dist/react-dom-server.min.js') + } + } + if (config.webpack) { console.log('> Using "webpack" config function defined in next.config.js.') webpackConfig = await config.webpack(webpackConfig, { dev }) From 6e89d49f996dcb0cdab3011c37fc7714f0ab8ec6 Mon Sep 17 00:00:00 2001 From: jascha ehrenreich <jascha@jaeh.at> Date: Wed, 3 May 2017 06:06:33 +0200 Subject: [PATCH 16/82] fix typo (#1856) --- examples/with-pretty-url-routing/pages/greeting.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/with-pretty-url-routing/pages/greeting.js b/examples/with-pretty-url-routing/pages/greeting.js index 03b9d4fb..b900599a 100644 --- a/examples/with-pretty-url-routing/pages/greeting.js +++ b/examples/with-pretty-url-routing/pages/greeting.js @@ -8,7 +8,7 @@ export default class GreetingPage extends React.Component { return {lang, name} } - renderSwitchLangageLink () { + renderSwitchLanguageLink () { const {lang, name} = this.props const switchLang = lang === 'fr' ? 'en' : 'fr' return ( @@ -23,7 +23,7 @@ export default class GreetingPage extends React.Component { return ( <div> <h1>{lang === 'fr' ? 'Bonjour' : 'Hello'} {name}</h1> - <div>{this.renderSwitchLangageLink()}</div> + <div>{this.renderSwitchLanguageLink()}</div> </div> ) } From 24f3f143a687ebb365c828a7ee72968a35c23594 Mon Sep 17 00:00:00 2001 From: Arunoda Susiripala <arunoda.susiripala@gmail.com> Date: Wed, 3 May 2017 09:40:09 -0700 Subject: [PATCH 17/82] Introduce "asPath" into router and getInitialProps (#1857) * Add asPath to next/router and getInitialProps context. * Add test cases. * Update docs. * Build as-path pages before they use. --- client/index.js | 10 +++-- lib/router/index.js | 2 +- lib/router/router.js | 10 ++--- readme.md | 2 + server/render.js | 3 +- .../basic/pages/nav/as-path-using-router.js | 22 +++++++++++ test/integration/basic/pages/nav/as-path.js | 15 +++++++ test/integration/basic/pages/nav/index.js | 3 ++ .../basic/test/client-navigation.js | 39 +++++++++++++++++++ test/integration/basic/test/index.test.js | 2 + test/integration/basic/test/rendering.js | 9 ++++- test/lib/next-test-utils.js | 3 +- 12 files changed, 106 insertions(+), 14 deletions(-) create mode 100644 test/integration/basic/pages/nav/as-path-using-router.js create mode 100644 test/integration/basic/pages/nav/as-path.js diff --git a/client/index.js b/client/index.js index 55f9e052..0a08779c 100644 --- a/client/index.js +++ b/client/index.js @@ -29,6 +29,8 @@ const { location } = window +const asPath = getURL() + const pageLoader = new PageLoader(buildId, assetPrefix) window.__NEXT_LOADED_PAGES__.forEach(({ route, fn }) => { pageLoader.registerPage(route, fn) @@ -56,7 +58,7 @@ export default async () => { Component = ErrorComponent } - router = createRouter(pathname, query, getURL(), { + router = createRouter(pathname, query, asPath, { pageLoader, Component, ErrorComponent, @@ -107,7 +109,7 @@ export async function renderError (error) { console.error(errorMessage) if (prod) { - const initProps = { err: error, pathname, query } + const initProps = { err: error, pathname, query, asPath } const props = await loadGetInitialProps(ErrorComponent, initProps) ReactDOM.render(createElement(ErrorComponent, props), errorContainer) } else { @@ -120,8 +122,8 @@ async function doRender ({ Component, props, hash, err, emitter }) { Component !== ErrorComponent && lastAppProps.Component === ErrorComponent) { // fetch props if ErrorComponent was replaced with a page component by HMR - const { pathname, query } = router - props = await loadGetInitialProps(Component, { err, pathname, query }) + const { pathname, query, asPath } = router + props = await loadGetInitialProps(Component, { err, pathname, query, asPath }) } if (emitter) { diff --git a/lib/router/index.js b/lib/router/index.js index faec82cc..1efaf3e9 100644 --- a/lib/router/index.js +++ b/lib/router/index.js @@ -13,7 +13,7 @@ const SingletonRouter = { } // Create public properties and methods of the router in the SingletonRouter -const propertyFields = ['components', 'pathname', 'route', 'query'] +const propertyFields = ['components', 'pathname', 'route', 'query', 'asPath'] const coreMethodFields = ['push', 'replace', 'reload', 'back', 'prefetch'] const routerEvents = ['routeChangeStart', 'beforeHistoryChange', 'routeChangeComplete', 'routeChangeError'] diff --git a/lib/router/router.js b/lib/router/router.js index 8b1a4263..3fde1c98 100644 --- a/lib/router/router.js +++ b/lib/router/router.js @@ -27,7 +27,7 @@ export default class Router { this.ErrorComponent = ErrorComponent this.pathname = pathname this.query = query - this.as = as + this.asPath = as this.subscriptions = new Set() this.componentLoadCancel = null this.onPopState = this.onPopState.bind(this) @@ -190,7 +190,7 @@ export default class Router { } const { Component } = routeInfo - const ctx = { pathname, query } + const ctx = { pathname, query, asPath: as } routeInfo.props = await this.getInitialProps(Component, ctx) this.components[route] = routeInfo @@ -229,13 +229,13 @@ export default class Router { this.route = route this.pathname = pathname this.query = query - this.as = as + this.asPath = as this.notify(data) } onlyAHashChange (as) { - if (!this.as) return false - const [ oldUrlNoHash ] = this.as.split('#') + if (!this.asPath) return false + const [ oldUrlNoHash ] = this.asPath.split('#') const [ newUrlNoHash, newHash ] = as.split('#') // If the urls are change, there's more than a hash change diff --git a/readme.md b/readme.md index 8760c6ef..a540ff23 100644 --- a/readme.md +++ b/readme.md @@ -238,6 +238,7 @@ export default Page - `pathname` - path section of URL - `query` - query string section of URL parsed as an object +- `asPath` - the actual url path - `req` - HTTP request object (server only) - `res` - HTTP response object (server only) - `jsonPageRes` - [Fetch Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) object (client only) @@ -283,6 +284,7 @@ Each top-level component receives a `url` property with the following API: - `pathname` - `String` of the current path excluding the query string - `query` - `Object` with the parsed query string. Defaults to `{}` +- `asPath` - `String` of the actual path (including the query) shows in the browser - `push(url, as=url)` - performs a `pushState` call with the given url - `replace(url, as=url)` - performs a `replaceState` call with the given url diff --git a/server/render.js b/server/render.js index 9678993b..75ac75a2 100644 --- a/server/render.js +++ b/server/render.js @@ -54,7 +54,8 @@ async function doRender (req, res, pathname, query, { ]) Component = Component.default || Component Document = Document.default || Document - const ctx = { err, req, res, pathname, query } + const asPath = req.url + const ctx = { err, req, res, pathname, query, asPath } const props = await loadGetInitialProps(Component, ctx) // the response might be finshed on the getinitialprops call diff --git a/test/integration/basic/pages/nav/as-path-using-router.js b/test/integration/basic/pages/nav/as-path-using-router.js new file mode 100644 index 00000000..e56634a1 --- /dev/null +++ b/test/integration/basic/pages/nav/as-path-using-router.js @@ -0,0 +1,22 @@ +import React from 'react' +import Router from 'next/router' + +export default class extends React.Component { + constructor (...args) { + super(...args) + this.state = {} + } + + componentDidMount () { + const asPath = Router.asPath + this.setState({ asPath }) + } + + render () { + return ( + <div className='as-path-content'> + {this.state.asPath} + </div> + ) + } +} diff --git a/test/integration/basic/pages/nav/as-path.js b/test/integration/basic/pages/nav/as-path.js new file mode 100644 index 00000000..03328489 --- /dev/null +++ b/test/integration/basic/pages/nav/as-path.js @@ -0,0 +1,15 @@ +import React from 'react' + +export default class extends React.Component { + static getInitialProps ({ asPath, req }) { + return { asPath } + } + + render () { + return ( + <div className='as-path-content'> + {this.props.asPath} + </div> + ) + } +} diff --git a/test/integration/basic/pages/nav/index.js b/test/integration/basic/pages/nav/index.js index f92a7cba..0a364ddf 100644 --- a/test/integration/basic/pages/nav/index.js +++ b/test/integration/basic/pages/nav/index.js @@ -35,6 +35,9 @@ export default class extends Component { <a id='query-string-link' style={linkStyle}>QueryString</a> </Link> <Link href='/nav/about' replace><a id='about-replace-link' style={linkStyle}>Replace state</a></Link> + <Link href='/nav/as-path' as='/as/path'><a id='as-path-link' style={linkStyle}>As Path</a></Link> + <Link href='/nav/as-path'><a id='as-path-link-no-as' style={linkStyle}>As Path (No as)</a></Link> + <Link href='/nav/as-path-using-router'><a id='as-path-using-router-link' style={linkStyle}>As Path (Using Router)</a></Link> <button onClick={() => this.visitQueryStringPage()} style={linkStyle} diff --git a/test/integration/basic/test/client-navigation.js b/test/integration/basic/test/client-navigation.js index b33d8be6..3b4c3539 100644 --- a/test/integration/basic/test/client-navigation.js +++ b/test/integration/basic/test/client-navigation.js @@ -347,5 +347,44 @@ export default (context, render) => { browser.close() }) }) + + describe('with asPath', () => { + describe('inside getInitialProps', () => { + it('should show the correct asPath with a Link with as prop', async () => { + const browser = await webdriver(context.appPort, '/nav/') + const asPath = await browser + .elementByCss('#as-path-link').click() + .waitForElementByCss('.as-path-content') + .elementByCss('.as-path-content').text() + + expect(asPath).toBe('/as/path') + browser.close() + }) + + it('should show the correct asPath with a Link without the as prop', async () => { + const browser = await webdriver(context.appPort, '/nav/') + const asPath = await browser + .elementByCss('#as-path-link-no-as').click() + .waitForElementByCss('.as-path-content') + .elementByCss('.as-path-content').text() + + expect(asPath).toBe('/nav/as-path') + browser.close() + }) + }) + + describe('with next/router', () => { + it('should show the correct asPath', async () => { + const browser = await webdriver(context.appPort, '/nav/') + const asPath = await browser + .elementByCss('#as-path-using-router-link').click() + .waitForElementByCss('.as-path-content') + .elementByCss('.as-path-content').text() + + expect(asPath).toBe('/nav/as-path-using-router') + browser.close() + }) + }) + }) }) } diff --git a/test/integration/basic/test/index.test.js b/test/integration/basic/test/index.test.js index 8ece248a..4636d676 100644 --- a/test/integration/basic/test/index.test.js +++ b/test/integration/basic/test/index.test.js @@ -51,6 +51,8 @@ describe('Basic Features', () => { renderViaHTTP(context.appPort, '/nav/hash-changes'), renderViaHTTP(context.appPort, '/nav/shallow-routing'), renderViaHTTP(context.appPort, '/nav/redirect'), + renderViaHTTP(context.appPort, '/nav/as-path'), + renderViaHTTP(context.appPort, '/nav/as-path-using-router'), renderViaHTTP(context.appPort, '/nested-cdm/index') ]) diff --git a/test/integration/basic/test/rendering.js b/test/integration/basic/test/rendering.js index 69cf619b..481b42a3 100644 --- a/test/integration/basic/test/rendering.js +++ b/test/integration/basic/test/rendering.js @@ -3,8 +3,8 @@ import cheerio from 'cheerio' export default function ({ app }, suiteName, render) { - async function get$ (path) { - const html = await render(path) + async function get$ (path, query) { + const html = await render(path, query) return cheerio.load(html) } @@ -69,6 +69,11 @@ export default function ({ app }, suiteName, render) { expect($('pre').text()).toMatch(/This is an expected error/) }) + test('asPath', async () => { + const $ = await get$('/nav/as-path', { aa: 10 }) + expect($('.as-path-content').text()).toBe('/nav/as-path?aa=10') + }) + test('error 404', async () => { const $ = await get$('/non-existent') expect($('h1').text()).toBe('404') diff --git a/test/lib/next-test-utils.js b/test/lib/next-test-utils.js index f02ec061..ca6764d6 100644 --- a/test/lib/next-test-utils.js +++ b/test/lib/next-test-utils.js @@ -11,7 +11,8 @@ export const nextBuild = build export const pkg = _pkg export function renderViaAPI (app, pathname, query = {}) { - return app.renderToHTML({}, {}, pathname, query) + const url = `${pathname}?${qs.stringify(query)}` + return app.renderToHTML({ url }, {}, pathname, query) } export function renderViaHTTP (appPort, pathname, query = {}) { From ee9dba9ea7c791d31afa48805357fe060d5872cc Mon Sep 17 00:00:00 2001 From: Arunoda Susiripala <arunoda.susiripala@gmail.com> Date: Wed, 3 May 2017 13:59:21 -0700 Subject: [PATCH 18/82] React react-dom/server minified alias. (#1862) That's simply because it has no effect since we don't run webpack on the server. And for the server, file size difference doesn't matter a lot. --- server/build/webpack.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/server/build/webpack.js b/server/build/webpack.js index 85ecd8fa..c14359fc 100644 --- a/server/build/webpack.js +++ b/server/build/webpack.js @@ -299,10 +299,11 @@ export default async function createCompiler (dir, { dev = false, quiet = false, } if (!dev) { + // We do this to use the minified version of React in production. + // This will significant file size redution when turned off uglifyjs. webpackConfig.resolve.alias = { 'react': require.resolve('react/dist/react.min.js'), - 'react-dom': require.resolve('react-dom/dist/react-dom.min.js'), - 'react-dom/server': require.resolve('react-dom/dist/react-dom-server.min.js') + 'react-dom': require.resolve('react-dom/dist/react-dom.min.js') } } From 5e393b14cd7708f772629d0a13e225c4af5350c9 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com> Date: Wed, 3 May 2017 14:08:30 -0700 Subject: [PATCH 19/82] chore(package): update fly to version 2.0.6 (#1866) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dd76227f..51778a0b 100644 --- a/package.json +++ b/package.json @@ -105,7 +105,7 @@ "chromedriver": "2.29.0", "coveralls": "2.13.1", "cross-env": "4.0.0", - "fly": "2.0.5", + "fly": "2.0.6", "fly-babel": "2.1.1", "fly-clear": "1.0.1", "fly-esnext": "2.0.1", From 383eec36049a41be9324ac08e21b03ffa9865fc5 Mon Sep 17 00:00:00 2001 From: Arunoda Susiripala <arunoda.susiripala@gmail.com> Date: Wed, 3 May 2017 15:03:39 -0700 Subject: [PATCH 20/82] We are using some divs to wrap some script tags. (#1867) We don't need them. So, this change will remove them. --- server/document.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/server/document.js b/server/document.js index c7d4108d..de7a6795 100644 --- a/server/document.js +++ b/server/document.js @@ -108,6 +108,7 @@ export class NextScript extends Component { return ( <script + key={filename} type='text/javascript' src={`${assetPrefix}/_next/${hash}/${filename}`} {...additionalProps} @@ -118,18 +119,16 @@ export class NextScript extends Component { getScripts () { const { dev } = this.context._documentProps if (dev) { - return ( - <div> - { this.getChunkScript('manifest.js') } - { this.getChunkScript('commons.js') } - { this.getChunkScript('main.js') } - </div> - ) + return [ + this.getChunkScript('manifest.js'), + this.getChunkScript('commons.js'), + this.getChunkScript('main.js') + ] } // In the production mode, we have a single asset with all the JS content. // So, we can load the script with async - return this.getChunkScript('app.js', { async: true }) + return [this.getChunkScript('app.js', { async: true })] } render () { From 9a2edfd040e7023e3f60cf5153e68679ab35151a Mon Sep 17 00:00:00 2001 From: Guillermo Rauch <rauchg@gmail.com> Date: Thu, 4 May 2017 07:22:17 -0700 Subject: [PATCH 21/82] Release 2.3.0 --- package.json | 2 +- yarn.lock | 197 +++++++++++++++++++++++++++++++-------------------- 2 files changed, 122 insertions(+), 77 deletions(-) diff --git a/package.json b/package.json index 51778a0b..d42c4de6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "2.2.0", + "version": "2.3.0", "description": "Minimalistic framework for server-rendered React applications", "main": "./dist/server/next.js", "license": "MIT", diff --git a/yarn.lock b/yarn.lock index b1162833..fb970ff4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -322,7 +322,7 @@ babel-eslint@7.2.3: babel-types "^6.23.0" babylon "^6.17.0" -babel-generator@6.24.1, babel-generator@^6.24.1: +babel-generator@6.24.1, babel-generator@^6.18.0, babel-generator@^6.24.0, babel-generator@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.24.1.tgz#e715f486c58ded25649d888944d52aa07c5d9497" dependencies: @@ -335,19 +335,6 @@ babel-generator@6.24.1, babel-generator@^6.24.1: source-map "^0.5.0" trim-right "^1.0.1" -babel-generator@^6.18.0, babel-generator@^6.24.0: - version "6.24.0" - resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.24.0.tgz#eba270a8cc4ce6e09a61be43465d7c62c1f87c56" - dependencies: - babel-messages "^6.23.0" - babel-runtime "^6.22.0" - babel-types "^6.23.0" - detect-indent "^4.0.0" - jsesc "^1.3.0" - lodash "^4.2.0" - source-map "^0.5.0" - trim-right "^1.0.1" - babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" @@ -493,13 +480,13 @@ babel-plugin-check-es2015-constants@^6.22.0: dependencies: babel-runtime "^6.22.0" -babel-plugin-istanbul@4.1.1, babel-plugin-istanbul@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.1.tgz#c12de0fc6fe42adfb16be56f1ad11e4a9782eca9" +babel-plugin-istanbul@4.1.3: + version "4.1.3" + resolved "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.3.tgz#6ee6280410dcf59c7747518c3dfd98680958f102" dependencies: find-up "^2.1.0" - istanbul-lib-instrument "^1.6.2" - test-exclude "^4.0.3" + istanbul-lib-instrument "^1.7.1" + test-exclude "^4.1.0" babel-plugin-istanbul@^3.0.0: version "3.1.2" @@ -510,6 +497,14 @@ babel-plugin-istanbul@^3.0.0: object-assign "^4.1.0" test-exclude "^3.3.0" +babel-plugin-istanbul@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.1.tgz#c12de0fc6fe42adfb16be56f1ad11e4a9782eca9" + dependencies: + find-up "^2.1.0" + istanbul-lib-instrument "^1.6.2" + test-exclude "^4.0.3" + babel-plugin-jest-hoist@^18.0.0: version "18.0.0" resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-18.0.0.tgz#4150e70ecab560e6e7344adc849498072d34e12a" @@ -659,7 +654,7 @@ babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015 babel-runtime "^6.22.0" babel-template "^6.24.1" -babel-plugin-transform-es2015-modules-commonjs@6.24.1, babel-plugin-transform-es2015-modules-commonjs@^6.24.1: +babel-plugin-transform-es2015-modules-commonjs@6.24.1, babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.24.1.tgz#d3e310b40ef664a36622200097c6d440298f2bfe" dependencies: @@ -668,15 +663,6 @@ babel-plugin-transform-es2015-modules-commonjs@6.24.1, babel-plugin-transform-es babel-template "^6.24.1" babel-types "^6.24.1" -babel-plugin-transform-es2015-modules-commonjs@^6.23.0: - version "6.24.0" - resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.24.0.tgz#e921aefb72c2cc26cb03d107626156413222134f" - dependencies: - babel-plugin-transform-strict-mode "^6.22.0" - babel-runtime "^6.22.0" - babel-template "^6.23.0" - babel-types "^6.23.0" - babel-plugin-transform-es2015-modules-systemjs@^6.23.0, babel-plugin-transform-es2015-modules-systemjs@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" @@ -802,9 +788,11 @@ babel-plugin-transform-react-jsx@^6.24.1: babel-plugin-syntax-jsx "^6.8.0" babel-runtime "^6.22.0" -babel-plugin-transform-react-remove-prop-types@0.4.1: - version "0.4.1" - resolved "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.1.tgz#50d6376d3973c6052087b274ca9bd21b8a07409a" +babel-plugin-transform-react-remove-prop-types@0.4.4: + version "0.4.4" + resolved "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.4.tgz#ef3f6fc166b0d1f53f828d1a9dda90106ac27cd8" + dependencies: + babel-traverse "^6.24.1" babel-plugin-transform-regenerator@^6.22.0, babel-plugin-transform-regenerator@^6.24.1: version "6.24.1" @@ -822,7 +810,7 @@ babel-plugin-transform-runtime@6.22.0: dependencies: babel-runtime "^6.22.0" -babel-plugin-transform-strict-mode@^6.22.0, babel-plugin-transform-strict-mode@^6.24.1: +babel-plugin-transform-strict-mode@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" dependencies: @@ -1036,7 +1024,7 @@ block-stream@*: dependencies: inherits "~2.0.0" -bluebird@^3.4.7: +bluebird@^3.4.7, bluebird@^3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c" @@ -1446,9 +1434,9 @@ cosmiconfig@^1.1.0: pinkie-promise "^2.0.0" require-from-string "^1.1.0" -coveralls@2.13.0: - version "2.13.0" - resolved "https://registry.yarnpkg.com/coveralls/-/coveralls-2.13.0.tgz#df933876e8c6f478efb04f4d3ab70dc96b7e5a8e" +coveralls@2.13.1: + version "2.13.1" + resolved "https://registry.npmjs.org/coveralls/-/coveralls-2.13.1.tgz#d70bb9acc1835ec4f063ff9dac5423c17b11f178" dependencies: js-yaml "3.6.1" lcov-parse "0.0.10" @@ -1580,13 +1568,7 @@ debug-log@^1.0.0, debug-log@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debug-log/-/debug-log-1.0.1.tgz#2307632d4c04382b8df8a32f70b895046d52745f" -debug@2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.1.tgz#79855090ba2c4e3115cc7d8769491d58f0491351" - dependencies: - ms "0.7.2" - -debug@^2.1.1, debug@^2.2.0: +debug@2.6.4, debug@^2.1.1, debug@^2.2.0, debug@^2.6.3: version "2.6.4" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.4.tgz#7586a9b3c39741c0282ae33445c4e8ac74734fe0" dependencies: @@ -2237,11 +2219,11 @@ fly-watch@1.1.1: arrify "^1.0.1" chokidar "^1.6.1" -fly@2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/fly/-/fly-2.0.5.tgz#5c204bc1740d677eb231feeffc3313d7f5e86961" +fly@2.0.6: + version "2.0.6" + resolved "https://registry.npmjs.org/fly/-/fly-2.0.6.tgz#77aa3c94e8e30ed235e06e91973f135dd55e03bd" dependencies: - bluebird "^3.4.7" + bluebird "^3.5.0" clor "^5.0.1" glob "^7.1.1" minimist "^1.2.0" @@ -2882,12 +2864,22 @@ istanbul-lib-coverage@^1.0.0, istanbul-lib-coverage@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.0.2.tgz#87a0c015b6910651cb3b184814dfb339337e25e1" +istanbul-lib-coverage@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.0.tgz#caca19decaef3525b5d6331d701f3f3b7ad48528" + istanbul-lib-hook@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.0.5.tgz#6ca3d16d60c5f4082da39f7c5cd38ea8a772b88e" dependencies: append-transform "^0.4.0" +istanbul-lib-hook@^1.0.6: + version "1.0.6" + resolved "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.0.6.tgz#c0866d1e81cf2d5319249510131fc16dee49231f" + dependencies: + append-transform "^0.4.0" + istanbul-lib-instrument@^1.1.1, istanbul-lib-instrument@^1.4.2, istanbul-lib-instrument@^1.6.2, istanbul-lib-instrument@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.7.0.tgz#b8e0dc25709bb44e17336ab47b7bb5c97c23f659" @@ -2900,6 +2892,18 @@ istanbul-lib-instrument@^1.1.1, istanbul-lib-instrument@^1.4.2, istanbul-lib-ins istanbul-lib-coverage "^1.0.2" semver "^5.3.0" +istanbul-lib-instrument@^1.7.1: + version "1.7.1" + resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.7.1.tgz#169e31bc62c778851a99439dd99c3cc12184d360" + dependencies: + babel-generator "^6.18.0" + babel-template "^6.16.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + babylon "^6.13.0" + istanbul-lib-coverage "^1.1.0" + semver "^5.3.0" + istanbul-lib-report@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.0.0.tgz#d83dac7f26566b521585569367fe84ccfc7aaecb" @@ -2909,6 +2913,15 @@ istanbul-lib-report@^1.0.0: path-parse "^1.0.5" supports-color "^3.1.2" +istanbul-lib-report@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.1.0.tgz#444c4ecca9afa93cf584f56b10f195bf768c0770" + dependencies: + istanbul-lib-coverage "^1.1.0" + mkdirp "^0.5.1" + path-parse "^1.0.5" + supports-color "^3.1.2" + istanbul-lib-source-maps@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.1.1.tgz#f8c8c2e8f2160d1d91526d97e5bd63b2079af71c" @@ -2918,12 +2931,28 @@ istanbul-lib-source-maps@^1.1.1: rimraf "^2.4.4" source-map "^0.5.3" +istanbul-lib-source-maps@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.0.tgz#8c7706d497e26feeb6af3e0c28fd5b0669598d0e" + dependencies: + debug "^2.6.3" + istanbul-lib-coverage "^1.1.0" + mkdirp "^0.5.1" + rimraf "^2.6.1" + source-map "^0.5.3" + istanbul-reports@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.0.2.tgz#4e8366abe6fa746cc1cd6633f108de12cc6ac6fa" dependencies: handlebars "^4.0.3" +istanbul-reports@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.1.0.tgz#1ef3b795889219cfb5fad16365f6ce108d5f8c66" + dependencies: + handlebars "^4.0.3" + jest-changed-files@^19.0.0: version "19.0.2" resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-19.0.2.tgz#16c54c84c3270be408e06d2e8af3f3e37a885824" @@ -3584,14 +3613,14 @@ moment@^2.11.2: version "2.18.1" resolved "https://registry.yarnpkg.com/moment/-/moment-2.18.1.tgz#c36193dd3ce1c2eed2adb7c802dbbc77a81b1c0f" -ms@0.7.2: - version "0.7.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" - ms@0.7.3: version "0.7.3" resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.3.tgz#708155a5e44e33f5fd0fc53e81d0d40a91be1fff" +ms@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/ms/-/ms-1.0.0.tgz#59adcd22edc543f7b5381862d31387b1f4bc9473" + mute-stream@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" @@ -3761,9 +3790,9 @@ number-is-nan@^1.0.0: version "1.3.9" resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.3.9.tgz#8bab486ff7fa3dfd086656bbe8b17116d3692d2a" -nyc@10.2.0: - version "10.2.0" - resolved "https://registry.yarnpkg.com/nyc/-/nyc-10.2.0.tgz#facd90240600c9aa4dd81ea99c2fb6a85c53de0c" +nyc@10.3.0: + version "10.3.0" + resolved "https://registry.npmjs.org/nyc/-/nyc-10.3.0.tgz#a7051ac03f89d17e719a586a66a84ce4bdfde857" dependencies: archy "^1.0.0" arrify "^1.0.1" @@ -3775,12 +3804,12 @@ nyc@10.2.0: find-up "^1.1.2" foreground-child "^1.5.3" glob "^7.0.6" - istanbul-lib-coverage "^1.0.2" - istanbul-lib-hook "^1.0.5" - istanbul-lib-instrument "^1.7.0" - istanbul-lib-report "^1.0.0" - istanbul-lib-source-maps "^1.1.1" - istanbul-reports "^1.0.2" + istanbul-lib-coverage "^1.1.0" + istanbul-lib-hook "^1.0.6" + istanbul-lib-instrument "^1.7.1" + istanbul-lib-report "^1.1.0" + istanbul-lib-source-maps "^1.2.0" + istanbul-reports "^1.1.0" md5-hex "^1.2.0" merge-source-map "^1.0.2" micromatch "^2.3.11" @@ -3789,9 +3818,9 @@ nyc@10.2.0: rimraf "^2.5.4" signal-exit "^3.0.1" spawn-wrap "1.2.4" - test-exclude "^4.0.0" - yargs "^7.0.2" - yargs-parser "^4.0.2" + test-exclude "^4.1.0" + yargs "^7.1.0" + yargs-parser "^5.0.0" oauth-sign@~0.8.1: version "0.8.2" @@ -4110,11 +4139,11 @@ public-encrypt@^4.0.0: parse-asn1 "^5.0.0" randombytes "^2.0.1" -punycode@1.3.2: +punycode@1.3.2, punycode@^1.2.4: version "1.3.2" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" -punycode@^1.2.4, punycode@^1.4.1: +punycode@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" @@ -4484,11 +4513,11 @@ sax@^1.2.1: version "5.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" -send@0.15.1: - version "0.15.1" - resolved "https://registry.yarnpkg.com/send/-/send-0.15.1.tgz#8a02354c26e6f5cca700065f5f0cdeba90ec7b5f" +send@0.15.2: + version "0.15.2" + resolved "https://registry.npmjs.org/send/-/send-0.15.2.tgz#f91fab4403bcf87e716f70ceb5db2f578bdc17d6" dependencies: - debug "2.6.1" + debug "2.6.4" depd "~1.1.0" destroy "~1.0.4" encodeurl "~1.0.1" @@ -4497,7 +4526,7 @@ send@0.15.1: fresh "0.5.0" http-errors "~1.6.1" mime "1.3.4" - ms "0.7.2" + ms "1.0.0" on-finished "~2.3.0" range-parser "~1.2.0" statuses "~1.3.1" @@ -4576,7 +4605,13 @@ source-list-map@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-1.1.1.tgz#1a33ac210ca144d1e561f906ebccab5669ff4cb4" -source-map-support@0.4.14, source-map-support@^0.4.2: +source-map-support@0.4.15: + version "0.4.15" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.15.tgz#03202df65c06d2bd8c7ec2362a193056fef8d3b1" + dependencies: + source-map "^0.5.6" + +source-map-support@^0.4.2: version "0.4.14" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.14.tgz#9d4463772598b86271b4f523f6c1f4e02a7d6aef" dependencies: @@ -4850,7 +4885,7 @@ test-exclude@^3.3.0: read-pkg-up "^1.0.1" require-main-filename "^1.0.1" -test-exclude@^4.0.0, test-exclude@^4.0.3: +test-exclude@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-4.0.3.tgz#86a13ce3effcc60e6c90403cf31a27a60ac6c4e7" dependencies: @@ -4860,6 +4895,16 @@ test-exclude@^4.0.0, test-exclude@^4.0.3: read-pkg-up "^1.0.1" require-main-filename "^1.0.1" +test-exclude@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/test-exclude/-/test-exclude-4.1.0.tgz#04ca70b7390dd38c98d4a003a173806ca7991c91" + dependencies: + arrify "^1.0.1" + micromatch "^2.3.11" + object-assign "^4.1.0" + read-pkg-up "^1.0.1" + require-main-filename "^1.0.1" + text-table@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -5237,7 +5282,7 @@ yallist@^2.0.0: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" -yargs-parser@^4.0.2, yargs-parser@^4.2.0: +yargs-parser@^4.2.0: version "4.2.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c" dependencies: @@ -5267,9 +5312,9 @@ yargs@^6.0.0, yargs@^6.3.0: y18n "^3.2.1" yargs-parser "^4.2.0" -yargs@^7.0.2: +yargs@^7.1.0: version "7.1.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8" + resolved "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8" dependencies: camelcase "^3.0.0" cliui "^3.2.0" From 93a1b73efed0e848efcf5342716792ca86fa13e3 Mon Sep 17 00:00:00 2001 From: "Trevor D. Miller" <trevordmiller@users.noreply.github.com> Date: Thu, 4 May 2017 11:06:58 -0600 Subject: [PATCH 22/82] Removing unneeded dev dependency (#1869) babel-jest is included automatically by jest when a babel config is present, so including it manually here doesn't do anything. > "Note: babel-jest is automatically installed when installing Jest and will automatically transform files if a babel configuration exists in your project." http://facebook.github.io/jest/docs/en/getting-started.html#using-babel --- examples/with-jest/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/with-jest/package.json b/examples/with-jest/package.json index 6614af9b..ec84a88d 100644 --- a/examples/with-jest/package.json +++ b/examples/with-jest/package.json @@ -12,7 +12,6 @@ "start": "next start" }, "devDependencies": { - "babel-jest": "^18.0.0", "enzyme": "^2.5.1", "jest-cli": "^18.0.0", "react-addons-test-utils": "^15.4.2", From 68880bc9f8b128e4ae7cb93a9e40c919adb63b0c Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com> Date: Thu, 4 May 2017 10:21:34 -0700 Subject: [PATCH 23/82] fix(package): update pkg-up to version 2.0.0 (#1876) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d42c4de6..ed765c97 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ "mv": "2.1.1", "mz": "2.6.0", "path-match": "1.2.4", - "pkg-up": "1.0.0", + "pkg-up": "2.0.0", "prop-types": "15.5.7", "react-hot-loader": "3.0.0-beta.6", "send": "0.15.2", From 0edee47d0778d5a94fd66d2f461dcfcd0a99a474 Mon Sep 17 00:00:00 2001 From: Arunoda Susiripala <arunoda.susiripala@gmail.com> Date: Thu, 4 May 2017 13:05:47 -0700 Subject: [PATCH 24/82] Fix the page-loader-normalization issue on '/index' page. (#1882) --- lib/page-loader.js | 3 ++- test/integration/basic/pages/index.js | 2 ++ .../basic/test/client-navigation.js | 22 ++++++++++++++++--- 3 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 test/integration/basic/pages/index.js diff --git a/lib/page-loader.js b/lib/page-loader.js index 8a47076f..fdfa9bd0 100644 --- a/lib/page-loader.js +++ b/lib/page-loader.js @@ -18,9 +18,10 @@ export default class PageLoader { if (route[0] !== '/') { throw new Error('Route name should start with a "/"') } + route = route.replace(/index$/, '') if (route === '/') return route - return route.replace(/index$/, '').replace(/\/$/, '') + return route.replace(/\/$/, '') } loadPage (route) { diff --git a/test/integration/basic/pages/index.js b/test/integration/basic/pages/index.js new file mode 100644 index 00000000..b6724fea --- /dev/null +++ b/test/integration/basic/pages/index.js @@ -0,0 +1,2 @@ +import CDM from '../lib/cdm' +export default CDM diff --git a/test/integration/basic/test/client-navigation.js b/test/integration/basic/test/client-navigation.js index 3b4c3539..898737d0 100644 --- a/test/integration/basic/test/client-navigation.js +++ b/test/integration/basic/test/client-navigation.js @@ -323,7 +323,7 @@ export default (context, render) => { }) describe('with different types of urls', () => { - it('on normal page', async () => { + it('should work with normal page', async () => { const browser = await webdriver(context.appPort, '/with-cdm') const text = await browser.elementByCss('p').text() @@ -331,7 +331,7 @@ export default (context, render) => { browser.close() }) - it('on dir/index page ', async () => { + it('should work with dir/index page ', async () => { const browser = await webdriver(context.appPort, '/nested-cdm/index') const text = await browser.elementByCss('p').text() @@ -339,13 +339,29 @@ export default (context, render) => { browser.close() }) - it('on dir/ page ', async () => { + it('should work with dir/ page ', async () => { const browser = await webdriver(context.appPort, '/nested-cdm/') const text = await browser.elementByCss('p').text() expect(text).toBe('ComponentDidMount executed on client.') browser.close() }) + + it('should work with /index page', async () => { + const browser = await webdriver(context.appPort, '/index') + const text = await browser.elementByCss('p').text() + + expect(text).toBe('ComponentDidMount executed on client.') + browser.close() + }) + + it('should work with / page', async () => { + const browser = await webdriver(context.appPort, '/') + const text = await browser.elementByCss('p').text() + + expect(text).toBe('ComponentDidMount executed on client.') + browser.close() + }) }) describe('with asPath', () => { From f4e6c51985466e7690c238fcc23c9894404bd362 Mon Sep 17 00:00:00 2001 From: Guillermo Rauch <rauchg@gmail.com> Date: Thu, 4 May 2017 13:06:32 -0700 Subject: [PATCH 25/82] Release 2.3.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ed765c97..8be6b35b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "2.3.0", + "version": "2.3.1", "description": "Minimalistic framework for server-rendered React applications", "main": "./dist/server/next.js", "license": "MIT", From 3fbccff9368904ef9601a5764e8bb4b82ede2e8b Mon Sep 17 00:00:00 2001 From: ateev <ateev@live.com> Date: Fri, 5 May 2017 02:14:25 +0530 Subject: [PATCH 26/82] remove elliptic precomputed folder --- server/build/webpack.js | 1 + 1 file changed, 1 insertion(+) diff --git a/server/build/webpack.js b/server/build/webpack.js index c14359fc..bd526ce0 100644 --- a/server/build/webpack.js +++ b/server/build/webpack.js @@ -74,6 +74,7 @@ export default async function createCompiler (dir, { dev = false, quiet = false, } const plugins = [ + new webpack.IgnorePlugin(/(precomputed)/, /node_modules.+(elliptic)/), new webpack.LoaderOptionsPlugin({ options: { context: dir, From 96b5e4a7cecd3604f20ded30b3a2881be2b3cafe Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com> Date: Thu, 4 May 2017 16:41:46 -0700 Subject: [PATCH 27/82] fix(package): update webpack to version 2.5.0 (#1871) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8be6b35b..dbe55c65 100644 --- a/package.json +++ b/package.json @@ -89,7 +89,7 @@ "unfetch": "2.1.2", "url": "0.11.0", "uuid": "3.0.1", - "webpack": "2.4.0", + "webpack": "2.5.0", "webpack-dev-middleware": "1.10.2", "webpack-hot-middleware": "2.18.0", "write-file-webpack-plugin": "4.0.2" From 9fb7987c6937dc226537a24d9ae76d8f56cf882f Mon Sep 17 00:00:00 2001 From: Tim de Koning <github@king-management.nl> Date: Fri, 5 May 2017 01:44:28 +0200 Subject: [PATCH 28/82] #1874 - A warning when using _document.js (#1884) --- readme.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/readme.md b/readme.md index a540ff23..e3ca4008 100644 --- a/readme.md +++ b/readme.md @@ -614,6 +614,8 @@ The `ctx` object is equivalent to the one received in all [`getInitialProps`](#f - `renderPage` (`Function`) a callback that executes the actual React rendering logic (synchronously). It's useful to decorate this function in order to support server-rendering wrappers like Aphrodite's [`renderStatic`](https://github.com/Khan/aphrodite#server-side-rendering) +__Note: React-components outside of `<Main />` will not be initialised by the browser. If you need shared components in all your pages (like a menu or a toolbar), do _not_ add application logic here, but take a look at [this example](https://github.com/zeit/next.js/tree/master/examples/layout-component).__ + ### Custom error handling 404 or 500 errors are handled both client and server side by a default component `error.js`. If you wish to override it, define a `_error.js`: From 8268905d2fac3339b6645aef894cb393b53efa91 Mon Sep 17 00:00:00 2001 From: Arunoda Susiripala <arunoda.susiripala@gmail.com> Date: Fri, 5 May 2017 23:54:47 -0700 Subject: [PATCH 29/82] Use cheap module inline source map (#1894) * Fix the page-loader-normalization issue on '/index' page. * Use cheap-module-inline-source-map as the default devtool. --- server/build/webpack.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/build/webpack.js b/server/build/webpack.js index c14359fc..ac972bd3 100644 --- a/server/build/webpack.js +++ b/server/build/webpack.js @@ -294,7 +294,7 @@ export default async function createCompiler (dir, { dev = false, quiet = false, module: { rules }, - devtool: dev ? 'inline-source-map' : false, + devtool: dev ? 'cheap-module-inline-source-map' : false, performance: { hints: false } } From 5153d6958b6cffa3e661a10a6b889f5b492ee92f Mon Sep 17 00:00:00 2001 From: Arunoda Susiripala <arunoda.susiripala@gmail.com> Date: Sat, 6 May 2017 00:07:50 -0700 Subject: [PATCH 30/82] Use development babel presets if it's we are not in production. (#1895) Otherwise, user has to expose it's env variable as development. Usually, that's unlikely to happen. --- server/build/babel/preset.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/build/babel/preset.js b/server/build/babel/preset.js index dd391359..129c2e85 100644 --- a/server/build/babel/preset.js +++ b/server/build/babel/preset.js @@ -9,7 +9,7 @@ const envPlugins = { ] } -const plugins = envPlugins[process.env.NODE_ENV] || [] +const plugins = envPlugins[process.env.NODE_ENV] || envPlugins['development'] module.exports = { presets: [ From 6ca1feaf98b2df0a700327b85609bdcb0fc6c51d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20Marohni=C4=87?= <matija.marohnic@gmail.com> Date: Sat, 6 May 2017 20:31:42 +0200 Subject: [PATCH 31/82] Add link to the Glamorous example (#1887) --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index e3ca4008..564411f7 100644 --- a/readme.md +++ b/readme.md @@ -139,7 +139,7 @@ export default () => ( <summary> <b>Examples</b> </summary> - <ul><li><a href="./examples/with-styled-components">Styled components</a></li><li><a href="./examples/with-styletron">Styletron</a></li><li><a href="./examples/with-glamor">Glamor</a></li><li><a href="./examples/with-cxs">Cxs</a></li><li><a href="./examples/with-aphrodite">Aphrodite</a></li><li><a href="./examples/with-fela">Fela</a></li></ul> + <ul><li><a href="./examples/with-styled-components">Styled components</a></li><li><a href="./examples/with-styletron">Styletron</a></li><li><a href="./examples/with-glamor">Glamor</a></li><li><a href="./examples/with-glamorous">Glamorous</a></li><li><a href="./examples/with-cxs">Cxs</a></li><li><a href="./examples/with-aphrodite">Aphrodite</a></li><li><a href="./examples/with-fela">Fela</a></li></ul> </details></p> It's possible to use any existing CSS-in-JS solution. The simplest one is inline styles: From 0abfca26f741ca78d2a60eed163ab7246a37183f Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" <greenkeeper[bot]@users.noreply.github.com> Date: Sat, 6 May 2017 20:31:56 +0200 Subject: [PATCH 32/82] chore(package): update nyc to version 10.3.2 (#1889) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dbe55c65..d977490f 100644 --- a/package.json +++ b/package.json @@ -115,7 +115,7 @@ "lint-staged": "^3.4.0", "node-fetch": "1.6.3", "node-notifier": "5.1.2", - "nyc": "10.3.0", + "nyc": "10.3.2", "react": "15.5.3", "react-dom": "15.5.3", "standard": "9.0.2", From 23574b5489752f3930bca56c2e8cda7654d28e6c Mon Sep 17 00:00:00 2001 From: Arana Jhonny <jhonnyjosearana@gmail.com> Date: Sat, 6 May 2017 14:37:47 -0400 Subject: [PATCH 33/82] Support for cxs rehydration and removal of duplicate styles. (#1860) * add cxs.rehydrate. * add id='cxs-style'. --- examples/with-cxs/pages/_document.js | 4 ++-- examples/with-cxs/pages/index.js | 10 +++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/examples/with-cxs/pages/_document.js b/examples/with-cxs/pages/_document.js index 9b2a7f46..47a8e4be 100644 --- a/examples/with-cxs/pages/_document.js +++ b/examples/with-cxs/pages/_document.js @@ -1,5 +1,5 @@ import Document, { Head, Main, NextScript } from 'next/document' -import cxs from 'cxs' +import cxs from 'cxs/lite' export default class MyDocument extends Document { static async getInitialProps ({ renderPage }) { @@ -13,7 +13,7 @@ export default class MyDocument extends Document { <html> <Head> <title>My page - + +) From 7c8d0246e2f9eccd43138ef48b7f8a20a772a57a Mon Sep 17 00:00:00 2001 From: Grokling Date: Wed, 10 May 2017 10:33:39 +1200 Subject: [PATCH 53/82] Add rehydration to example/aphrodite (#1858) * Add rehydration to example/aphrodite * linting * replaced yarn.lock --- examples/with-aphrodite/pages/_document.js | 20 ++- examples/with-aphrodite/pages/index.js | 7 + yarn.lock | 192 +++++++++++---------- 3 files changed, 127 insertions(+), 92 deletions(-) diff --git a/examples/with-aphrodite/pages/_document.js b/examples/with-aphrodite/pages/_document.js index a4f6cda2..682000bc 100644 --- a/examples/with-aphrodite/pages/_document.js +++ b/examples/with-aphrodite/pages/_document.js @@ -4,15 +4,31 @@ import { StyleSheetServer } from 'aphrodite' export default class MyDocument extends Document { static async getInitialProps ({ renderPage }) { const { html, css } = StyleSheetServer.renderStatic(() => renderPage()) - return { ...html, css } + const ids = css.renderedClassNames + return { ...html, css, ids } + } + + constructor (props) { + super(props) + /* Take the renderedClassNames from aphrodite (as generated + in getInitialProps) and assign them to __NEXT_DATA__ so that they + are accessible to the client for rehydration. */ + const { __NEXT_DATA__, ids } = props + if (ids) { + __NEXT_DATA__.ids = this.props.ids + } } render () { + /* Make sure to use data-aphrodite attribute in the style tag here + so that aphrodite knows which style tag it's in control of when + the client goes to render styles. If you don't you'll get a second + + ) ``` +Please see the [styled-jsx documentation](https://github.com/zeit/styled-jsx) for more examples. + #### CSS-in-JS

From f4d6cbfc197e1b8d1674e10a9821ba5387cc2032 Mon Sep 17 00:00:00 2001 From: Roland Warmerdam Date: Wed, 10 May 2017 15:23:11 -0700 Subject: [PATCH 61/82] Many improvements to the Apollo examples (#1905) * Many improvements to the Apollo examples * Use static properties --- .../with-apollo-and-redux/lib/initApollo.js | 36 +++++++++ .../with-apollo-and-redux/lib/initClient.js | 28 ------- .../with-apollo-and-redux/lib/initRedux.js | 39 ++++++++++ .../with-apollo-and-redux/lib/initStore.js | 18 ----- .../with-apollo-and-redux/lib/middleware.js | 9 --- examples/with-apollo-and-redux/lib/reducer.js | 7 -- .../with-apollo-and-redux/lib/reducers.js | 12 +++ .../with-apollo-and-redux/lib/withData.js | 75 ++++++++++++------- examples/with-apollo-and-redux/package.json | 11 ++- examples/with-apollo/lib/initApollo.js | 37 +++++++++ examples/with-apollo/lib/initClient.js | 28 ------- examples/with-apollo/lib/withData.js | 60 +++++++++------ examples/with-apollo/package.json | 11 ++- 13 files changed, 223 insertions(+), 148 deletions(-) create mode 100644 examples/with-apollo-and-redux/lib/initApollo.js delete mode 100644 examples/with-apollo-and-redux/lib/initClient.js create mode 100644 examples/with-apollo-and-redux/lib/initRedux.js delete mode 100644 examples/with-apollo-and-redux/lib/initStore.js delete mode 100644 examples/with-apollo-and-redux/lib/middleware.js delete mode 100644 examples/with-apollo-and-redux/lib/reducer.js create mode 100644 examples/with-apollo-and-redux/lib/reducers.js create mode 100644 examples/with-apollo/lib/initApollo.js delete mode 100644 examples/with-apollo/lib/initClient.js diff --git a/examples/with-apollo-and-redux/lib/initApollo.js b/examples/with-apollo-and-redux/lib/initApollo.js new file mode 100644 index 00000000..d7f8c199 --- /dev/null +++ b/examples/with-apollo-and-redux/lib/initApollo.js @@ -0,0 +1,36 @@ +import { ApolloClient, createNetworkInterface } from 'react-apollo' +import fetch from 'isomorphic-fetch' + +let apolloClient = null + +// Polyfill fetch() on the server (used by apollo-client) +if (!process.browser) { + global.fetch = fetch +} + +function create () { + return new ApolloClient({ + ssrMode: !process.browser, // Disables forceFetch on the server (so queries are only run once) + networkInterface: createNetworkInterface({ + uri: 'https://api.graph.cool/simple/v1/cixmkt2ul01q00122mksg82pn', // Server URL (must be absolute) + opts: { // Additional fetch() options like `credentials` or `headers` + credentials: 'same-origin' + } + }) + }) +} + +export default function initApollo () { + // Make sure to create a new client for every server-side request so that data + // isn't shared between connections (which would be bad) + if (!process.browser) { + return create() + } + + // Reuse client on the client-side + if (!apolloClient) { + apolloClient = create() + } + + return apolloClient +} diff --git a/examples/with-apollo-and-redux/lib/initClient.js b/examples/with-apollo-and-redux/lib/initClient.js deleted file mode 100644 index 31f590f3..00000000 --- a/examples/with-apollo-and-redux/lib/initClient.js +++ /dev/null @@ -1,28 +0,0 @@ -import { ApolloClient, createNetworkInterface } from 'react-apollo' - -let apolloClient = null - -function _initClient (headers, initialState) { - return new ApolloClient({ - initialState, - ssrMode: !process.browser, - dataIdFromObject: result => result.id || null, - networkInterface: createNetworkInterface({ - uri: 'https://api.graph.cool/simple/v1/cixmkt2ul01q00122mksg82pn', - opts: { - credentials: 'same-origin' - // Pass headers here if your graphql server requires them - } - }) - }) -} - -export const initClient = (headers, initialState = {}) => { - if (!process.browser) { - return _initClient(headers, initialState) - } - if (!apolloClient) { - apolloClient = _initClient(headers, initialState) - } - return apolloClient -} diff --git a/examples/with-apollo-and-redux/lib/initRedux.js b/examples/with-apollo-and-redux/lib/initRedux.js new file mode 100644 index 00000000..28f880c7 --- /dev/null +++ b/examples/with-apollo-and-redux/lib/initRedux.js @@ -0,0 +1,39 @@ +import { createStore, combineReducers, applyMiddleware, compose } from 'redux' +import reducers from './reducers' + +let reduxStore = null + +// Get the Redux DevTools extension and fallback to a no-op function +let devtools = f => f +if (process.browser && window.__REDUX_DEVTOOLS_EXTENSION__) { + devtools = window.__REDUX_DEVTOOLS_EXTENSION__() +} + +function create (apollo, initialState = {}) { + return createStore( + combineReducers({ // Setup reducers + ...reducers, + apollo: apollo.reducer() + }), + initialState, // Hydrate the store with server-side data + compose( + applyMiddleware(apollo.middleware()), // Add additional middleware here + devtools + ) + ) +} + +export default function initRedux (apollo, initialState) { + // Make sure to create a new store for every server-side request so that data + // isn't shared between connections (which would be bad) + if (!process.browser) { + return create(apollo, initialState) + } + + // Reuse store on the client-side + if (!reduxStore) { + reduxStore = create(apollo, initialState) + } + + return reduxStore +} diff --git a/examples/with-apollo-and-redux/lib/initStore.js b/examples/with-apollo-and-redux/lib/initStore.js deleted file mode 100644 index 7c95b51f..00000000 --- a/examples/with-apollo-and-redux/lib/initStore.js +++ /dev/null @@ -1,18 +0,0 @@ -import { createStore } from 'redux' -import getReducer from './reducer' -import createMiddleware from './middleware' - -let reduxStore = null - -export const initStore = (client, initialState) => { - let store - if (!process.browser || !reduxStore) { - const middleware = createMiddleware(client.middleware()) - store = createStore(getReducer(client), initialState, middleware) - if (!process.browser) { - return store - } - reduxStore = store - } - return reduxStore -} diff --git a/examples/with-apollo-and-redux/lib/middleware.js b/examples/with-apollo-and-redux/lib/middleware.js deleted file mode 100644 index 1ff86a58..00000000 --- a/examples/with-apollo-and-redux/lib/middleware.js +++ /dev/null @@ -1,9 +0,0 @@ -import { applyMiddleware, compose } from 'redux' - -export default function createMiddleware (clientMiddleware) { - const middleware = applyMiddleware(clientMiddleware) - if (process.browser && window.devToolsExtension) { - return compose(middleware, window.devToolsExtension()) - } - return middleware -} diff --git a/examples/with-apollo-and-redux/lib/reducer.js b/examples/with-apollo-and-redux/lib/reducer.js deleted file mode 100644 index 95434891..00000000 --- a/examples/with-apollo-and-redux/lib/reducer.js +++ /dev/null @@ -1,7 +0,0 @@ -import { combineReducers } from 'redux' - -export default function getReducer (client) { - return combineReducers({ - apollo: client.reducer() - }) -} diff --git a/examples/with-apollo-and-redux/lib/reducers.js b/examples/with-apollo-and-redux/lib/reducers.js new file mode 100644 index 00000000..e22542ed --- /dev/null +++ b/examples/with-apollo-and-redux/lib/reducers.js @@ -0,0 +1,12 @@ +export default { + example: (state = {}, { type, payload }) => { + switch (type) { + case 'EXAMPLE_ACTION': + return { + ...state + } + default: + return state + } + } +} diff --git a/examples/with-apollo-and-redux/lib/withData.js b/examples/with-apollo-and-redux/lib/withData.js index 206fdf80..1c08274b 100644 --- a/examples/with-apollo-and-redux/lib/withData.js +++ b/examples/with-apollo-and-redux/lib/withData.js @@ -1,56 +1,75 @@ -import 'isomorphic-fetch' import React from 'react' +import PropTypes from 'prop-types' import { ApolloProvider, getDataFromTree } from 'react-apollo' -import { initClient } from './initClient' -import { initStore } from './initStore' +import initApollo from './initApollo' +import initRedux from './initRedux' + +export default ComposedComponent => { + return class WithData extends React.Component { + static displayName = `WithData(${ComposedComponent.displayName})` + static propTypes = { + serverState: PropTypes.object.isRequired + } -export default (Component) => ( - class extends React.Component { static async getInitialProps (ctx) { - const headers = ctx.req ? ctx.req.headers : {} - const client = initClient(headers) - const store = initStore(client, client.initialState) + let serverState = {} - const props = { - url: { query: ctx.query, pathname: ctx.pathname }, - ...await (Component.getInitialProps ? Component.getInitialProps(ctx) : {}) + // Evaluate the composed component's getInitialProps() + let composedInitialProps = {} + if (ComposedComponent.getInitialProps) { + composedInitialProps = await ComposedComponent.getInitialProps(ctx) } + // Run all graphql queries in the component tree + // and extract the resulting data if (!process.browser) { + const apollo = initApollo() + const redux = initRedux(apollo) + // Provide the `url` prop data in case a graphql query uses it + const url = {query: ctx.query, pathname: ctx.pathname} + + // Run all graphql queries const app = ( - - + // No need to use the Redux Provider + // because Apollo sets up the store for us + + ) await getDataFromTree(app) + + // Extract query data from the store + const state = redux.getState() + + // No need to include other initial Redux state because when it + // initialises on the client-side it'll create it again anyway + serverState = { + apollo: { // Make sure to only include Apollo's data state + data: state.apollo.data + } + } } - const state = store.getState() - return { - initialState: { - ...state, - apollo: { - data: client.getInitialState().data - } - }, - headers, - ...props + serverState, + ...composedInitialProps } } constructor (props) { super(props) - this.client = initClient(this.props.headers, this.props.initialState) - this.store = initStore(this.client, this.props.initialState) + this.apollo = initApollo() + this.redux = initRedux(this.apollo, this.props.serverState) } render () { return ( - - + // No need to use the Redux Provider + // because Apollo sets up the store for us + + ) } } -) +} diff --git a/examples/with-apollo-and-redux/package.json b/examples/with-apollo-and-redux/package.json index 455d5a2e..899ffe62 100644 --- a/examples/with-apollo-and-redux/package.json +++ b/examples/with-apollo-and-redux/package.json @@ -1,16 +1,19 @@ { "name": "with-apollo-and-redux", - "version": "1.0.0", + "version": "2.0.0", "scripts": { "dev": "next", "build": "next build", "start": "next start" }, "dependencies": { - "graphql": "^0.9.1", + "graphql": "^0.9.3", + "isomorphic-fetch": "^2.2.1", "next": "latest", - "react": "^15.4.2", - "react-apollo": "^1.0.0-rc.2", + "prop-types": "^15.5.8", + "react": "^15.5.4", + "react-apollo": "^1.1.3", + "react-dom": "^15.5.4", "redux": "^3.6.0" }, "author": "", diff --git a/examples/with-apollo/lib/initApollo.js b/examples/with-apollo/lib/initApollo.js new file mode 100644 index 00000000..dfd1976f --- /dev/null +++ b/examples/with-apollo/lib/initApollo.js @@ -0,0 +1,37 @@ +import { ApolloClient, createNetworkInterface } from 'react-apollo' +import fetch from 'isomorphic-fetch' + +let apolloClient = null + +// Polyfill fetch() on the server (used by apollo-client) +if (!process.browser) { + global.fetch = fetch +} + +function create (initialState) { + return new ApolloClient({ + initialState, + ssrMode: !process.browser, // Disables forceFetch on the server (so queries are only run once) + networkInterface: createNetworkInterface({ + uri: 'https://api.graph.cool/simple/v1/cixmkt2ul01q00122mksg82pn', // Server URL (must be absolute) + opts: { // Additional fetch() options like `credentials` or `headers` + credentials: 'same-origin' + } + }) + }) +} + +export default function initApollo (initialState) { + // Make sure to create a new client for every server-side request so that data + // isn't shared between connections (which would be bad) + if (!process.browser) { + return create(initialState) + } + + // Reuse client on the client-side + if (!apolloClient) { + apolloClient = create(initialState) + } + + return apolloClient +} diff --git a/examples/with-apollo/lib/initClient.js b/examples/with-apollo/lib/initClient.js deleted file mode 100644 index 31f590f3..00000000 --- a/examples/with-apollo/lib/initClient.js +++ /dev/null @@ -1,28 +0,0 @@ -import { ApolloClient, createNetworkInterface } from 'react-apollo' - -let apolloClient = null - -function _initClient (headers, initialState) { - return new ApolloClient({ - initialState, - ssrMode: !process.browser, - dataIdFromObject: result => result.id || null, - networkInterface: createNetworkInterface({ - uri: 'https://api.graph.cool/simple/v1/cixmkt2ul01q00122mksg82pn', - opts: { - credentials: 'same-origin' - // Pass headers here if your graphql server requires them - } - }) - }) -} - -export const initClient = (headers, initialState = {}) => { - if (!process.browser) { - return _initClient(headers, initialState) - } - if (!apolloClient) { - apolloClient = _initClient(headers, initialState) - } - return apolloClient -} diff --git a/examples/with-apollo/lib/withData.js b/examples/with-apollo/lib/withData.js index ee8ffd3e..faf8a018 100644 --- a/examples/with-apollo/lib/withData.js +++ b/examples/with-apollo/lib/withData.js @@ -1,50 +1,66 @@ -import 'isomorphic-fetch' import React from 'react' +import PropTypes from 'prop-types' import { ApolloProvider, getDataFromTree } from 'react-apollo' -import { initClient } from './initClient' +import initApollo from './initApollo' + +export default ComposedComponent => { + return class WithData extends React.Component { + static displayName = `WithData(${ComposedComponent.displayName})` + static propTypes = { + serverState: PropTypes.object.isRequired + } -export default (Component) => ( - class extends React.Component { static async getInitialProps (ctx) { - const headers = ctx.req ? ctx.req.headers : {} - const client = initClient(headers) + let serverState = {} - const props = { - url: { query: ctx.query, pathname: ctx.pathname }, - ...await (Component.getInitialProps ? Component.getInitialProps(ctx) : {}) + // Evaluate the composed component's getInitialProps() + let composedInitialProps = {} + if (ComposedComponent.getInitialProps) { + composedInitialProps = await ComposedComponent.getInitialProps(ctx) } + // Run all graphql queries in the component tree + // and extract the resulting data if (!process.browser) { + const apollo = initApollo() + // Provide the `url` prop data in case a graphql query uses it + const url = {query: ctx.query, pathname: ctx.pathname} + + // Run all graphql queries const app = ( - - + + ) await getDataFromTree(app) + + // 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 + } + } } return { - initialState: { - apollo: { - data: client.getInitialState().data - } - }, - headers, - ...props + serverState, + ...composedInitialProps } } constructor (props) { super(props) - this.client = initClient(this.props.headers, this.props.initialState) + this.apollo = initApollo(this.props.serverState) } render () { return ( - - + + ) } } -) +} diff --git a/examples/with-apollo/package.json b/examples/with-apollo/package.json index 778aef08..9d48d3a2 100644 --- a/examples/with-apollo/package.json +++ b/examples/with-apollo/package.json @@ -1,16 +1,19 @@ { "name": "with-apollo", - "version": "1.0.1", + "version": "2.0.0", "scripts": { "dev": "next", "build": "next build", "start": "next start" }, "dependencies": { - "graphql": "^0.9.1", + "graphql": "^0.9.3", + "isomorphic-fetch": "^2.2.1", "next": "latest", - "react": "^15.4.2", - "react-apollo": "^1.0.0-rc.3" + "prop-types": "^15.5.8", + "react": "^15.5.4", + "react-dom": "^15.5.4", + "react-apollo": "^1.1.3" }, "author": "", "license": "ISC" From 6f674b8c0ab15d0e18006c11f8ddd3ecef8a0da9 Mon Sep 17 00:00:00 2001 From: Arunoda Susiripala Date: Wed, 10 May 2017 20:01:42 -0700 Subject: [PATCH 62/82] Get rid of realPathname for consistant page file structure. --- package.json | 1 + server/document.js | 17 +++++++++++------ server/export.js | 34 ++++++++++++++++++++++++++++++---- server/render.js | 8 -------- yarn.lock | 10 ++++++++++ 5 files changed, 52 insertions(+), 18 deletions(-) diff --git a/package.json b/package.json index 5a80534a..faf280f2 100644 --- a/package.json +++ b/package.json @@ -121,6 +121,7 @@ "react-dom": "15.5.3", "recursive-copy": "^2.0.6", "standard": "9.0.2", + "walk": "^2.3.9", "wd": "1.2.0" }, "peerDependencies": { diff --git a/server/document.js b/server/document.js index 7a0e4b3d..685778cf 100644 --- a/server/document.js +++ b/server/document.js @@ -67,11 +67,13 @@ export class Head extends Component { render () { const { head, styles, __NEXT_DATA__ } = this.context._documentProps - const { realPathname, buildId, assetPrefix } = __NEXT_DATA__ + const { pathname, buildId, assetPrefix, nextExport } = __NEXT_DATA__ + + const pagePathname = nextExport ? `${pathname}/index.js` : pathname return - - + + {this.getPreloadMainLinks()} {(head || []).map((h, i) => React.cloneElement(h, { key: i }))} {styles || null} @@ -133,7 +135,9 @@ export class NextScript extends Component { render () { const { staticMarkup, __NEXT_DATA__ } = this.context._documentProps - const { pathname, realPathname, buildId, assetPrefix } = __NEXT_DATA__ + const { pathname, nextExport, buildId, assetPrefix } = __NEXT_DATA__ + + const pagePathname = nextExport ? `${pathname}/index.js` : pathname return
{staticMarkup ? null :