Vue.js SSR Step by Step (3) - 改造 vue/webpack 腳手架

經過前面兩篇文章,寫了一個簡單的支持 vue 同構的 webpack 配置,可是尚未 dev server,不能熱更新和實時編譯,用於開發仍是很是的麻煩。css

Vue 官方的 webpack 腳手架只是針對客戶端的,功能強大,配置齊全。因此在這個官方腳手架的基礎上改了一個支持 #SSR# 的版本,在改的過程當中參考了 GitHub - vuejs/vue-hackernews-2.0: HackerNews clone built with Vue 2.0, vue-router & vuex, with server-side renderinghtml

改事後的源碼在 Github 上,使用方式:vue init wheato/vue-ssr-boilerplate project-name。接下來簡單的說說這個修改的過程。vue

修改代碼

這一部分主要是增長兩個入口 ,修改內容和以前文章還有官方文檔同樣。若是有用到 vue-router 還要修改 route.js,具體修改能夠看官方文檔。有了 vue-router 咱們就能夠在組件裏面定義靜態方法,服務端調用注入數據。webpack

// Foo.vue
<template>
  <div>
    <h2>Foo</h2>
  </div>
</template>

<script>
export default {
  preFetch(data) {
    console.log(data)
  },
  data () {
    return {}
  }
}
</script>複製代碼
// entry-server.js
import { createApp } from './app.js'
export default context => {
  return new Promise((resolve, reject) => {
    const { app, router } = createApp()
    router.push('/foo')
    router.onReady(() => {
      const matchedComponents = router.getMatchedComponents()
      matchedComponents.forEach(p => {
        p.preFetch('數據')
      })
      resolve(app)
    }, reject)
  })
}複製代碼

增長 server.js

server.js 基本上就是從 vue-hackernews-2.0 種複製過來的,作了一些刪減,使用 express,也可使用 Koa。git

修改 webpack.*.conf.js

webpack.prod.conf.js 的修改點:github

  • webpack.prod.conf.js 改爲 webpack.server.conf.js;
  • 去掉 html-webpack-plugin,用了 SSR,不須要在把資源自動注入 html 文件中了;
  • 把壓縮 css 和 js 插件放到條件判斷中,只有生產環境才壓縮文件;
  • 修改入口;
  • 增長 process.env.VUE_ENV = ‘client’
  • 增長 vue-server-renderer client 端插件。

增長 webpack.server.conf.js:web

  • 在 client 基礎上去掉 CommonsChunkPlugin;
  • 修改入口文件,和輸出文件,編譯目標平臺;
  • 增長 vue-server-renderer server 端插件;
  • 增長 extract-text-webpack-plugin,不把 css 編譯進 server 端中;
  • 增長 process.env.VUE_ENV = ‘server’

webpack.dev.conf.js 中增長 vue-server-renderer client 端插件,修改入口爲 entry-client.js。vue-router

修改 dev-server.js

dev-server.js 這部分修改挺大的, 其中 client 的配置使用 webpack.dev.conf.js。vuex

Client 部分沒有太多的改動,必需要使用的兩個插件 webpack-dev-middleware 和 webpack-hot-middleware。增長了 clientCompiler done 事件的回調,把編譯好的 client-bundle 文件保存進 clientManifest 中,頁面刷新的時候服務器渲染就能同步到以前修改過的內容。express

// dev middleware
var clientCompiler = webpack(clientWebpackConfig)
var devMiddleware = require('webpack-dev-middleware')(clientCompiler, {
  publicPath: clientWebpackConfig.output.publicPath,
  noInfo: true
})
app.use(devMiddleware)
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
  clientManifest = JSON.parse(readFile(
    devMiddleware.fileSystem,
    'vue-ssr-client-manifest.json'
  ))
  update()
})
// hot middleware
var hotMiddleware = require('webpack-hot-middleware')(clientCompiler, { heartbeat: 5000 })
app.use(hotMiddleware)複製代碼

Server 部分中,devMiddleware 的代碼更新不到服務端,因此要添加 watch 事件,實時編譯 server-bundle。

// watch and update server renderer
var serverCompiler = webpack(serverWebpackConfig)
var mfs = new MFS()
serverCompiler.outputFileSystem = mfs
serverCompiler.watch({}, (err, stats) => {
  if (err) throw err
  stats = stats.toJson()
  if (stats.errors.length) return
  // read bundle generated by vue-ssr-webpack-plugin
  bundle = JSON.parse(readFile(mfs, 'vue-ssr-server-bundle.json'))
  update()
})
// read template from disk and watch
template = fs.readFileSync(templatePath, 'utf-8')
chokidar.watch(templatePath).on('change', () => {
  template = fs.readFileSync(templatePath, 'utf-8')
  console.log('index.html template updated.')
  hotMiddleware.publish({ action: 'reload' })
})複製代碼

修改 build.js

修改點比較簡單,在 client 端編譯完後,再增長編譯 server 端就能夠。最後修改一下 package.json 的命令。

npm run dev
npm run build
npm run server // 啓動服務器複製代碼

更多的代碼可使用腳手架模板建立一個空項目跑一下看看。

Vue.js SSR Step by Step 系列

相關文章
相關標籤/搜索