当前位置: 首页/ 学苑/走心Share/

尝试prerender-spa-plugin进行服务端渲染

2018-07-09| 阅读:3,483 |类别:走心Share

使用vue做了多个后台管理的多页面应用,项目越积越大,使用静态资源CDN加快了网页访问速度,使用vue的路由懒加载,减少首次加载的js大小,总感觉对于提升单页面的性能和扩充性,没有实质性提升!

一直以来,使用惯了vue,就总想用vue多做一些项目。比如用vue做一些小网站(需要SEO)的应用,进而开始尝试vue的服务端渲染。

1、nuxt.js,一个服务端渲染框架,跟着api尝试去做,就能达到目的。https://zh.nuxtjs.org/guide/installation    ,但是大而全,不易于自主调整,容易被框架自身限制。

2、vue-server-renderer ,https://ssr.vuejs.org/zh/ ,自己根据这个api从头到尾写过至少3次代码,但是总达不到想要的效果(介绍的代码至少局部代码),屡屡半途而废。 参考官方项目https://github.com/vuejs/vue-hackernews-2.0/,依然很难自主调整。后面参考网上的一个简易实践 https://segmentfault.com/a/1190000009554693 ,渐渐了解服务端渲染思路。基于自己更了解vue-cli的搭建构造,于是重新生成脚手架项目,一点一点完善代码,实现了服务端渲染的配置,可以参考https://github.com/Heyff12/vuessr  

3、prerender-spa-plugin,似乎是最简单的一种服务端渲染方式,也是对于原本项目构造影响最少的一种方式。于是,作为娱乐性质,再次开启了关于它的尝试。https://github.com/chrisvfritz/prerender-spa-plugin


一、使用vue-cli构建原始项目

A、vue init webpack webpackSPA

B、根据api进行尝试

1、最进本的设置–webpack.prod.conf.js

const PrerenderSPAPlugin = require('prerender-spa-plugin')  

new PrerenderSPAPlugin({
    // Required - The path to the webpack-outputted app to prerender.
    staticDir: path.join(__dirname, '../dist'),
    // Required - Routes to render.
    routes: ['/'],
})

结果:执行npm  run build,完美得到完整的html页面

2、增加路由——在components文件夹下面新建page1.vue和page2.vue

router文件夹下面的index.js

const HelloWorld = () =>
  import ("@/components/HelloWorld");
const page1 = () =>
  import ("@/components/page1");
const page2 = () =>
  import ("@/components/page2");

export default new Router({
  // mode: 'history',
  scrollBehavior: () => ({
    y: 0
  }),
  routes: [{
      path: '/',
      name: 'HelloWorld',
      component: HelloWorld
    },
    {
      path: '/page1',
      name: 'page1',
      component: page1
    },
    {
      path: '/page2',
      name: 'page2',
      component: page2
    }
  ]
})

webpack.prod.conf.js

new PrerenderSPAPlugin({
    // Required - The path to the webpack-outputted app to prerender.
    staticDir: path.join(__dirname, '../dist'),
    // Required - Routes to render.
    routes: ['/','/page1'],
})

结果:

a、存的page1.html和index.html内容相同
b、
在路由为page2的时候,刷新,则页面报错,不显示
c、将
路由的mode更改成–history,则生成的html相对应;但是没有进行编译的page2在浏览器查看源代码时,为空

const router = new VueRouter({
  routes,
  mode: 'history'
})

d、路由的mode必须是history格式,所有路由都应该写进打包配置里面

new PrerenderSPAPlugin({
    // Required - The path to the webpack-outputted app to prerender.
    staticDir: path.join(__dirname, '../dist'),
    // Required - Routes to render.
    routes: ['/','/page1','/page2'],
})

3、进行prerender-spa-plugin的高级配置

webpack.prod.conf.js

const PrerenderSPAPlugin = require('prerender-spa-plugin')  

const Renderer = PrerenderSPAPlugin.PuppeteerRenderer  


new PrerenderSPAPlugin({
    staticDir: path.join(__dirname, '../dist'),
    routes: ['/','/page1'],

    renderer: new Renderer({
    inject: {
        foo: 'bar'
    },
    headless: false,
    renderAfterDocumentEvent: 'render-event'
    })
})

mian.js

new Vue({
    el: '#app',
    router,
    // components: { App },
    // template: '<App/>'
    render: h => h(App),
    mounted () {
      // You'll need this for renderAfterDocumentEvent.
      document.dispatchEvent(new Event('render-event'))
    }
})

结果:

a、跟2的生成内容一致
b、跟是否异步加载(懒加载)没有关系
c、在路由为page2的时候,刷新,则页面报错,不显示

d、路由的mode必须是history格式,所有路由都应该写进打包配置里面

4、测试了路由,下面测试数据,通过ajax请求,执行步骤在生命周期created

这个改动在page1页面,封装了axios进行数据获取;同时,通过mockjs模拟了返回数据(mock文件夹)

created: function() {
    this.get_info();
},
methods: {
    //获取信息
    get_info: function() {
      this.$ajax_axios.ajax_get(this, this.listUrl, "", data_return => {
        this.list = data_return.data;
      });
    }
}

封装axios(util/ajax_axios.js),在main.js中注册

//ajax请求通用---------------------------------------------------------------------------------------------
import ajax_axios from "./util/ajax_axios"
Vue.prototype.$ajax_axios = ajax_axios //设置ajax请求全局变量

在mian.js中开启mock数据

//本地模拟数据-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
import '../mock/global'

npm run build结果:

a、通过mock,可以获取到内容,源代码里面 有mock返回的数据
b、取消mock,则在page1页面会有请求发出,404

5、安装vuex,增加store目录,在actions里面进行ajax获取数据

a、通过mock,可以获取到内容,源代码里面 有mock返回的数据

b、取消mock,则在page1页面会有请求发出,404

6、增加server文件夹,通过koa构建服务,查看数据请求

渲染和请求都正常,其中使用了https://www.easy-mock.com/login 构建了数据请求


7、判断是否登录

//路由拦截,未登录返回登录页---------------------------------------------------------------------------------------------
router.beforeEach(({ meta, path }, from, next) => {
    var { auth = true } = meta
    var isLogin = Boolean(store.state.sessionid) //true用户已登录, false用户未登录
        // console.log(auth);
        // console.log(store.state.sessionid);
        // console.log(isLogin);
    if (path == '/login') {
        store.commit('login_ify');
    } else {
        store.commit('login_ifn');
    }
    if (auth && !isLogin && path !== '/login') {
        store.commit('login_ify');
        return next({ path: '/login' })
    }
    next()
});
//请求响应拦截,未登录返回登录页---------------------------------------------------------------------------------------------
axios.interceptors.response.use(data => {
    if (data.data.respcd == 1001) {
        router.replace({
            path: "/login"
        });
        return false;
    } else {
        return data;
    }
});

备注: 路由拦截会导致,打包时,导致无法只能生存‘/’,’/login’两个页面;如果返回登录页面的逻辑没有太多限制,可以取消路由的拦截判断


8、关于多页面系统如何进行服务端渲染

1、既然是多页面,每个页面实现的功能较少,勿需进行服务端渲染(提升速度)——自欺欺人的小想法

2、如果有更好的关于服务端渲染的方法,欢迎进行探讨

服务端渲染, 觉得有用,烦请给个小赏¥以资鼓励!~~