1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
| // [L3-L5] 替换引入的包
const Koa = require('koa2')
const KoaRuoter = require('koa-router')
const KoaServe = require('./build/serve')
// /build/serve.js 这个是我手写的一个静态文件挂载中间组件
// [L14-L17] 声明创建app和路由对象
const app = new Koa()
const router = new KoaRuoter()
// dev下因为使用原express中间组件,
// 一定要在设置setup-dev-server之前设置api路由。
// 包括普通的静态json文件
const api_router = new KoaRuoter()
// [L20-L44] 更改 serve 函数以便支持koa2,替换原有serve使用的地方
const serve = (url, path, cache) => KoaServe(url, {
root: resolve(path),
maxAge: cache && isProd ? 60 * 60 * 24 * 30 : 0
})
// 模拟api
app.use(serve('/api/topstories.json', './public/api/topstories.json'))
app.use(serve('/api/newstories.json', './public/api/newstories.json'))
// 修改为koa支持
api_router.get('/api/item/:id.json', (ctx, next) => {
const id = ctx.params.id
const time = parseInt(Math.random()*(1487396700-1400000000+1)+1400000000)
const item = {
by: "zero" + id,
descendants: 0,
id: id,
score: id - 13664000,
time: time,
title: `测试Item:${id}-${time}`,
type: 'story',
url: `/api/item/${id}.json`
}
ctx.body = item
})
app.use(api_router.routes()).use(api_router.allowedMethods())
// [L89-L132] ssr的处理转换换为koa2
// 原express 调用res.end会通知express结束,
// koa2则需要使用返回一个Promise来达到异步
router.get('*', (ctx, next) => {
if (!renderer) {
return ctx.body ='waiting for compilation.. refresh in a moment.'
}
ctx.set("Context-Type", "text/html")
ctx.set("Server", serverInfo)
const s = Date.now()
const context = { url: ctx.url }
const renderStream = renderer.renderToStream(context)
const res = ctx.res
return new Promise(function(resolve){
renderStream.once('data', () => {
// 不设置这个会默认404
res.statusCode = 200
res.write(indexHTML.head)
})
renderStream.on('data', chunk => {
res.write(chunk)
})
renderStream.on('end', () => {
if (context.initialState) {
res.write(
`<script>window.__INSTAL_STATE__=${
serialize(context.initialState)
}</script>`
)
}
res.end(indexHTML.tail)
resolve() // 通知koa2异步操作已经结束
console.log(`whole request: ${Date.now() - s}ms`)
})
renderStream.on('error', err => {
if (err && err.code === '404') {
res.statusCode = 404
res.end('404 | Page Not Found')
resolve() // 通知koa2异步操作已经结束
return
}
res.statusCode = 500
res.end('Internal Error 500')
resolve() // 通知koa2异步操作已经结束
console.error(`error during render : ${ctx.url}`)
console.error(err)
})
// [L134] 注册路由
app.use(router.routes()).use(router.allowedMethods())
|