美文网首页javascript
vue基于vue实现SSR渲染

vue基于vue实现SSR渲染

作者: ysp123 | 来源:发表于2019-03-29 18:13 被阅读0次

    与传统的spa渲染,服务器端渲染可以有更好的seo,更快的内容到达时间(time to content)。但是服务器端渲染并不是必须的,是否使用,需要细细斟酌。本文是一个完整的服务器渲染的实现,结合一个例子实现。同时假如是仅仅几个静态页面,完全可以使用预渲染实现,没必要完全使用服务器实时动态编译html。

    在学习以下内容时请先观看下官方的文档
    基本用法:(vue-server-renderer)注意一下几点
    1、推荐使用 Node.js 版本 6+。
    2、vue-server-renderer 和 vue 必须匹配版本。
    3、vue-server-renderer 依赖一些 Node.js 原生模块,因此只能在 Node.js 中使用。我们可能会提供一个更简单的构建,可以在将来在其他「JavaScript 运行时(runtime)」运行
    基本环境为 vue2.X+koa2,vue2.X和koa2的环境请自行搭建

    npm install  vue-server-render --save
    
    const Koa = require('koa');
    const Vue = require('vue');
    
    const renderer= require('vue-server-renderer').createRenderer({
            template: require('fs').readFileSync('./temp.html', 'utf-8')
    });
    
    const server= new Koa();
    server.use(async ctx=>{
              const app = new Vue({
                        data:{
                                    msg:'hello  vue+node ssr'
                                },
                        template:'<h4>{{msg}}</h4>'
              });
              renderer.renderToString(app, (err, html)=>{
                      if(err){
                                ctx.status = 500;
                        }
                        ctx.body = html;
              })
    });
    server.listen(5000, ()=>{
            console.log('server is start.........');
    })
    

    渲染模板(temp.html)

    <!DOCTYPE html>
    <html lang="en">
        <head>
          <title>title</title>
        </head>
      <body>
        <!--vue-ssr-outlet-->
      </body>
    </html>
    

    以上我们就实现了一个简单的ssr渲染。但是以上内容还不能应用于生产环境,我们以下进一步深入。
    避免状态单列:我们为用户每次请求创建vue实例,如果我们在多个请求之间使用一个共享的实例,很容易导致交叉请求状态污染(cross-request state pollution)。
    因此,我们不应该直接创建一个应用程序实例,而是应该暴露一个可以重复执行的工厂函数,为每个请求创建新的应用程序实例:

    //app.js
    import Vue from 'vue';
    import App from './app.vue';
    export function createApp(){
            const app = new Vue({
                    render:h=>h(App)
              });
          return app;
    }
    
    //app.vue
    <template>
        <div>
            <div class="demo">
                <h1>Simple-webpack demo</h1>
                <p>这是一个简单的  Vue demo</p>
            </div>
        </div>
    </template>
    

    创建client入口文件和server入口文件,并创建对应的webpack文件

    //entry-client.js
    import  { createApp } from  './app.js';
    const app = createApp();
    app.$mount("#app");
    
    //entry-server.js
    import { createApp }  from './app.js';
    const app = createApp();
    return app;
    

    webpack配置:

    //webpack.client.js
    ............
    const  VueSSRClientPluguin  = require('vue-server-renderer/client-plugin');
    ..............
    plugins:[
            new VueSSRClientPluguin()
    ]
    
    //webpack.server.js
    const VueSSRServerPlugin = require('vue-server-renderer/server-plugin');
    ...............
          entry:{
                main:'./entry-server.js'
          },
         output:{
              filename:'server-bundle.js',
              libraryTarget:'commonjs2'
          },
    ............
          plugins:[
               new  VueSSRServerPlugin ()
          ]
    

    执行 webpack.client.js 和 webpack.server.js 文件,会生成 vue-ssr-server-bundle.json 和 vue-ssr-client-manifest.json 两个文件。服务端使用这两个文件解析文件。

    const  Koa = require('koa');
    const Server = new Koa();
    
    const { createBundleRenderer } = require('vue-server-renderer');
    
    const path = require('path');
    const fs = require('fs');
    const template = fs.readFileSync(path.resolve(__dirname, '/temp.html'), 'UTF-8');
    
    const serverBundle = require('./dist/vue-ssr-server-bundle.json');
    const clientMainfest = require('./dist/vue-ssr-client-manifest.json');
    
    const renderer = createBundleRenderer(serverBundle,{
        basedir: path.resolve(__dirname, './dist'),
        runInNewContext: false,
        template,
        clientMainfest
     });
    
    const renderToString = function(context){
            return new Promise((resolve, reject) => {
                    renderer.renderToString(context, (err, html)=>{
                          if(err){
                                  reject(err);
                                }
                        resolve(html);
                    });
            });
    }
    
    Server.use(async ctx =>{
               let html = '';
               try{
                    html  = await renderToString({});
              }catch(err){
                    ctx.throw(500, err)
              }
              ctx.body = html;
    });
    
    Server.listen(5000, ()=>{
                console.log('server is start.........');
    });
    

    这样就完成了vue+node的ssr渲染。

    附上demo的git地址:https://github.com/yspwf/ssr-vue-node-

    相关文章

      网友评论

        本文标题:vue基于vue实现SSR渲染

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