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:
parent
a8dcb52ac5
commit
4f21383e0f
|
@ -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}/>
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
|
@ -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$/, '')
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue