-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdev.server.js
95 lines (85 loc) · 3.63 KB
/
dev.server.js
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
92
93
94
95
const fs = require('fs')
const path = require('path')
const portfinder = require('portfinder')
const express = require('express')
const favicon = require('serve-favicon')
const { createProxyMiddleware } = require('http-proxy-middleware')
const resolve = dir => path.join(__dirname, dir)
let renderer
const app = express()
createRenderer() // 提前生成 renderer (没有生成 renderer 之前不可以访问 express 路由)
app.use('/app', createProxyMiddleware({ target: 'https://www.example.com', changeOrigin: true, secure: false })) // 代理配置
app.use(favicon(resolve('./server/favicon.ico')))
app.use(express.static('./server/public'))
app.get('*', (req, res) => renderer.renderToString({ url: req.url }).then(html => res.send(html)).catch(error => handleError(error, res)))
portfinder.getPort((error, port) => {
if (error) {
console.log(error) // eslint-disable-line no-console
process.exit(1)
}
app.listen(port, '0.0.0.0', () => console.log(`server started at http://0.0.0.0:${port}`)) // eslint-disable-line no-console
})
function handleError(error, res) {
const status = error?.response?.status
console.log('===================== Server Error =====================') // eslint-disable-line no-console
console.log(status, error?.response?.data || error) // eslint-disable-line no-console
if (status === 401) res.redirect('/signin')
else if (status === 404) res.redirect('/404')
else if (status === 403) res.redirect('/404')
else res.status(500).send('Internal Server Error')
}
/*
*
*
*
*
*
* 创建 render 给 app 使用
*/
function createRenderer() {
const webpack = require('webpack')
const { createBundleRenderer } = require('vue-server-renderer')
// 更新 renderer
let [serverBundle, clientManifest] = []
const update = async () => {
if (serverBundle && clientManifest) {
renderer = await createBundleRenderer(serverBundle, { // 更新 renderer
runInNewContext: false,
clientManifest,
template: fs.readFileSync(resolve('./server/template.html'), 'utf-8'),
})
}
}
// server (不需要热更新)
const MFS = require('memory-fs')
const mfs = new MFS()
const serverConfig = require('./build/webpack.server.config')
const serverComplier = webpack(serverConfig)
serverComplier.outputFileSystem = mfs
serverComplier.watch({}, (error, stats) => {
if (error) throw error
stats = stats.toJson()
if (stats.errors.length) return
serverBundle = JSON.parse(mfs.readFileSync(path.join(serverConfig.output.path, 'vue-ssr-server-bundle.json')))
update()
})
// client
const webpackDevMiddleware = require('webpack-dev-middleware')
const webpackHotMiddleware = require('webpack-hot-middleware')
const clientConfig = require('./build/webpack.client.config')
// 修改入口 -> 热更新
clientConfig.entry = ['webpack-hot-middleware/client?quiet=true&reload=true&overlay=false', clientConfig.entry]
clientConfig.plugins.push(new webpack.HotModuleReplacementPlugin())
const clientComplier = webpack(clientConfig)
const clientMiddleware = webpackDevMiddleware(clientComplier, { logLevel: 'silent' })
app.use(clientMiddleware)
app.use(webpackHotMiddleware(clientComplier)) // 热更新
clientComplier.hooks.done.tap('done', stats => { // 注册事件
stats = stats.toJson()
stats.warnings.forEach(error => console.warn(error)) // eslint-disable-line no-console
stats.errors.forEach(error => console.error(error)) // eslint-disable-line no-console
if (stats.errors.length) return
clientManifest = JSON.parse(clientMiddleware.fileSystem.readFileSync(path.join(clientConfig.output.path, 'vue-ssr-client-manifest.json')))
update()
})
}