step-02 初识vue-ssr

陆和泰
2023-12-01

在vue-ssr中,vue会运行在客户端和服务端,首先安装vue-server-renderer和vue,它们版本必须匹配。
先在根目录创建server.js

//现在是在nodejs环境下,使用commonjs导入 
const Vue = require('vue')
const vueRenderer = require('vue-server-renderer')

const vueApp = new Vue({
    data() {
        return { str: 'Hello Vue SSR'}
    },
    template: '<div>{{str}}</div>'
})

const renderer = vueRenderer.createRenderer()

renderer.renderToString(vueApp).then(html => {
    console.log(html)
}).catch(err => {
    console.log(err)
})

这时执行改文件(node server.js)可以发现打印出了<div data-server-rendered="true">Hello Vue SSR</div>,vue-server-renderer已经将vue的template解析成了html。
将它加入到服务器,我使用的是koa,server.js的代码为

const Vue = require('vue')
const vueRenderer = require('vue-server-renderer')
const Koa = require('koa')
const KoaRouter = require('koa-router')

const koaApp = new Koa()
const router = new KoaRouter()

const vueApp = new Vue({
    data() {
        return { str: 'hello Vue SSR'}
    },
    template: '<div>{{str}}</div>'
})
router.get('/', async ctx => {
    const renderer = vueRenderer.createRenderer()
    //也可以使用回调函数的方式  renderer.renderToString(app, callback)
    await renderer.renderToString(vueApp).then(html => {
        ctx.body = `<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>vue ssr</title>
</head>
<body>
    ${html}
</body>
</html>
        `
    }).catch(err => {
        console.log(err)
    })
})

koaApp.use(router.routes())
koaApp.listen(3019, () => { console.log('server started at 3019') })

浏览器打开localhost:3019 可以发现服务器返回的是html代码

vue-server-renderer 内有2个方法,分别是createRenderer和createBundleRenderer,具体的参数和返回值可以查看源码vue-server-renderer的index.d.ts文件。
createRenderer参数是一个可省略的对象,对象的属性有template、cache等也可省略。
createBundleRenderer接收2个参数bundle和options,bundle为一个字符串或者对象,字符串必须是一个js或者json的绝对路径,或者由webpack + vue-server-renderer/server-plugin生成的bundle对象(JavaScript代码字符串也行,官方不推荐),第二个参数是一个可以选对象,属性包括createRenderer参数的属性外还有clientManifest,runInNewContext等属性,所有属性都是可省略的。

//源码index.d.ts
export declare function createRenderer(options?: RendererOptions): Renderer;
export declare function createBundleRenderer(bundle: string | object, options?: BundleRendererOptions): BundleRenderer;

源代码对createBundleRenderer参数bundle的判断

    if (
      typeof bundle === 'string' &&
      /\.js(on)?$/.test(bundle) &&
      path$2.isAbsolute(bundle)    //var path$2 = require('path');
    ) {
      if (fs.existsSync(bundle)) {
        var isJSON = /\.json$/.test(bundle);
        basedir = basedir || path$2.dirname(bundle);
        bundle = fs.readFileSync(bundle, 'utf-8');
        if (isJSON) {
          try {
            bundle = JSON.parse(bundle);
          } catch (e) {
            throw new Error(("Invalid JSON bundle file: " + bundle))
          }
        }
      } else {
        throw new Error(("Cannot locate bundle file: " + bundle))
      }
    }

    if (typeof bundle === 'object') {
      entry = bundle.entry;
      files = bundle.files;
      basedir = basedir || bundle.basedir;
      maps = createSourceMapConsumers(bundle.maps);
      if (typeof entry !== 'string' || typeof files !== 'object') {
        throw new Error(INVALID_MSG)
      }
    } else if (typeof bundle === 'string') {
      entry = '__vue_ssr_bundle__';
      files = { '__vue_ssr_bundle__': bundle };
      maps = {};
    } else {
      throw new Error(INVALID_MSG)
    }

这2个方法都将返回renderToString和renderToStream方法,从命名就可以看出renderToString返回的是html字符串,renderToStream返回的是Node.js Stream(流)。
createRenderer返回的renderToString第一个参数是一个Vue实例,第二个参数可以为context对象或者回调函数(可选),当第二个参数为context时,第三个参数为回调函数(可选)。当没有回调函数作为参数时将返回一个promise对象。

//源码index.d.ts
type RenderCallback = (err: Error | null, html: string) => void;
interface Renderer {
  renderToString(vm: Vue, callback: RenderCallback): void;
  renderToString(vm: Vue, context: object, callback: RenderCallback): void;
  renderToString(vm: Vue): Promise<string>;
  renderToString(vm: Vue, context: object): Promise<string>;

  renderToStream(vm: Vue, context?: object): Readable;
}

createBundleRenderer返回的renderToString第一个参数为context或者回调函数,当第一个参数时context时回调函数为第二参数,参数都是可选的。
当没有回调函数作为参数时将返回一个promise对象。

interface BundleRenderer {
  renderToString(callback: RenderCallback): void;
  renderToString(context: object, callback: RenderCallback): void;
  renderToString(): Promise<string>;
  renderToString(context: object): Promise<string>;

  renderToStream(context?: object): Readable;
}

源码地址

上一篇: step-01 搭建一个简易的vue
下一篇: step-03 开始vue-ssr

 类似资料: