资讯专栏INFORMATION COLUMN

理解vue ssr原理,自己搭建简单的ssr框架

Riddler / 1607人阅读

摘要:前言大多数项目要支持应该是为了考虑,毕竟对于应用来说,搜索引擎是一个很大的流量入口。引入是一个构建客户端应用的框架,即组件是在浏览器中进行渲染的。由于服务端渲染要用做中间层,所以部署项目时,需要处于运行环境。

前言

大多数Vue项目要支持SSR应该是为了SEO考虑,毕竟对于WEB应用来说,搜索引擎是一个很大的流量入口。Vue SSR现在已经比较成熟了,但是如果是把一个SPA应用改造成SSR应用,成本还是有些高的,这工作量无异于重构前端。另外对前端的技术要求也是挺高的,需要对Vue比较熟悉,还要有Node.js 和 webpack 的应用经验。

引入

Vue是一个构建客户端应用的框架,即vue组件是在浏览器中进行渲染的。所谓服务端渲染,指的是把vue组件在服务器端渲染为组装好的HTML字符串,然后将它们直接发送到浏览器,最后需要将这些静态标记"激活"为客户端上完全可交互的应用程序。

服务端渲染的优点

更好的SEO,搜索引擎爬虫可以抓取渲染好的页面

更快的内容到达时间(首屏加载更快),因为服务端只需要返回渲染好的HTML,这部分代码量很小的,所以用户体验更好

服务端渲染的缺点

首先就是开发成本比较高,比如某些声明周期钩子函数(如beforeCreate、created)能同时运行在服务端和客户端,因此第三方库要做特殊处理,才能在服务器渲染应用程序中运行。

由于服务端渲染要用Nodejs做中间层,所以部署项目时,需要处于Node.js server运行环境。在高流量环境下,还要做好服务器负载和缓存策略

原理解析

先附上demo地址:https://github.com/wmui/vue-s...

第一步:编写entry-client.js和entry-server.js

entry-client.js只在浏览器环境下执行,所以需要显示调用$mount方法,挂载DOM节点

</>复制代码

  1. import Vue from "vue";
  2. import App from "./App.vue";
  3. import createStore from "./store/index.js";
  4. function createApp() {
  5. const store = createStore();
  6. const app = new Vue({
  7. store,
  8. render: h => h(App)
  9. });
  10. return {app, store}
  11. }
  12. const { app, store } = createApp();
  13. // 使用window.__INITIAL_STATE__中的数据替换整个state中的数据,这样服务端渲染结束后,客户端也可以自由操作state中的数据
  14. if (window.__INITIAL_STATE__) {
  15. store.replaceState(window.__INITIAL_STATE__);
  16. }
  17. app.$mount("#app");

entry-server.js需要导出一个函数,在服务端渲染期间会被调用

</>复制代码

  1. import Vue from "vue";
  2. import App from "./App.vue";
  3. import createStore from "./store/index.js";
  4. export default function(context) {
  5. // context是上下文对象
  6. const store = createStore();
  7. let app = new Vue({
  8. store,
  9. render: h => h(App)
  10. });
  11. // 找到所有 asyncData 方法
  12. let components = App.components;
  13. let asyncDataArr = []; // promise集合
  14. for (let key in components) {
  15. if (!components.hasOwnProperty(key)) continue;
  16. let component = components[key];
  17. if (component.asyncData) {
  18. asyncDataArr.push(component.asyncData({store})) // 把store传给asyncData
  19. }
  20. }
  21. // 所有请求并行执行
  22. return Promise.all(asyncDataArr).then(() => {
  23. // context.state 赋值成什么,window.__INITIAL_STATE__ 就是什么
  24. // 这下你应该明白entry-client.js中window.__INITIAL_STATE__是哪来的了,它是在服务端渲染期间被添加进上下文的
  25. context.state = store.state;
  26. return app;
  27. });
  28. };

上面的asyncData是干嘛用的?其实,这个函数是专门请求数据用的,你可能会问请求数据为什么不在beforeCreate或者created中完成,还要专门定义一个函数?虽然beforeCreatecreated在服务端也会被执行(其他周期函数只会在客户端执行),但是我们都知道请求是异步的,这就导致请求发出后,数据还没返回,渲染就已经结束了,所以无法把 Ajax 返回的数据也一并渲染出来。因此需要想个办法,等到所有数据都返回后再渲染组件

asyncData需要返回一个promise,这样就可以等到所有请求都完成后再渲染组件。下面是在foo组价中使用asyncData的示例,在这里完成数据的请求

</>复制代码

  1. export default {
  2. asyncData: function({store}) {
  3. return store.dispatch("GET_ARTICLE") // 返回promise
  4. },
  5. computed: {
  6. article() {
  7. return this.$store.state.article
  8. }
  9. }
  10. }

第二步:配置webpack

webpack配置比较简单,但是也需要针对client和server端多带带配置

