vue-服务端渲染3:server/routers/dev-ssr.js

358 阅读1分钟

npm i koa-router -S

const Router = require('koa-router')
const axios = require('axios')
const path = require('path')
const fs = require('fs')
const MemoryFs = require('memory-fs')        //跟node.js中的FS类似。不写入磁盘,输出到memoryFs
const webpack = require('webpack')
const VueServerRender = require('vue-server-renderer')  //服务端渲染  复杂工具

const serverRender = require('./server-render')
const serverConfig = require('../../build/webpack.config.server')    //webpackconfig

const serverCompiler = webpack(serverConfig)   //生成服务端渲染时候的bundle
const mfs = new MemoryFs()
serverCompiler.outputFileSystem = mfs          //指定webpack的输出目录

let bundle     //记录webpack打包生成的新文件

//webpack相关操作
serverCompiler.watch({}, (err, stats) => {         //监听client文件改变,重新打包
  if (err) throw  err                              //打包有错,抛出
  stats = stats.toJson()                           //通过stats监听eslint类的错误
  stats.errors.forEach(err => console.log(err))
  stats.warnings.forEach(warn => console.log(err))

  const bundlePath = path.join(
    serverConfig.output.path,             //webpack配置文件生成的文件
    'vue-ssr-server-bundle.json'          //注意,不是使用的output中使用的文件名
                                          //插件生成的json文件,默认文件名          
  )
 bundle = JSON.parse(mfs.readFileSync(bundlePath, 'utf-8'))
  console.log('new bundle generated')
})   //每次有文件变化,webpack重新打包后,拿到一个新的bundle
//处理服务端渲染,要返回的东西
const handleSSR = async (ctx) => {
  if (!bundle) {                          //初次启动,还没有打包好bundle
    ctx.body = " wait minutes"
    return
  }
  //通过axios发送一个请求给webpackserver,将
  const clientManifestResp = await axios.get(
    'http://127.0.0.1:8000/public/vue-ssr-client-manifest.json' 
    //包含webpack.devserver打包出来的静态文件的路径
    //请求路径: 注意要和 dev端一致   
    //文件名:   由VueClientPlugin(vue-server-render/client-plugin)插件默认自动生成
    //在webpack.config.client.js中配置。  类比上面vue-ssr-server-bundle.json
  )
  const clientManifest = clientManifestResp.data
  const template = fs.readFileSync(              //step1:拿到模板
    path.join(__dirname, '../server.template.ejs'),
    'utf-8'
  )
  const render = VueServerRender                 //step2:创建一个render
    .createBundleRenderer(bundle, {
      inject: false,                  //不用vueServerRender官方提供的template模板
      clientManifest                  //自动生成一个带有script标签的js文件引用的字符串
    })                                //制造一个bundleRender,再去serverRender
  await serverRender(ctx, render, template)
}

const router = new Router()
router.get('*', handleSSR)    //所有请求都通过handleSSR来处理

module.exports = router