美文网首页
Vue ssr vue-server-renderer 学习

Vue ssr vue-server-renderer 学习

作者: 岚枫丶 | 来源:发表于2018-08-30 11:56 被阅读0次

    前言


    现在Vue的ssr方案,在我了解到的有如下几种:

    1. vue-server-renderer服务端渲染
    2. prerender-spa-plugin客户端的静态页面生成
    3. Nuxt.js 一个vue的服务端渲染框架,容易上手。

    本文主要参考vue官网的ssr文档,研究学习,其中代码比较碎片,所以自己整理出来并且运行成功。
    vue ssr官网文档


    package.json

    {
      "name": "ssr-demo",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "server": "webpack --config ./build/webpack.server.conf.js",
        "client": "webpack --config ./build/webpack.client.conf.js"
      },
      "author": "lanfeng",
      "license": "ISC",
      "dependencies": {
        "babel-polyfill": "^6.26.0",
        "express": "^4.16.3",
        "vue": "^2.5.17",
        "vue-router": "^3.0.1",
        "vue-server-renderer": "^2.5.17"
      },
      "devDependencies": {
        "babel": "^6.23.0",
        "babel-core": "^6.26.3",
        "babel-loader": "^7.1.1",
        "babel-plugin-transform-runtime": "^6.23.0",
        "babel-preset-env": "^1.7.0",
        "babel-preset-stage-0": "^6.24.1",
        "css-loader": "^1.0.0",
        "style-loader": "^0.23.0",
        "vue-loader": "^11.1.4", // 这个地方有一个坑,最新版本是15以上,刚开始用的时候生成的js好像有些问题,以后再验证怎么解决
        "vue-template-compiler": "^2.5.17",
        "webpack": "^3.6.0",
        "webpack-merge": "^4.1.4",
        "webpack-node-externals": "^1.7.2"
      }
    }
    

    项目结构

    图1

    build&entry

    在ssr指南中,主要是构建配置这一块代码有小部分缺失,所以在这里主要指出配置模块详细代码

    webpack.base.config.js
    module.exports = {
      module: {
        rules: [{
          test: /\.vue$/,
          loader: 'vue-loader',
        },
          {
            test: /\.js$/,
            loader: 'babel-loader',
            exclude: /node_modules/
          }
        ]
      },
      plugins: [],
      resolve: {
        alias: {
          'vue$': 'vue/dist/vue.esm.js'
        }
      }
    }
    
    webpack.server.conf.js
    const merge = require('webpack-merge')
    const nodeExternals = require('webpack-node-externals')
    const baseConfig = require('./webpack.base.config.js')
    const VueSSRServerPlugin = require('vue-server-renderer/server-plugin')
    
    const path = require('path');
    const root= path.resolve(__dirname, '..');
    
    module.exports = merge(baseConfig, {
      // 将 entry 指向应用程序的 server entry 文件
      entry: path.join(root, 'entry/entry-server.js'),
    
      // 这允许 webpack 以 Node 适用方式(Node-appropriate fashion)处理动态导入(dynamic import),
      // 并且还会在编译 Vue 组件时,
      // 告知 `vue-loader` 输送面向服务器代码(server-oriented code)。
      target: 'node',
    
      // 对 bundle renderer 提供 source map 支持
      devtool: 'source-map',
    
      // 此处告知 server bundle 使用 Node 风格导出模块(Node-style exports)
      output: {
        libraryTarget: 'commonjs2',
        path: path.join(root, 'dist'),
        filename: 'bundle.server.js'
      },
    
      // https://webpack.js.org/configuration/externals/#function
      // https://github.com/liady/webpack-node-externals
      // 外置化应用程序依赖模块。可以使服务器构建速度更快,
      // 并生成较小的 bundle 文件。
      externals: nodeExternals({
        // 不要外置化 webpack 需要处理的依赖模块。
        // 你可以在这里添加更多的文件类型。例如,未处理 *.vue 原始文件,
        // 你还应该将修改 `global`(例如 polyfill)的依赖模块列入白名单
        whitelist: /\.css$/
      }),
    
      // 这是将服务器的整个输出
      // 构建为单个 JSON 文件的插件。
      // 默认文件名为 `vue-ssr-server-bundle.json`
      plugins: [
        new VueSSRServerPlugin()
      ]
    })
    
    webpack.client.conf.js
    const webpack = require('webpack')
    const merge = require('webpack-merge')
    const baseConfig = require('./webpack.base.config.js')
    const VueSSRClientPlugin = require('vue-server-renderer/client-plugin')
    
    const path = require('path');
    const root= path.resolve(__dirname, '..');
    module.exports = merge(baseConfig, {
      entry: path.join(root, 'entry/entry-client.js'),
      output: {
        path: path.join(root, 'dist'),
        filename: 'bundle.client.js'
      },
      plugins: [
        // 重要信息:这将 webpack 运行时分离到一个引导 chunk 中,
        // 以便可以在之后正确注入异步 chunk。
        // 这也为你的 应用程序/vendor 代码提供了更好的缓存。
        new webpack.optimize.CommonsChunkPlugin({
          name: 'manifest',
          filename: 'manifest.js',
          minChunks: Infinity
        }),
        // 此插件在输出目录中
        // 生成 `vue-ssr-client-manifest.json`。
        new VueSSRClientPlugin()
      ]
    })
    
    entry-server.js
    /* entry-server.js */
    import { createApp } from '../src/app'
    
    export default context => {
      return new Promise((resolve, reject) => {
        const {app, router} = createApp()
        // 更改路由
        router.push(context.url)
        // 等到 router 将可能的异步组件和钩子函数解析完
        router.onReady(() => {
          const matchedComponents = app.$router.getMatchedComponents()
          // 匹配不到的路由,执行 reject 函数,并返回 404
          if (!matchedComponents.length) { return reject({code: 404}) }
          // Promise 应该 resolve 应用程序实例,以便它可以渲染
          resolve(app)
        }, reject)
      })
    
    }
    
    entry-client.js
    import { createApp } from '../src/app'
    // 客户端特定引导逻辑……
    const {app} = createApp()
    // 这里假定 App.vue 模板中根元素具有 `id="app"`
    app.$mount('#app')
    

    基本上配置就是这样子了。其他就可以参考官方的代码例子。构建这块就没有问题,最后就是server.js

    server.js

    /* server.js */
    const path = require('path')
    const express = require('express')
    const app = express()
    const { createBundleRenderer } = require('vue-server-renderer')
    
    // 创建renderer
    const template = require('fs').readFileSync('./index.ssr.html', 'utf-8')
    const serverBundle = require('./dist/vue-ssr-server-bundle.json')
    const clientManifest = require('./dist/vue-ssr-client-manifest.json') // 这个可以动态将生成的js文件渲染到html模版中
    const renderer = createBundleRenderer(serverBundle, {
      runInNewContext: false, // 推荐
      template: template,
      clientManifest: clientManifest
    })
    
    app.use(express.static(path.join(__dirname, 'dist')))
    // 响应路由请求
    app.get('*', (req, res) => {
      const context = { url: req.url }
      // 创建vue实例,传入请求路由信息
      renderer.renderToString(context, (err, html) => {
        if (err) {
          return res.state(500).end('运行时错误')
        }
        res.send(html)
      })
    })
    
    // 服务器监听地址
    app.listen(8099, () => {
      console.log('服务器已启动!')
    })
    

    总结

    基本上到这个地方关键性构建以及服务模块代码补充完成。一个简单的基于vue-server-renderer例子就可以运行起来。

    相关文章

      网友评论

          本文标题:Vue ssr vue-server-renderer 学习

          本文链接:https://www.haomeiwen.com/subject/zzerwftx.html