webpack.client.conf.js显然是用来打包客户端应用的

</>复制代码

  1. module.exports = merge(base, {
  2. entry: {
  3. client: path.join(__dirname, "../entry-client.js")
  4. }
  5. });

webpack.server.conf.js用来打包服务端应用,这里需要指定node环境

</>复制代码

  1. module.exports = merge(base, {
  2. target: "node", // 指定是node环境
  3. entry: {
  4. server: path.join(__dirname, "../entry-server.js")
  5. },
  6. output: {
  7. filename: "[name].js", // server.js
  8. libraryTarget: "commonjs2" // 必须按照 commonjs规范打包才能被服务器调用。
  9. },
  10. plugins: [
  11. new HtmlWebpackPlugin({
  12. template: path.join(__dirname, "../index.ssr.html"),
  13. filename: "index.ssr.html",
  14. files: {
  15. js: "client.js"
  16. }, // client.js需要在html中引入
  17. excludeChunks: ["server"] // server.js只在服务端执行,所以不能打包到html中
  18. })
  19. ]
  20. });

第三步:启动服务

打包完成后就可以启动服务了,在start.js中我们需要把server.js加载进来,然后通过renderToString方法把渲染好的html返回给浏览器

</>复制代码

  1. const bundle = fs.readFileSync(path.resolve(__dirname, "dist/server.js"), "utf-8");
  2. const renderer = require("vue-server-renderer").createBundleRenderer(bundle, {
  3. template: fs.readFileSync(path.resolve(__dirname, "dist/index.ssr.html"), "utf-8") // 服务端渲染数据
  4. });
  5. server.get("*", (req, res) => {
  6. renderer.renderToString((err, html) => {
  7. // console.log(html)
  8. if (err) {
  9. console.error(err);
  10. res.status(500).end("服务器内部错误");
  11. return;
  12. }
  13. res.end(html);
  14. })
  15. });
效果图

demo已经上传到github: http://github.com/wmui/vue-ss...

结语

个人实践Vue SSR已有一段时间,发现要想搭建一套完整的 SSR 服务框架还是很有挑战的,或许 Nuxt 是一个不错的选择,对 Nuxt 感兴趣的朋友可以参考我的一个开源小作品Essay

以上,感谢阅读!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/100285.html

相关文章

  • 关于Vue2一些值得推荐文章 -- 五、六月份

    摘要:五六月份推荐集合查看最新的请点击集前端最近很火的框架资源定时更新,欢迎一下。苏幕遮燎沈香宋周邦彦燎沈香,消溽暑。鸟雀呼晴,侵晓窥檐语。叶上初阳乾宿雨,水面清圆,一一风荷举。家住吴门,久作长安旅。五月渔郎相忆否。小楫轻舟,梦入芙蓉浦。 五、六月份推荐集合 查看github最新的Vue weekly;请::点击::集web前端最近很火的vue2框架资源;定时更新,欢迎 Star 一下。 苏...

    sutaking 评论0 收藏0
  • 关于Vue2一些值得推荐文章 -- 五、六月份

    摘要:五六月份推荐集合查看最新的请点击集前端最近很火的框架资源定时更新,欢迎一下。苏幕遮燎沈香宋周邦彦燎沈香,消溽暑。鸟雀呼晴,侵晓窥檐语。叶上初阳乾宿雨,水面清圆,一一风荷举。家住吴门,久作长安旅。五月渔郎相忆否。小楫轻舟,梦入芙蓉浦。 五、六月份推荐集合 查看github最新的Vue weekly;请::点击::集web前端最近很火的vue2框架资源;定时更新,欢迎 Star 一下。 苏...

    khs1994 评论0 收藏0
  • 从零开始搭建一个vue-ssr(上)

    摘要:从零开始搭建一个背景是什么全拼是,服务端渲染。大家不妨可以打开一些页面或者一些公司的网站,查看源代码,你会发现,也是有这个标记。这时候,我们发现页面的路由切换生效了,并且不同页面的源代码也不一样了。从零开始搭建一个下项目源码 从零开始搭建一个vue-ssr 背景 What?SSR是什么? SSR全拼是Server-Side Rendering,服务端渲染。 所谓服务端渲染,指的是把...

    Winer 评论0 收藏0
  • vue服务端渲染demo将vue-cli生成项目转为ssr

    摘要:无需使用服务器实时动态编译,而是使用预渲染方式,在构建时简单地生成针对特定路由的静态文件。与可以部署在任何静态文件服务器上的完全静态单页面应用程序不同,服务器渲染应用程序,需要处于运行环境。更多的服务器端负载。 目录结构 -no-ssr-demo 未做ssr之前的项目代码用于对比 -vuecli2ssr 将vuecli生成的项目转为ssr -prerender-demo 使用prer...

    whinc 评论0 收藏0

发表评论

0条评论

Riddler

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<