Koa2+Vue SSR+webpack热更新的详细配置

2020-3-30 23:27:50
学习记录
213

Koa2+Vue SSR+webpack热更新的详细配置

由于最近做博客前台需要改界面,不能每次修改就重新打包一次吧,太费时费力了,索性我就花了2天时间,研究了一下基于koa2的webpack热更新。

本文主要讲解setup-dev-middleware.js的配置和使用

需要用到的第三方依赖包

  • Koa-webpack-dev-middleware

  • koa-webpack-hot-middleware

  • koa-convert

    koa-convert是必须的,因为Koa-webpack-dev-middlewarekoa-webpack-hot-middleware是koa1的插件,需要进行转换

配置koa版本的setup-dev-middleware.js

  • 定义服务器端bundle和浏览器端manifest

    let bundle; let template = fs.readFileSync(templatePath, 'utf-8'); let clientManifest; //update检测到有更新后,调用传递过来的回调函数,一般是createBundleRenderer这个函数。 const update = () => { if (bundle && clientManifest) { callback(bundle, { template, clientManifest }) } }
  • 修改client端入口配置文件,注意配置文件需要

    clientConfig.entry.app = ['webpack-hot-middleware/client?path=/__webpack_hmr&timeout=2000&reload=true', clientConfig.entry.app] clientConfig.output.filename = '[name].js' clientConfig.plugins.push( new webpack.HotModuleReplacementPlugin(), new webpack.NoEmitOnErrorsPlugin() )
  • 配置koa-webpack-dev-middleware,这里需要传递浏览器端的Compiler

    注意:这里使用devMiddleware的时候需要先调用convert()把koa1的包转成koa2可以用的包

    const clientCompiler = webpack(clientConfig) const devMiddleware = webpackDevMiddleware(clientCompiler, { publicPath: clientConfig.output.publicPath,//必选参数,定义启动后的默认访问路径,填错可导致404 noInfo: true,//可选 stats: {//可选 colors: true, modules: false, }, }) app.use(convert(devMiddleware))
  • 配置订阅热更新

    注意:这里使用webpackHotMiddleware也需要包裹convert()

    // hot update clientCompiler.plugin('done', stats => { stats = stats.toJson() stats.errors.forEach(err => console.error(err)) stats.warnings.forEach(err => console.warn(err)) if (stats.errors.length) return console.log('\nclient-dev...\n') clientManifest = JSON.parse(readFile( devMiddleware.fileSystem, 'vue-ssr-client-manifest.json' )) update() }) // hot middleware app.use(convert(webpackHotMiddleware(clientCompiler)))
  • 配置服务端热更新

    const serverCompiler = webpack(serverConfig) const mfs = new MFS() serverCompiler.outputFileSystem = mfs serverCompiler.watch({}, (err, stats) => { if (err) throw err stats = stats.toJson() if (stats.errors.length) return console.log('server-dev...') bundle = JSON.parse(readFile(mfs, 'vue-ssr-server-bundle.json')) update() })

完整代码

const path = require('path') const MFS = require('memory-fs') const webpack = require('webpack') const clientConfig = require('./webpack.client.config') const serverConfig = require('./webpack.server.config') const webpackDevMiddleware = require('koa-webpack-dev-middleware') const webpackHotMiddleware = require('koa-webpack-hot-middleware') const convert = require('koa-convert') const fs = require('fs'); const opn = require('opn') const readFile = (fs, file) => fs.readFileSync(path.join(clientConfig.output.path, file), 'utf-8') module.exports = function setupDevServer(app, uri, callback) { let bundle; let template = fs.readFileSync(uri, 'utf-8') let clientManifest const update = () => { if (bundle && clientManifest) { callback(bundle, { template, clientManifest }) } } // client clientConfig.entry.app = ['webpack-hot-middleware/client?path=/__webpack_hmr&timeout=2000&reload=true', clientConfig.entry.app] clientConfig.output.filename = '[name].js' clientConfig.plugins.push( new webpack.HotModuleReplacementPlugin(), new webpack.NoEmitOnErrorsPlugin() ) // webpack config const clientCompiler = webpack(clientConfig) // dev middleware const devMiddleware = webpackDevMiddleware(clientCompiler, { publicPath: clientConfig.output.publicPath, noInfo: true, stats: { colors: true, modules: false, }, }) app.use(convert(devMiddleware)) // hot update clientCompiler.plugin('done', stats => { stats = stats.toJson() stats.errors.forEach(err => console.error(err)) stats.warnings.forEach(err => console.warn(err)) if (stats.errors.length) return console.log('\nclient-dev...\n') clientManifest = JSON.parse(readFile( devMiddleware.fileSystem, 'vue-ssr-client-manifest.json' )) update() }) // hot middleware app.use(convert(webpackHotMiddleware(clientCompiler))) // server const serverCompiler = webpack(serverConfig) const mfs = new MFS() serverCompiler.outputFileSystem = mfs serverCompiler.watch({}, (err, stats) => { if (err) throw err stats = stats.toJson() if (stats.errors.length) return console.log('server-dev...') bundle = JSON.parse(readFile(mfs, 'vue-ssr-server-bundle.json')) update() }) devMiddleware.waitUntilValid(() => { console.log('\n> Listening at http://localhost:3001' + '' + '\n') opn('http://localhost:3001/'); }) }

调用setup-dev-middleware

const setupDevServer = require('./build/setup-dev-middleware'); let renderer; setupDevServer(app, './template.html', (bundle, options) => { try { renderer = createBundleRenderer(bundle, options) } catch (e) { console.log('\nbundle errorasdasd', e) } }) const renderData = (ctx, renderer) => { const context = { url: ctx.url } return new Promise((resolve, reject) => { renderer.renderToString(context, (err, html) => { if (err) { return reject(err) } resolve(html) }) }) } app.use(async (ctx, next) => { let html, status; try { status = 200 html = await renderData(ctx, renderer) } catch (e) { console.log('\ne', e) if (e.code === 404) { status = 404 html = '404 | Not Found' } else { status = 500 html = '500 | Internal Server Error' } } ctx.type = 'html' ctx.status = status ? status : ctx.status ctx.body = html })

有疑问可以在下方评论或者联系我哈!

下一片预告:

欢迎关注我的个人博客,第一时间发布最新内容:小新的个人博客,完整源码在我的github:完整源码
Koa2+Vue SSR+webpack热更新的详细配置

avatar

Sky(小新)

个人签名: 提升能力,创造价值!

江苏-南京
skylpz@qq.com