From 7f89c39045a4aa3afbe5f3bfd27868c4b1aa4ae3 Mon Sep 17 00:00:00 2001 From: Dan Zajdband Date: Wed, 12 Oct 2016 19:15:58 -0400 Subject: [PATCH 01/16] Set test command and added more tests --- .gitignore | 1 + package.json | 2 +- test/fixtures/basic/pages/head.js | 10 ++++++++++ test/fixtures/basic/pages/stateful.js | 20 ++++++++++++++++++++ test/index.js | 15 +++++++++++++-- 5 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 test/fixtures/basic/pages/head.js create mode 100644 test/fixtures/basic/pages/stateful.js diff --git a/.gitignore b/.gitignore index 2cceb5fd..a7018501 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ node_modules dist .next +yarn.lock diff --git a/package.json b/package.json index 3defb291..1121688f 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ }, "scripts": { "build": "gulp", - "test": "ava" + "test": "gulp test" }, "dependencies": { "aphrodite": "0.5.0", diff --git a/test/fixtures/basic/pages/head.js b/test/fixtures/basic/pages/head.js new file mode 100644 index 00000000..7af9c5a7 --- /dev/null +++ b/test/fixtures/basic/pages/head.js @@ -0,0 +1,10 @@ + +import React from 'react' +import Head from 'next/head' + +export default () =>
+ + + +

I can haz meta tags

+
diff --git a/test/fixtures/basic/pages/stateful.js b/test/fixtures/basic/pages/stateful.js new file mode 100644 index 00000000..02248c42 --- /dev/null +++ b/test/fixtures/basic/pages/stateful.js @@ -0,0 +1,20 @@ + +import React, { Component } from 'react' + +export default class Statefull extends Component { + constructor (props) { + super(props) + + this.state = { answer: null } + } + + componentWillMount () { + this.setState({ answer: 42 }) + } + + render () { + return
+

The answer is {this.state.answer}

+
+ } +} diff --git a/test/index.js b/test/index.js index 54183c3c..d90a7844 100644 --- a/test/index.js +++ b/test/index.js @@ -7,17 +7,28 @@ const dir = resolve(__dirname, 'fixtures', 'basic') test.before(() => build(dir)) -test(async (t) => { +test(async t => { const html = await render('/stateless') t.true(html.includes('

My component!

')) }) -test(async (t) => { +test(async t => { const html = await render('/css') t.true(html.includes('')) t.true(html.includes('
This is red
')) }) +test(async t => { + const html = await (render('/stateful')) + t.true(html.includes('

The answer is 42

')) +}) + +test(async t => { + const html = await (render('/head')) + t.true(html.includes('')) + t.true(html.includes('

I can haz meta tags

')) +}) + function render (url, ctx) { return _render(url, ctx, { dir, staticMarkup: true }) } From 7a379ac25e10c074a0719153099a79f4a1cad0f0 Mon Sep 17 00:00:00 2001 From: Dan Zajdband Date: Thu, 13 Oct 2016 16:01:11 -0400 Subject: [PATCH 02/16] Added benchmark suite --- bench/fixtures/basic/pages/css.js | 27 +++++++++++++++++ bench/fixtures/basic/pages/stateless-big.js | 17 +++++++++++ bench/fixtures/basic/pages/stateless.js | 3 ++ bench/index.js | 32 +++++++++++++++++++++ gulpfile.js | 26 +++++++++++++++-- package.json | 1 + 6 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 bench/fixtures/basic/pages/css.js create mode 100644 bench/fixtures/basic/pages/stateless-big.js create mode 100644 bench/fixtures/basic/pages/stateless.js create mode 100644 bench/index.js diff --git a/bench/fixtures/basic/pages/css.js b/bench/fixtures/basic/pages/css.js new file mode 100644 index 00000000..ad8b10cf --- /dev/null +++ b/bench/fixtures/basic/pages/css.js @@ -0,0 +1,27 @@ +import React, { Component } from 'react' +import { StyleSheet, css } from 'next/css' + + +const spans = () => ( +) + +export default class CrazyCSS extends Component { + spans () { + const out = [] + for (let i = 0; i < 1000; i++) { + out.push(This is ${i}) + } + return out + } + + render () { + return
{this.spans()}
+ } +} + +const spanStyles = {} +for (let i = 0; i < 1000; i++) { + spanStyles[`padding-${i}`] = { padding: i } +} + +const styles = StyleSheet.create(spanStyles) diff --git a/bench/fixtures/basic/pages/stateless-big.js b/bench/fixtures/basic/pages/stateless-big.js new file mode 100644 index 00000000..44c37af8 --- /dev/null +++ b/bench/fixtures/basic/pages/stateless-big.js @@ -0,0 +1,17 @@ +import React from 'react' + +export default () => { + return ( + + ) +} + +const items = () => { + var out = new Array(10000) + for (let i = 0; i < out.length; i++) { + out[i] =
  • This is row {i+1}
  • + } + return out +} diff --git a/bench/fixtures/basic/pages/stateless.js b/bench/fixtures/basic/pages/stateless.js new file mode 100644 index 00000000..b6796ba8 --- /dev/null +++ b/bench/fixtures/basic/pages/stateless.js @@ -0,0 +1,3 @@ +import React from 'react' + +export default () =>

    My component!

    diff --git a/bench/index.js b/bench/index.js new file mode 100644 index 00000000..51efc3ef --- /dev/null +++ b/bench/index.js @@ -0,0 +1,32 @@ + +import { resolve } from 'path' +import build from '../server/build' +import { render as _render } from '../server/render' +import Benchmark from 'benchmark' + +const dir = resolve(__dirname, 'fixtures', 'basic') +const suite = new Benchmark.Suite('Next.js'); + +suite +.on('start', async () => build(dir)) + +.add('Tiny stateless component', async p => { + await render('/stateless') + p.resolve() +}, { defer: true }) + +.add('Big stateless component', async p => { + await render('/stateless-big') + p.resolve() +}, { defer: true }) + +.add('Stateful component with a loooot of css', async p => { + await render('/css') + p.resolve() +}, { defer: true }) + +module.exports = suite + +function render (url, ctx) { + return _render(url, ctx, { dir, staticMarkup: true }) +} diff --git a/gulpfile.js b/gulpfile.js index 3caee0bb..5dd598be 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -3,6 +3,7 @@ const babel = require('gulp-babel') const cache = require('gulp-cached') const notify_ = require('gulp-notify') const ava = require('gulp-ava') +const benchmark = require('gulp-benchmark') const sequence = require('run-sequence') const webpack = require('webpack-stream') const del = require('del') @@ -22,7 +23,8 @@ gulp.task('compile', [ 'compile-lib', 'compile-server', 'compile-client', - 'compile-test' + 'compile-test', + 'compile-bench' ]) gulp.task('compile-bin', () => { @@ -68,7 +70,20 @@ gulp.task('compile-test', () => { gulp.task('copy-test-fixtures', () => { return gulp.src('test/fixtures/**/*') .pipe(gulp.dest('dist/test/fixtures')) -}); +}) + +gulp.task('compile-bench', () => { + return gulp.src('bench/*.js') + .pipe(cache('bench')) + .pipe(babel(babelOptions)) + .pipe(gulp.dest('dist/bench')) + .pipe(notify('Compiled bench files')) +}) + +gulp.task('copy-bench-fixtures', () => { + return gulp.src('bench/fixtures/**/*') + .pipe(gulp.dest('dist/bench/fixtures')) +}) gulp.task('build', [ 'build-dev-client', @@ -113,6 +128,13 @@ gulp.task('test', ['compile', 'copy-test-fixtures'], () => { .pipe(ava()) }) +gulp.task('bench', ['compile', 'copy-bench-fixtures'], () => { + return gulp.src('dist/bench/*.js', {read: false}) + .pipe(benchmark({ + reporters: benchmark.reporters.etalon('RegExp#test') + })) +}) + gulp.task('watch', [ 'watch-bin', 'watch-lib', diff --git a/package.json b/package.json index 1121688f..d618327a 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "babel-runtime": "6.11.6", "cross-spawn": "4.0.2", "glob-promise": "1.0.6", + "gulp-benchmark": "^1.1.1", "htmlescape": "1.1.1", "minimist": "1.2.0", "mkdirp-then": "1.2.0", From 864e088cba30bf5de2a4d233c8a467ea2da60946 Mon Sep 17 00:00:00 2001 From: Dan Zajdband Date: Fri, 14 Oct 2016 17:13:46 -0400 Subject: [PATCH 03/16] Fixed examples. --- Readme.md | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/Readme.md b/Readme.md index d9dd3092..4f369367 100644 --- a/Readme.md +++ b/Readme.md @@ -30,9 +30,9 @@ Every `import` you declare gets bundled and served with each page ```jsx import React from 'react' -import cowsay from 'cowsay' +import cowsay from 'cowsay-browser' export default () => ( -
    { cowsay('hi there!') }
    +
    { cowsay({ text: 'hi there!' }) }
    ) ``` @@ -46,11 +46,11 @@ We use [Aphrodite](https://github.com/Khan/aphrodite) to provide a great built-i import React from 'react' import { css, StyleSheet } from 'next/css' -export default () => { +export default () => (
    Hello world
    -}) +) const styles = StyleSheet.create({ main: { @@ -70,11 +70,13 @@ We expose a built-in component for appending elements to the `` of the pag import React from 'react' import Head from 'next/head' export default () => ( - - My page title - - -

    Hello world!

    +
    + + My page title + + +

    Hello world!

    +
    ) ``` From c81ab7cc95a2126153215d80d51bed670e62c506 Mon Sep 17 00:00:00 2001 From: Guillermo Rauch Date: Sat, 15 Oct 2016 08:15:10 -0500 Subject: [PATCH 04/16] Update Readme.md --- Readme.md | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/Readme.md b/Readme.md index 4f369367..59933f39 100644 --- a/Readme.md +++ b/Readme.md @@ -139,17 +139,6 @@ Each top-level component receives a `url` property with the following API: - `pushTo(url)` - performs a `pushState` call that renders the new `url`. This is equivalent to following a `` - `replaceTo(url)` - performs a `replaceState` call that renders the new `url` -### 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`: - -```jsx -import React from 'react' -export default ({ statusCode }) => ( -

    An error { statusCode } occurred

    -) -``` - ### Production deployment To deploy, run: @@ -174,3 +163,10 @@ For example, to deploy with `now` a `package.json` like follows is recommended: } } ``` + +### In progress + +- [ ] Add option to supply a `req`, `res` handling function for custom routing +- [ ] Add option to supply a custom error component to render 404, 500 pages +- [ ] Add option to extend or replace custom babel configuration +- [ ] Add option to extend or replace custom webpack configuration From ed90c2dd7c90e0173e04327dc2896ce05d67e114 Mon Sep 17 00:00:00 2001 From: Guillermo Rauch Date: Sat, 15 Oct 2016 08:16:25 -0500 Subject: [PATCH 05/16] Update Readme.md --- Readme.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Readme.md b/Readme.md index 59933f39..96ebc71e 100644 --- a/Readme.md +++ b/Readme.md @@ -166,6 +166,8 @@ For example, to deploy with `now` a `package.json` like follows is recommended: ### In progress +The following tasks are planned and part of our roadmap + - [ ] Add option to supply a `req`, `res` handling function for custom routing - [ ] Add option to supply a custom error component to render 404, 500 pages - [ ] Add option to extend or replace custom babel configuration From a9321714a51d8bff40d1a7911318ca2723cd698f Mon Sep 17 00:00:00 2001 From: Guillermo Rauch Date: Sat, 15 Oct 2016 08:17:47 -0500 Subject: [PATCH 06/16] Update Readme.md --- Readme.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Readme.md b/Readme.md index 96ebc71e..b4a2520d 100644 --- a/Readme.md +++ b/Readme.md @@ -172,3 +172,4 @@ The following tasks are planned and part of our roadmap - [ ] Add option to supply a custom error component to render 404, 500 pages - [ ] Add option to extend or replace custom babel configuration - [ ] Add option to extend or replace custom webpack configuration +- [ ] Investigate pluggable component-oriented rendering backends (Inferno, Preact, etc) From e527098bb904a59d428d1ee0537a9bd03a6407cc Mon Sep 17 00:00:00 2001 From: Dan Zajdband Date: Sat, 15 Oct 2016 18:36:54 -0400 Subject: [PATCH 07/16] Implemented missing pieces for overriding 404 and 500 pages. (#10) --- Readme.md | 12 +++++++++++- lib/router.js | 8 +++++++- server/build/index.js | 2 +- server/render.js | 7 ++++++- 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/Readme.md b/Readme.md index b4a2520d..b420f893 100644 --- a/Readme.md +++ b/Readme.md @@ -139,6 +139,17 @@ Each top-level component receives a `url` property with the following API: - `pushTo(url)` - performs a `pushState` call that renders the new `url`. This is equivalent to following a `` - `replaceTo(url)` - performs a `replaceState` call that renders the new `url` +### 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`: + +```jsx +import React from 'react' +export default ({ statusCode }) => ( +

    An error { statusCode } occurred

    +) +``` + ### Production deployment To deploy, run: @@ -169,7 +180,6 @@ For example, to deploy with `now` a `package.json` like follows is recommended: The following tasks are planned and part of our roadmap - [ ] Add option to supply a `req`, `res` handling function for custom routing -- [ ] Add option to supply a custom error component to render 404, 500 pages - [ ] Add option to extend or replace custom babel configuration - [ ] Add option to extend or replace custom webpack configuration - [ ] Investigate pluggable component-oriented rendering backends (Inferno, Preact, etc) diff --git a/lib/router.js b/lib/router.js index 6e8a9534..57e78be9 100644 --- a/lib/router.js +++ b/lib/router.js @@ -149,7 +149,13 @@ export default class Router { const cancel = () => { cancelled = true } this.componentLoadCancel = cancel - const props = await (Component.getInitialProps ? Component.getInitialProps(ctx) : {}) + let props = {} + const status = ctx.xhr.status + if (status === 404 || status === 500) { + props = { statusCode: ctx.xhr.status } + } else { + props = await (Component.getInitialProps ? Component.getInitialProps(ctx) : {}) + } if (cancel === this.componentLoadCancel) { this.componentLoadCancel = null diff --git a/server/build/index.js b/server/build/index.js index 569fe639..1b29f9d0 100644 --- a/server/build/index.js +++ b/server/build/index.js @@ -8,7 +8,7 @@ export default async function build (dir) { const templateDir = resolve(__dirname, '..', '..', 'lib', 'pages') // create `.next/pages/_error.js` - // which may be overwriten by the user sciprt, `pages/_error.js` + // which may be overwriten by the user script, `pages/_error.js` const templatPaths = await glob('**/*.js', { cwd: templateDir }) await Promise.all(templatPaths.map(async (p) => { await transpile(resolve(templateDir, p), resolve(dstDir, 'pages', p)) diff --git a/server/render.js b/server/render.js index 670fc550..f7a020af 100644 --- a/server/render.js +++ b/server/render.js @@ -21,7 +21,8 @@ export async function render (url, ctx = {}, { const mod = require(p) const Component = mod.default || mod - const props = await (Component.getInitialProps ? Component.getInitialProps(ctx) : {}) + const { err, res } = ctx + const props = ctx.err ? getErrorProps(ctx, dev) : await (Component.getInitialProps ? Component.getInitialProps(ctx) : {}) const component = await read(resolve(dir, '.next', '_bundles', 'pages', path)) const { html, css } = StyleSheetServer.renderStatic(() => { @@ -62,3 +63,7 @@ export async function renderJSON (url, { dir = process.cwd() } = {}) { function getPath (url) { return parse(url || '/').pathname.slice(1).replace(/\.json$/, '') } + +function getErrorProps (ctx, dev) { + return { statusCode: ctx.res.statusCode, stacktrace: dev ? ctx.err.message : undefined } +} From 89089f5546555d41fcc37c2640aa1edbcdf5e7ee Mon Sep 17 00:00:00 2001 From: Guillermo Rauch Date: Sat, 15 Oct 2016 23:31:05 -0500 Subject: [PATCH 08/16] add some basic examples --- examples/basic-css/pages/index.js | 21 ++++++++ examples/head-elements/pages/index.js | 14 ++++++ examples/hello-world/pages/about.js | 4 ++ examples/hello-world/pages/index.js | 5 ++ .../nested-components/components/paragraph.js | 13 +++++ examples/nested-components/components/post.js | 23 +++++++++ examples/nested-components/pages/index.js | 48 +++++++++++++++++++ 7 files changed, 128 insertions(+) create mode 100644 examples/basic-css/pages/index.js create mode 100644 examples/head-elements/pages/index.js create mode 100644 examples/hello-world/pages/about.js create mode 100644 examples/hello-world/pages/index.js create mode 100644 examples/nested-components/components/paragraph.js create mode 100644 examples/nested-components/components/post.js create mode 100644 examples/nested-components/pages/index.js diff --git a/examples/basic-css/pages/index.js b/examples/basic-css/pages/index.js new file mode 100644 index 00000000..9dead5b1 --- /dev/null +++ b/examples/basic-css/pages/index.js @@ -0,0 +1,21 @@ +import React from 'react' +import { css, StyleSheet } from 'next/css' + +export default () => ( +
    +

    Hello World

    +
    +) + +const styles = StyleSheet.create({ + main: { + font: '15px Helvetica, Arial, sans-serif', + background: '#eee', + padding: '100px', + textAlign: 'center', + transition: '100ms ease-in background', + ':hover': { + background: '#ccc' + } + } +}) diff --git a/examples/head-elements/pages/index.js b/examples/head-elements/pages/index.js new file mode 100644 index 00000000..71a72f4a --- /dev/null +++ b/examples/head-elements/pages/index.js @@ -0,0 +1,14 @@ +import React from 'react' +import Head from 'next/head' + +export default () => ( +
    + + This page has a title 🤔 + + + + +

    This page has a title 🤔

    +
    +) diff --git a/examples/hello-world/pages/about.js b/examples/hello-world/pages/about.js new file mode 100644 index 00000000..759018a0 --- /dev/null +++ b/examples/hello-world/pages/about.js @@ -0,0 +1,4 @@ +import React from 'react' +export default () => ( +
    About us
    +) diff --git a/examples/hello-world/pages/index.js b/examples/hello-world/pages/index.js new file mode 100644 index 00000000..d1b17869 --- /dev/null +++ b/examples/hello-world/pages/index.js @@ -0,0 +1,5 @@ +import React from 'react' +import Link from 'next/link' +export default () => ( +
    Hello World. About
    +) diff --git a/examples/nested-components/components/paragraph.js b/examples/nested-components/components/paragraph.js new file mode 100644 index 00000000..0332a3da --- /dev/null +++ b/examples/nested-components/components/paragraph.js @@ -0,0 +1,13 @@ +import React from 'react' +import { css, StyleSheet } from 'next/css' + +export default ({ children }) => ( +

    {children}

    +) + +const styles = StyleSheet.create({ + main: { + font: '13px Helvetica, Arial', + margin: '10px 0' + } +}) diff --git a/examples/nested-components/components/post.js b/examples/nested-components/components/post.js new file mode 100644 index 00000000..8d90dd91 --- /dev/null +++ b/examples/nested-components/components/post.js @@ -0,0 +1,23 @@ +import React from 'react' +import { css, StyleSheet } from 'next/css' + +export default ({ title, children }) => ( +
    +

    { title }

    + { children } +
    +) + +const styles = StyleSheet.create({ + main: { + font: '15px Helvetica, Arial', + border: '1px solid #eee', + padding: '0 10px' + }, + + title: { + fontSize: '16px', + fontWeight: 'bold', + margin: '10px 0' + } +}) diff --git a/examples/nested-components/pages/index.js b/examples/nested-components/pages/index.js new file mode 100644 index 00000000..ef0c632a --- /dev/null +++ b/examples/nested-components/pages/index.js @@ -0,0 +1,48 @@ +import React from 'react' +import P from '../components/paragraph' +import Post from '../components/post' +import { css, StyleSheet } from 'next/css' + +export default () => ( +
    + +

    Hello there

    +

    This is an example of a componentized blog post

    +
    + +
    + + +

    Hello there

    +

    This is another example.

    +

    Wa-hoo!

    +
    + +
    + + +

    C'est fin

    +
    +
    +) + +const Hr = () =>
    + +const styles = StyleSheet.create({ + main: { + margin: 'auto', + maxWidth: '420px', + padding: '10px' + }, + + hr: { + width: '100px', + borderWidth: 0, + margin: '20px auto', + textAlign: 'center', + ':before': { + content: '"***"', + color: '#ccc' + } + } +}) From 78fa6b191d24525f9d8285c0c8b775c759af5a57 Mon Sep 17 00:00:00 2001 From: Dan Zajdband Date: Sun, 16 Oct 2016 00:32:58 -0400 Subject: [PATCH 09/16] Added async props test (#9) --- test/fixtures/basic/pages/async-props.js | 18 ++++++++++++++++++ test/index.js | 7 ++++++- 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 test/fixtures/basic/pages/async-props.js diff --git a/test/fixtures/basic/pages/async-props.js b/test/fixtures/basic/pages/async-props.js new file mode 100644 index 00000000..2401e133 --- /dev/null +++ b/test/fixtures/basic/pages/async-props.js @@ -0,0 +1,18 @@ +import React from 'react' + +export default class AsyncProps extends React.Component { + static async getInitialProps () { + return await AsyncProps.fetchData() + } + + static fetchData () { + const p = new Promise(resolve => { + setTimeout(() => resolve({ name: 'Diego Milito' }), 10) + }) + return p + } + + render () { + return

    {this.props.name}

    + } +} diff --git a/test/index.js b/test/index.js index d90a7844..596d9db6 100644 --- a/test/index.js +++ b/test/index.js @@ -19,7 +19,7 @@ test(async t => { }) test(async t => { - const html = await (render('/stateful')) + const html = await render('/stateful') t.true(html.includes('

    The answer is 42

    ')) }) @@ -29,6 +29,11 @@ test(async t => { t.true(html.includes('

    I can haz meta tags

    ')) }) +test(async t => { + const html = await render('/async-props') + t.true(html.includes('

    Diego Milito

    ')) +}) + function render (url, ctx) { return _render(url, ctx, { dir, staticMarkup: true }) } From ea61fe412ab0ab8de8931a8ee5840fdc27b5d344 Mon Sep 17 00:00:00 2001 From: Dan Zajdband Date: Sun, 16 Oct 2016 01:25:13 -0400 Subject: [PATCH 10/16] Add current props to state when data available (#13) --- lib/app.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/app.js b/lib/app.js index 53b6c78d..52696b8c 100644 --- a/lib/app.js +++ b/lib/app.js @@ -28,6 +28,7 @@ export default class App extends Component { const props = data.props || this.state.props const state = propsToState({ ...data, + props, router }) From 7a331084dc2c0a905d0edfc6820d1596451a42ee Mon Sep 17 00:00:00 2001 From: Dan Zajdband Date: Sun, 16 Oct 2016 18:44:26 -0400 Subject: [PATCH 11/16] Reverting default props for errors. (#12) --- Readme.md | 16 +++++++++++++--- lib/router.js | 8 +------- server/render.js | 7 +------ 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/Readme.md b/Readme.md index b420f893..5b9fd139 100644 --- a/Readme.md +++ b/Readme.md @@ -145,9 +145,19 @@ Each top-level component receives a `url` property with the following API: ```jsx import React from 'react' -export default ({ statusCode }) => ( -

    An error { statusCode } occurred

    -) + +export default class Error extends React.Component { + static getInitialProps ({ res, xhr }) { + const statusCode = res ? res.statusCode : xhr.status + return { statusCode } + } + + render () { + return ( +

    An error { this.props.statusCode } occurred

    + ) + } +} ``` ### Production deployment diff --git a/lib/router.js b/lib/router.js index 57e78be9..6e8a9534 100644 --- a/lib/router.js +++ b/lib/router.js @@ -149,13 +149,7 @@ export default class Router { const cancel = () => { cancelled = true } this.componentLoadCancel = cancel - let props = {} - const status = ctx.xhr.status - if (status === 404 || status === 500) { - props = { statusCode: ctx.xhr.status } - } else { - props = await (Component.getInitialProps ? Component.getInitialProps(ctx) : {}) - } + const props = await (Component.getInitialProps ? Component.getInitialProps(ctx) : {}) if (cancel === this.componentLoadCancel) { this.componentLoadCancel = null diff --git a/server/render.js b/server/render.js index f7a020af..670fc550 100644 --- a/server/render.js +++ b/server/render.js @@ -21,8 +21,7 @@ export async function render (url, ctx = {}, { const mod = require(p) const Component = mod.default || mod - const { err, res } = ctx - const props = ctx.err ? getErrorProps(ctx, dev) : await (Component.getInitialProps ? Component.getInitialProps(ctx) : {}) + const props = await (Component.getInitialProps ? Component.getInitialProps(ctx) : {}) const component = await read(resolve(dir, '.next', '_bundles', 'pages', path)) const { html, css } = StyleSheetServer.renderStatic(() => { @@ -63,7 +62,3 @@ export async function renderJSON (url, { dir = process.cwd() } = {}) { function getPath (url) { return parse(url || '/').pathname.slice(1).replace(/\.json$/, '') } - -function getErrorProps (ctx, dev) { - return { statusCode: ctx.res.statusCode, stacktrace: dev ? ctx.err.message : undefined } -} From 97ad05385594dfc0123ba3b08c34320ddcb447f8 Mon Sep 17 00:00:00 2001 From: Dan Zajdband Date: Sun, 16 Oct 2016 19:55:30 -0400 Subject: [PATCH 12/16] Added next init command for starting a new project (#15) * Added next bootstrap command for starting a new project * renamed bootstrap to init and check we are not in a dir called pages * Removed extra empty line --- bin/next | 1 + bin/next-init | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100755 bin/next-init diff --git a/bin/next b/bin/next index 81f7d96c..9004fe25 100755 --- a/bin/next +++ b/bin/next @@ -7,6 +7,7 @@ import { spawn } from 'cross-spawn'; const defaultCommand = 'dev' const commands = new Set([ defaultCommand, + 'init', 'build', 'start' ]) diff --git a/bin/next-init b/bin/next-init new file mode 100755 index 00000000..b060e428 --- /dev/null +++ b/bin/next-init @@ -0,0 +1,56 @@ +#!/usr/bin/env node +import { resolve, join, basename } from 'path' +import parseArgs from 'minimist' +import { exists, writeFile, mkdir } from 'mz/fs' + +const argv = parseArgs(process.argv.slice(2), { + alias: { + h: 'help' + }, + boolean: ['h'] +}) + +const dir = resolve(argv._[0] || '.') + +exists(join(dir, 'package.json')) +.then(async present => { + if (basename(dir) === 'pages') { + console.warn('Your root directory is named "pages". This looks suspicious. You probably want to go one directory up.') + return + } + + if (!present) { + await writeFile(join(dir, 'package.json'), basePackage) + } + + if (!await exists(join(dir, 'static'))) { + await mkdir(join(dir, 'static')) + } + + if (!await exists(join(dir, 'pages'))) { + await mkdir(join(dir, 'pages')) + await writeFile(join(dir, 'pages', 'index.js'), basePage) + } +}) +.catch((err) => { + console.error(err) + exit(1) +}) + +const basePackage = `{ + "name": "my-app", + "description": "my app", + "dependencies": { + "next": "latest" + }, + "scripts": { + "dev": "next", + "build": "next build", + "start": "next start" + } +}` + +const basePage =` +import React from 'react' +export default () =>

    Hello, world

    +` From 14777342115522a2d2a182fcf3bb44938560d52c Mon Sep 17 00:00:00 2001 From: Dan Zajdband Date: Sun, 16 Oct 2016 20:00:17 -0400 Subject: [PATCH 13/16] Added linting using standard (#27) * Added linting using standard * Linting on test --- bench/fixtures/basic/pages/css.js | 4 ---- bench/fixtures/basic/pages/stateless-big.js | 6 +++--- bench/index.js | 2 +- bin/next | 3 +-- bin/next-build | 2 +- bin/next-dev | 2 +- bin/next-start | 2 +- client/head-manager.js | 6 +++--- client/next.js | 2 +- examples/head-elements/pages/index.js | 4 ++-- examples/hello-world/pages/index.js | 2 +- examples/nested-components/pages/index.js | 6 +++--- gulpfile.js | 2 +- lib/document.js | 18 +++++++++--------- lib/head.js | 2 +- lib/link.js | 10 +++++----- lib/pages/_error.js | 2 +- lib/router.js | 18 +++++++++--------- lib/shallow-equals.js | 6 +++--- lib/side-effect.js | 2 +- package.json | 8 +++++++- server/build/transpile.js | 4 ++-- server/index.js | 10 +++++----- server/render.js | 3 +-- test/fixtures/basic/pages/head.js | 2 +- 25 files changed, 64 insertions(+), 64 deletions(-) diff --git a/bench/fixtures/basic/pages/css.js b/bench/fixtures/basic/pages/css.js index ad8b10cf..6d125bdc 100644 --- a/bench/fixtures/basic/pages/css.js +++ b/bench/fixtures/basic/pages/css.js @@ -1,10 +1,6 @@ import React, { Component } from 'react' import { StyleSheet, css } from 'next/css' - -const spans = () => ( -) - export default class CrazyCSS extends Component { spans () { const out = [] diff --git a/bench/fixtures/basic/pages/stateless-big.js b/bench/fixtures/basic/pages/stateless-big.js index 44c37af8..5b14df33 100644 --- a/bench/fixtures/basic/pages/stateless-big.js +++ b/bench/fixtures/basic/pages/stateless-big.js @@ -3,15 +3,15 @@ import React from 'react' export default () => { return (
      - {items()} -
    + {items()} + ) } const items = () => { var out = new Array(10000) for (let i = 0; i < out.length; i++) { - out[i] =
  • This is row {i+1}
  • + out[i] =
  • This is row {i + 1}
  • } return out } diff --git a/bench/index.js b/bench/index.js index 51efc3ef..b7a01e69 100644 --- a/bench/index.js +++ b/bench/index.js @@ -5,7 +5,7 @@ import { render as _render } from '../server/render' import Benchmark from 'benchmark' const dir = resolve(__dirname, 'fixtures', 'basic') -const suite = new Benchmark.Suite('Next.js'); +const suite = new Benchmark.Suite('Next.js') suite .on('start', async () => build(dir)) diff --git a/bin/next b/bin/next index 9004fe25..7e2a46e6 100755 --- a/bin/next +++ b/bin/next @@ -1,8 +1,7 @@ #!/usr/bin/env node import { resolve } from 'path' -import parseArgs from 'minimist' -import { spawn } from 'cross-spawn'; +import { spawn } from 'cross-spawn' const defaultCommand = 'dev' const commands = new Set([ diff --git a/bin/next-build b/bin/next-build index c8a02600..11c6c8a1 100755 --- a/bin/next-build +++ b/bin/next-build @@ -6,7 +6,7 @@ import build from '../server/build' const argv = parseArgs(process.argv.slice(2), { alias: { - h: 'help', + h: 'help' }, boolean: ['h'] }) diff --git a/bin/next-dev b/bin/next-dev index 34b6c758..b5c54dd0 100755 --- a/bin/next-dev +++ b/bin/next-dev @@ -22,7 +22,7 @@ build(dir) .then(async () => { const srv = new Server({ dir, dev: true }) await srv.start(argv.port) - console.log('> Ready on http://localhost:%d', argv.port); + console.log('> Ready on http://localhost:%d', argv.port) }) .catch((err) => { console.error(err) diff --git a/bin/next-start b/bin/next-start index ddd6163d..c5261fd8 100755 --- a/bin/next-start +++ b/bin/next-start @@ -20,7 +20,7 @@ const dir = resolve(argv._[0] || '.') const srv = new Server({ dir }) srv.start(argv.port) .then(() => { - console.log('> Ready on http://localhost:%d', argv.port); + console.log('> Ready on http://localhost:%d', argv.port) }) .catch((err) => { console.error(err) diff --git a/client/head-manager.js b/client/head-manager.js index 4cd5b7fa..7e124738 100644 --- a/client/head-manager.js +++ b/client/head-manager.js @@ -23,7 +23,7 @@ export default class HeadManager { let title if (component) { const { children } = component.props - title = 'string' === typeof children ? children : children.join('') + title = typeof children === 'string' ? children : children.join('') } else { title = DEFAULT_TITLE } @@ -53,7 +53,7 @@ function reactElementToDOM ({ type, props }) { const el = document.createElement(type) for (const p in props) { if (!props.hasOwnProperty(p)) continue - if ('children' === p || 'dangerouslySetInnerHTML' === p) continue + if (p === 'children' || p === 'dangerouslySetInnerHTML') continue const attr = HTMLDOMPropertyConfig.DOMAttributeNames[p] || p.toLowerCase() el.setAttribute(attr, props[p]) @@ -63,7 +63,7 @@ function reactElementToDOM ({ type, props }) { if (dangerouslySetInnerHTML) { el.innerHTML = dangerouslySetInnerHTML.__html || '' } else if (children) { - el.textContent = 'string' === typeof children ? children : children.join('') + el.textContent = typeof children === 'string' ? children : children.join('') } return el } diff --git a/client/next.js b/client/next.js index 09adf75f..7e1c9d1d 100644 --- a/client/next.js +++ b/client/next.js @@ -13,7 +13,7 @@ const { const App = app ? evalScript(app).default : DefaultApp const Component = evalScript(component).default -const router = new Router(location.href, { Component }) +const router = new Router(window.location.href, { Component }) const headManager = new HeadManager() const container = document.getElementById('__next') const appProps = { Component, props, router, headManager } diff --git a/examples/head-elements/pages/index.js b/examples/head-elements/pages/index.js index 71a72f4a..827bd40d 100644 --- a/examples/head-elements/pages/index.js +++ b/examples/head-elements/pages/index.js @@ -5,8 +5,8 @@ export default () => (
    This page has a title 🤔 - - + +

    This page has a title 🤔

    diff --git a/examples/hello-world/pages/index.js b/examples/hello-world/pages/index.js index d1b17869..a5e64a34 100644 --- a/examples/hello-world/pages/index.js +++ b/examples/hello-world/pages/index.js @@ -1,5 +1,5 @@ import React from 'react' import Link from 'next/link' export default () => ( -
    Hello World. About
    +
    Hello World. About
    ) diff --git a/examples/nested-components/pages/index.js b/examples/nested-components/pages/index.js index ef0c632a..e78df55f 100644 --- a/examples/nested-components/pages/index.js +++ b/examples/nested-components/pages/index.js @@ -5,14 +5,14 @@ import { css, StyleSheet } from 'next/css' export default () => (
    - +

    Hello there

    This is an example of a componentized blog post


    - +

    Hello there

    This is another example.

    Wa-hoo!

    @@ -20,7 +20,7 @@ export default () => (
    - +

    C'est fin

    diff --git a/gulpfile.js b/gulpfile.js index 5dd598be..1b8c55a0 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -86,7 +86,7 @@ gulp.task('copy-bench-fixtures', () => { }) gulp.task('build', [ - 'build-dev-client', + 'build-dev-client' ]) gulp.task('build-release', [ diff --git a/lib/document.js b/lib/document.js index 07827b6e..65cff06a 100644 --- a/lib/document.js +++ b/lib/document.js @@ -14,11 +14,11 @@ export default class Document extends Component { render () { return - + -
    - - +
    + + } @@ -30,14 +30,14 @@ export function Head (props, context) { .map((h, i) => React.cloneElement(h, { key: '_next' + i })) return {h} -