什么是服务器端渲染 (SSR)?
Vue.js 是构建客户端应用程序的框架。默认情况下,可以在浏览器中输出 Vue 组件,进行生成 DOM 和操作 DOM。然而,也可以将同一个组件渲染为服务器端的 HTML 字符串,将它们直接发送到浏览器,最后将这些静态标记"激活"为客户端上完全可交互的应用程序。
服务器渲染的 Vue.js 应用程序也可以被认为是"同构"或"通用",因为应用程序的大部分代码都可以在服务器和客户端上运行。
为什么使用服务器端渲染 (SSR)?
- 与传统 SPA (单页应用程序 (Single-Page Application)) 相比,服务器端渲染 (SSR) 的优势主要在于:
- 更好的SEO,由于搜索引擎爬虫抓取工具可以直接查看完全渲染的页面。
请注意,截至目前,Google 和 Bing 可以很好对同步 JavaScript 应用程序进行索引。在这里,同步是关键。如果你的应用程序初始展示 loading 菊花图,然后通过 Ajax 获取内容,抓取工具并不会等待异步完成后再行抓取页面内容。也就是说,如果 SEO 对你的站点至关重要,而你的页面又是异步获取内容,则你可能需要服务器端渲染(SSR)解决此问题。 - 更快的内容到达时间 (time-to-content),特别是对于缓慢的网络情况或运行缓慢的设备。无需等待所有的 JavaScript 都完成下载并执行,才显示服务器渲染的标记,所以你的用户将会更快速地看到完整渲染的页面。通常可以产生更好的用户体验,并且对于那些「内容到达时间(time-to-content) 与转化率直接相关」的应用程序而言,服务器端渲染 (SSR) 至关重要。
- 更好的SEO,由于搜索引擎爬虫抓取工具可以直接查看完全渲染的页面。
- 使用服务器端渲染 (SSR) 时还需要有一些权衡之处:
- 开发条件所限。浏览器特定的代码,只能在局限于某些生命周期钩子函数(beforeCreate&&created(lifecycle hook) 中使用;一些外部扩展库 (external library) 可能需要特殊处理,才能在服务器渲染应用程序中运行。
- 涉及构建设置和部署的更多要求。与可以部署在任何静态文件服务器上的完全静态单页面应用程序 (SPA) 不同,服务器渲染应用程序,需要处于 Node.js server 运行环境。
- 更多的服务器端负载。在 Node.js 中渲染完整的应用程序,显然会比仅仅提供静态文件的 server 更加大量占用 CPU 资源 (CPU-intensive - CPU 密集),因此如果你预料在高流量环境 (high traffic) 下使用,请准备相应的服务器负载,并明智地采用缓存策略。
- 在对你的应用程序使用服务器端渲染 (SSR) 之前,你应该问的第一个问题是,是否真的需要它。这主要取决于内容到达时间 (time-to-content) 对应用程序的重要程度。例如,如果你正在构建一个内部仪表盘,初始加载时的额外几百毫秒并不重要,这种情况下去使用服务器端渲染 (SSR) 将是一个小题大作之举。然而,内容到达时间 (time-to-content) 要求是绝对关键的指标,在这种情况下,服务器端渲染 (SSR) 可以帮助你实现最佳的初始加载性能。
nuxt.js
https://www.nuxtjs.cn/
https://zh.nuxtjs.org/docs/
- 创建项目:npm create-nuxt-app 项目名
- 在集成的服务器端框架之间进行选择:
None (Nuxt 默认服务器)
Express
Koa
Hapi
Feathers
Micro
Fastify
Adonis (WIP) - 选择您喜欢的 UI 框架:
None (无)
Bootstrap
Vuetify
Bulma
Tailwind
Element UI
Ant Design Vue
Buefy
iView
Tachyons - 选择您喜欢的测试框架:
None (随意添加一个)
Jest
AVA - 选择你想要的 Nuxt 模式 (Universal or SPA)
- 添加 axios module 以轻松地将 HTTP 请求发送到您的应用程序中。
- 添加 EsLint 以在保存时代码规范和错误检查您的代码。
- 添加 Prettier 以在保存时格式化/美化您的代码。
- 运行:cd 文件夹
- npm run dev
数据请求和 跨域问题
- 使用原版 axiox,也可以使用 this.$axios
- 跨域:nuxt.config.js
axios: {
proxy: true
},
proxy:{
"/api":{
target:"http://localhost:3000"
}
},
- 视图出口:
<Nuxt />
- 插件plugins
plugins文件夹下定义插件
*domian.js
import Vue from "vue"
Vue.prototype.$domian = "http://localhost:3000"
*element-ui.js
import Vue from 'vue'
import Element from 'element-ui'
import locale from 'element-ui/lib/locale/lang/en'
Vue.use(Element, {
locale })
*guard.js
// app 应用实例
export default(({
app})=>{
// 定义全局守卫
app.router.beforeEach((to,from,next)=>{
// console.log(to,from);
next()
})
})
*mint-ui.js
import Vue from 'vue'
import MintUI from 'mint-ui'
import 'mint-ui/lib/style.css'
Vue.use(MintUI)
nuxt.config.js注册插件配置
plugins: [
'@/plugins/element-ui',
'@/plugins/mint-ui',
"@/plugins/guard.js",
"@/plugins/domain.js",
],
- 状态管理(vuex)
- store/index.js
export const state = () => ({
counter: 0
})
export const mutations = {
increment(state) {
state.counter++
}
}
- store/todo.js
export const state = () => ({
msg: "hi"
})
- 组件内
import {
mapState,mapMutations} from "vuex"
computed:{
...mapState(["counter"]),
msg(){
console.log(this.$store)
return this.$store.state.todo.msg;
}
},
- 组件中asyncData()是设置服务器端渲染的数据的方法:
- 异步的数据:服务器端会执行的函数
- 没有this
// context: 组件实例
async asyncData(context) {
// console.log(context)
// console.log(context.app)
// console.log(this); //没有this
// console.log(context.$axios)// 通过context 获取axios
let res = await context.$axios.get("/api/getbanner");
console.log(res);
// 返回一个对象,服务器端渲染使用的数据源
return {
name: "World",
list:res.data.list
};
},
- 路由:定义一个组件就是定义了一个一级路由,嵌套路由(创建一个同名的文件夹,其下的路由就为当前路由的子路由)
- 导航:
<nuxt-link to="/">首页</nuxt-link>
(声明式路由写法) - 子路由视图出口:
<nuxt-child></nuxt-child>
- 动态路由:新建一个
_参数名.vue
的文件(_传参,获取:<p>{ {$route.params.id}}</p>
)
腾讯云开发者手册
https://cloud.tencent.com/developer/devdocs