前言
相信在座的各位肯定都是正人君子,现在生活压力可能有点大,偶尔做做spa放松放松也是无可厚非的。接下来呢各位浴皇大帝可以先收一收自己的小心思,咱们来聊一聊程序员世界中的spa。
spa 是什么?
当我们谈起 spa 大多数人心里想的都是那种放松的方式,但是在程序员的世界中的 spa(single page web application,SPA)指的是单页应用。
说起单页应用想必学过前端的哥们应该并不陌生,目前流行的 Vue3 就是一个单页应用,这种应用有两个特点:
- 整个项目中只有一个页面
- 页面中的内容是动态的,以组件的形式展示,靠路由的方式来映射匹配对应的组件
spa 的优缺点
优点
在简单了解完了 spa 是什么之后,我们来聊一聊它身上的一些特点,首先呢我们来聊聊它身上的一些优点,从它的特点中我们可以看出,这种应用的页面一般是以组件来展示的,而组件就有个非常明显的特点就是组件化开发,易于维护。
如果是一个多页应用的话,我们想要实现不同的url展现不同页面的效果,那么就要写很多的html并且在每次展示的时候都要重新进行请求,而spa却不用。spa 只需要根据不同的路由展现不同的组件即可,组件是全部都加载好的,所以我们在需要展示组件的时候,直接显示即可,不需要重新发送请求,这就带来了它的另一个优点:页面切换快,体验好。
- 组件化开发,易于维护
- 页面切换快,体验好
缺点
正所谓天底下没有十全十美的东西,spa 同样也不例外,它主要是有两个缺点,在上文中我们说到 spa 在初次启动项目的时候就已经将所有组件加载完成,而这一点带来了良好体验的同时,也带来了一个缺点:初次加载慢。
在讲剩下的这个缺点前,我们先来看一个 spa 应用在浏览器上面的源码展示,下面是网上搜的一个网站源代码:
我们通过观察上述代码可以发现,html 中所展示的内容我们在源代码中都看不到,这是因为这些内容都是由 js 来生成的,而这一点呢如果有了解过爬虫的小伙伴可能就会发现这种手段可以很好的防止爬虫爬取数据。
虽然这种手段可以一定程度上防止爬虫,但是也为 SEO(搜索引擎) 带来了负面影响。我们要知道当我们在百度或者别的搜索来中输入关键词的时候,它会通过我们页面的源代码来搜索对应的关键词,这个时候如果我们是通过 js 来渲染的话,那么就可能找不到对应的关键词,这样就无法搜索到我们所有展示的网页了,这就是它的另一个缺点:不利于SEO。
- 首次加载慢
- 不利于 SEO
小结
优点:
- 组件化开发,易于维护
- 页面切换快,体验好
缺点:
- 初次加载慢
- 不利于SEO
ssr
经过前面两小结,相信在座的各位肯定对这个会所的 spa 有一定了解了,经过了一定的体验后发现还有些许的美中不足,接下来我们来为大家解决这个烦恼来认识一下这个会所的金牌技师 SSR(server side render,服务端渲染)。
首先我们得知道 spa 的两个缺点,在上文中我们已经了解了,我们想要解决这两个问题其实很简单,解决初次加载慢这个问题,我们只需要初次加载时优先加载首次展现给用户的组件即可。而解决SEO问题,我们可以将前端的代码传给后端,让后端帮我们将数据进行渲染最后返回即可。
思路:如果我们按需进行加载的话,那么就可以在首次加载时不需要加载所有组件,从而减少了初次加载时间,并且我们将需要首次展现的组件交给后端,让后端帮我们将前端的
template修改成html并且将数据渲染上去,最后将生成的html返回即可,而这个思路就是我们所说的 SSR。
接下来我们来看代码实现,首先我们得先安装个东西:
npm i express
接下来是完整代码:
const express = require('express');
const app = express();
const Vue = require('vue')
const vue3Compiler = require('@vue/compiler-ssr') // 用来编译vue代码,编译器
const renderer = require('@vue/server-renderer') // 用来渲染vue代码,渲染器
// 这里模仿前端传来的要展示在首页的组件
const vueapp = {
template: `
<div>
<h1 @click='add'>Hello, SSR! -- {{count}}</h1>
<ul>
<li v-for="item in items" :key="item">{{ item }}</li>
</ul>
</div>
`,
data() {
return {
count: 0,
items: ['Item 1', 'Item 2', 'Item 3']
}
},
methods: {
add() {
this.count++
// this.items.push(`Item ${this.items.length + 1}`);
}
}
}
// 读取 vue 文件,编译成 js 代码
vueapp.ssrRender = new Function('require', vue3Compiler.compile(vueapp.template).code)(require)
app.get('/', async(req, res) => {
let vapp = Vue.createSSRApp(vueapp)
let html = await renderer.renderToString(vapp) // 渲染成 html
const title = 'SSR Demo'
let ret = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>${title}</title>
</head>
<body>
${html}
</body>
</html>
`
res.send(ret)
})
app.listen(3000, () => {
console.log('Server listening on port 3000');
});
SSR 的原理:
- 启动一个 node 服务
- 前端将需要首次展现给客户的组件传给后端
- 借助 vue 自带的编译器函数编译 vue 组件,得到 AST 语法树
- 借助 vue 自带的渲染器函数渲染 vue 组件,得到代码块
- 将代码块放入 html 模板中
- 响应即可