improve render

This commit is contained in:
nkzawa 2016-10-10 13:24:30 +09:00
parent a8dcb52ac5
commit 4f21383e0f
3 changed files with 60 additions and 39 deletions

View file

@ -37,10 +37,10 @@ export function Head (props, context) {
Head.contextTypes = { _documentProps: PropTypes.any }
export function Main (props, context) {
const { html, data } = context._documentProps;
const { html, data, staticMarkup } = context._documentProps;
return <div>
<div id='__next' dangerouslySetInnerHTML={{ __html: html }} />
<script dangerouslySetInnerHTML={{ __html: '__NEXT_DATA__ = ' + htmlescape(data) }} />
{staticMarkup ? null : <script dangerouslySetInnerHTML={{ __html: '__NEXT_DATA__ = ' + htmlescape(data) }} />}
</div>
}
@ -54,7 +54,8 @@ export function DevTools (props, context) {
DevTools.contextTypes = { _documentProps: PropTypes.any }
export function NextScript (props, context) {
const { dev } = context._documentProps;
const { dev, staticMarkup } = context._documentProps;
if (staticMarkup) return null
const src = !dev ? '/_next/next.bundle.js' : '/_next/next-dev.bundle.js'
return <script type='text/javascript' src={src}/>
}

View file

@ -31,14 +31,12 @@ export default class Server {
await this.serveStatic(req, res, p)
})
this.router.get('/:path+.json', async (req, res, params) => {
const path = (params.path || []).join('/')
await this.renderJSON(path, req, res)
this.router.get('/:path+.json', async (req, res) => {
await this.renderJSON(req, res)
})
this.router.get('/:path*', async (req, res, params) => {
const path = (params.path || []).join('/')
await this.render(path, req, res)
this.router.get('/:path*', async (req, res) => {
await this.render(req, res)
})
await new Promise((resolve, reject) => {
@ -58,33 +56,11 @@ export default class Server {
}
}
async render (path, req, res) {
async render (req, res) {
const { dir, dev } = this
let html
try {
html = await render(path, { req, res }, { dir, dev })
} catch (err) {
let statusCode
if ('ENOENT' === err.code) {
statusCode = 404
} else {
console.error(err)
statusCode = 500
}
res.statusCode = err.statusCode = statusCode
html = await render('_error', { req, res, err }, { dir, dev })
}
res.setHeader('Content-Type', 'text/html')
res.setHeader('Content-Length', Buffer.byteLength(html))
res.end(html)
}
async renderJSON (path, req, res) {
const { dir } = this
let json
try {
json = await renderJSON(path, { dir })
html = await render(req.url, { req, res }, { dir, dev })
} catch (err) {
if ('ENOENT' === err.code) {
res.statusCode = 404
@ -92,7 +68,25 @@ export default class Server {
console.error(err)
res.statusCode = 500
}
json = await renderJSON('_error', { dir })
html = await render('/_error', { req, res, err }, { dir, dev })
}
sendHTML(res, html)
}
async renderJSON (req, res) {
const { dir } = this
let json
try {
json = await renderJSON(req.url, { dir })
} catch (err) {
if ('ENOENT' === err.code) {
res.statusCode = 404
} else {
console.error(err)
res.statusCode = 500
}
json = await renderJSON('/_error.json', { dir })
}
const data = JSON.stringify(json)
@ -101,6 +95,14 @@ export default class Server {
res.end(data)
}
async render404 (req, res) {
const { dir, dev } = this
res.statusCode = 404
const html = await render('/_error', { req, res }, { dir, dev })
sendHTML(res, html)
}
serveStatic (req, res, path) {
return new Promise((resolve, reject) => {
send(req, path)
@ -116,3 +118,9 @@ export default class Server {
})
}
}
function sendHTML (res, html) {
res.setHeader('Content-Type', 'text/html')
res.setHeader('Content-Length', Buffer.byteLength(html))
res.end(html)
}

View file

@ -1,4 +1,5 @@
import { relative, resolve } from 'path'
import { parse } from 'url'
import { createElement } from 'react'
import { renderToString, renderToStaticMarkup } from 'react-dom/server'
import fs from 'mz/fs'
@ -10,7 +11,12 @@ import Head from '../lib/head'
import App from '../lib/app'
import { StyleSheetServer } from '../lib/css'
export async function render (path, ctx, { dir = process.cwd(), dev = false } = {}) {
export async function render (url, ctx = {}, {
dir = process.cwd(),
dev = false,
staticMarkup = false
} = {}) {
const path = getPath(url)
const p = await requireResolve(resolve(dir, '.next', 'pages', path))
const mod = require(p)
const Component = mod.default || mod
@ -22,10 +28,10 @@ export async function render (path, ctx, { dir = process.cwd(), dev = false } =
const app = createElement(App, {
Component,
props,
router: new Router(ctx.req.url)
router: new Router(ctx.req ? ctx.req.url : url)
})
return renderToString(app)
return (staticMarkup ? renderToStaticMarkup : renderToString)(app)
})
const head = Head.rewind() || []
@ -40,13 +46,19 @@ export async function render (path, ctx, { dir = process.cwd(), dev = false } =
classNames: css.renderedClassNames
},
hotReload: false,
dev
dev,
staticMarkup
})
return '<!DOCTYPE html>' + renderToStaticMarkup(doc)
}
export async function renderJSON (path, { dir = process.cwd() }) {
export async function renderJSON (url, { dir = process.cwd() } = {}) {
const path = getPath(url)
const component = await read(resolve(dir, '.next', '_bundles', 'pages', path))
return { component }
}
function getPath (url) {
return parse(url || '/').pathname.slice(1).replace(/\.json$/, '')
}