1
0
Fork 0
mirror of https://github.com/terribleplan/next.js.git synced 2024-01-19 02:48:18 +00:00

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

View file

@ -31,14 +31,12 @@ export default class Server {
await this.serveStatic(req, res, p) await this.serveStatic(req, res, p)
}) })
this.router.get('/:path+.json', async (req, res, params) => { this.router.get('/:path+.json', async (req, res) => {
const path = (params.path || []).join('/') await this.renderJSON(req, res)
await this.renderJSON(path, req, res)
}) })
this.router.get('/:path*', async (req, res, params) => { this.router.get('/:path*', async (req, res) => {
const path = (params.path || []).join('/') await this.render(req, res)
await this.render(path, req, res)
}) })
await new Promise((resolve, reject) => { 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 const { dir, dev } = this
let html let html
try { try {
html = await render(path, { req, res }, { dir, dev }) html = await render(req.url, { 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 })
} catch (err) { } catch (err) {
if ('ENOENT' === err.code) { if ('ENOENT' === err.code) {
res.statusCode = 404 res.statusCode = 404
@ -92,7 +68,25 @@ export default class Server {
console.error(err) console.error(err)
res.statusCode = 500 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) const data = JSON.stringify(json)
@ -101,6 +95,14 @@ export default class Server {
res.end(data) 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) { serveStatic (req, res, path) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
send(req, path) 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 { relative, resolve } from 'path'
import { parse } from 'url'
import { createElement } from 'react' import { createElement } from 'react'
import { renderToString, renderToStaticMarkup } from 'react-dom/server' import { renderToString, renderToStaticMarkup } from 'react-dom/server'
import fs from 'mz/fs' import fs from 'mz/fs'
@ -10,7 +11,12 @@ import Head from '../lib/head'
import App from '../lib/app' import App from '../lib/app'
import { StyleSheetServer } from '../lib/css' 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 p = await requireResolve(resolve(dir, '.next', 'pages', path))
const mod = require(p) const mod = require(p)
const Component = mod.default || mod const Component = mod.default || mod
@ -22,10 +28,10 @@ export async function render (path, ctx, { dir = process.cwd(), dev = false } =
const app = createElement(App, { const app = createElement(App, {
Component, Component,
props, 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() || [] const head = Head.rewind() || []
@ -40,13 +46,19 @@ export async function render (path, ctx, { dir = process.cwd(), dev = false } =
classNames: css.renderedClassNames classNames: css.renderedClassNames
}, },
hotReload: false, hotReload: false,
dev dev,
staticMarkup
}) })
return '<!DOCTYPE html>' + renderToStaticMarkup(doc) 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)) const component = await read(resolve(dir, '.next', '_bundles', 'pages', path))
return { component } return { component }
} }
function getPath (url) {
return parse(url || '/').pathname.slice(1).replace(/\.json$/, '')
}