使用vue做了多个后台管理的多页面应用,项目越积越大,使用静态资源CDN加快了网页访问速度,使用vue的路由懒加载,减少首次加载的js大小,总感觉对于提升单页面的性能和扩充性,没有实质性提升!
一直以来,使用惯了vue,就总想用vue多做一些项目。比如用vue做一些小网站(需要SEO)的应用,进而开始尝试vue的服务端渲染。
1、nuxt.js,一个服务端渲染框架,跟着api尝试去做,就能达到目的。zh.nuxtjs.org/guide/insta… ,但是大而全,不易于自主调整,容易被框架自身限制。
2、vue-server-renderer ,ssr.vuejs.org/zh/ ,自己根据这个api从头到尾写过至少3次代码,但是总达不到想要的效果(介绍的代码至少局部代码),屡屡半途而废。 参考官方项目github.com/vuejs/vue-h…,依然很难自主调整。后面参考网上的一个简易实践 https://segmentfault.com/a/1190000009554693 ,渐渐了解服务端渲染思路。基于自己更了解vue-cli的搭建构造,于是重新生成脚手架项目,一点一点完善代码,实现了服务端渲染的配置,可以参考github.com/Heyff12/vue…
3、prerender-spa-plugin,似乎是最简单的一种服务端渲染方式,也是对于原本项目构造影响最少的一种方式。于是,作为娱乐性质,再次开启了关于它的尝试。github.com/chrisvfritz…
一、使用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构建服务,查看数据请求
渲染和请求都正常,其中使用了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、如果有更好的关于服务端渲染的方法,欢迎进行探讨