2018-11-11 23:47:41 +08:00
|
|
|
|
const fs = require('fs')
|
|
|
|
|
const path = require('path')
|
|
|
|
|
const chalk = require('chalk')
|
|
|
|
|
const LRU = require('lru-cache')
|
|
|
|
|
const {
|
|
|
|
|
createBundleRenderer
|
|
|
|
|
} = require('vue-server-renderer')
|
|
|
|
|
const isProd = process.env.NODE_ENV === 'production'
|
|
|
|
|
const setUpDevServer = require('./setup-dev-server')
|
|
|
|
|
const HtmlMinifier = require('html-minifier').minify
|
|
|
|
|
|
|
|
|
|
const pathResolve = file => path.resolve(__dirname, file)
|
|
|
|
|
|
|
|
|
|
module.exports = app => {
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
const createRenderer = (bundle, options) => {
|
|
|
|
|
return createBundleRenderer(bundle, Object.assign(options, {
|
|
|
|
|
cache: LRU({
|
|
|
|
|
max: 1000,
|
|
|
|
|
maxAge: 1000 * 60 * 15
|
|
|
|
|
}),
|
|
|
|
|
basedir: pathResolve('../dist/web'),
|
|
|
|
|
runInNewContext: false
|
|
|
|
|
}))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let renderer = null
|
|
|
|
|
if (isProd) {
|
|
|
|
|
// prod mode
|
|
|
|
|
const template = HtmlMinifier(fs.readFileSync(pathResolve('../public/index.html'), 'utf-8'), {
|
|
|
|
|
collapseWhitespace: true,
|
|
|
|
|
removeAttributeQuotes: true,
|
|
|
|
|
removeComments: false
|
|
|
|
|
})
|
|
|
|
|
const bundle = require(pathResolve('../dist/web/vue-ssr-server-bundle.json'))
|
|
|
|
|
const clientManifest = require(pathResolve('../dist/web/vue-ssr-client-manifest.json'))
|
|
|
|
|
renderer = createRenderer(bundle, {
|
|
|
|
|
template,
|
|
|
|
|
clientManifest
|
|
|
|
|
})
|
|
|
|
|
} else {
|
|
|
|
|
// dev mode
|
|
|
|
|
setUpDevServer(app, (bundle, options, apiMain, apiOutDir) => {
|
|
|
|
|
try {
|
|
|
|
|
const API = eval(apiMain).default // eslint-disable-line
|
|
|
|
|
const server = API(app)
|
|
|
|
|
renderer = createRenderer(bundle, options)
|
|
|
|
|
resolve(server)
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.log(chalk.red('\nServer error'), e)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
2018-11-11 23:57:03 +08:00
|
|
|
|
|
2018-11-11 23:47:41 +08:00
|
|
|
|
app.use(async (ctx, next) => {
|
|
|
|
|
if (!renderer) {
|
|
|
|
|
ctx.type = 'html'
|
|
|
|
|
ctx.body = 'waiting for compilation... refresh in a moment.'
|
|
|
|
|
next()
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let status = 200
|
|
|
|
|
let html = null
|
|
|
|
|
const context = {
|
|
|
|
|
url: ctx.url,
|
|
|
|
|
title: 'OK'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (/^\/api/.test(ctx.url)) { // 如果请求以/api开头,则进入api部分进行处理。
|
|
|
|
|
next()
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
status = 200
|
|
|
|
|
html = await renderer.renderToString(context)
|
|
|
|
|
} catch (e) {
|
|
|
|
|
if (e.message === '404') {
|
|
|
|
|
status = 404
|
|
|
|
|
html = '404 | Not Found'
|
|
|
|
|
} else {
|
|
|
|
|
status = 500
|
|
|
|
|
console.log(chalk.red('\nError: '), e.message)
|
|
|
|
|
html = '500 | Internal Server Error'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ctx.type = 'html'
|
|
|
|
|
ctx.status = status || ctx.status
|
|
|
|
|
ctx.body = html
|
|
|
|
|
next()
|
|
|
|
|
})
|
2018-11-11 23:57:03 +08:00
|
|
|
|
|
|
|
|
|
if (isProd) {
|
|
|
|
|
const API = require('../dist/api/api').default
|
|
|
|
|
const server = API(app)
|
|
|
|
|
resolve(server)
|
|
|
|
|
}
|
2018-11-11 23:47:41 +08:00
|
|
|
|
})
|
|
|
|
|
}
|