Vue SSR 组件加载问题


Posted in Javascript onMay 02, 2018

Node 端渲染提示 window/document 没有定义

Vue SSR 组件加载问题

业务场景

首先来看一个简单的 Vue 组件 test.vue

<template>
 <div>
  <h2>clientHeight: {{ clientHeight }} px </h2>
 </div>
</template>

<script type="text/babel">
 export default {
  data(){
   return {
   }
  },
  computed :{
   clientHeight() {
    return document.body.clientHeight;
   }
  },
  mounted(){
  }
 }
</script>

上面 test.vue 组件通过 Vue computed 属性 clientHeight 直接获取 document 的文档高度,这段代码在前端渲染是不会报错的,也能拿到正确的值。但如果把这个组件放到 SSR(Server Side Render) 模式下, 就会报如下错误:
ReferenceError: document is not defined

解决方案

通过 typeof 判断是否是存在 document 对象, 如果存在则执行后面代码。 这种方式虽然能解决问题, 但在 Webpack 构建压缩时, 不会执行的代码不会被剔除,也会打包到 js 文件中去, 因为这个是在运行期才知道结果的, 所以在 Webpack 构建方案中,不建议使用 typeof 方式判断。而是使用 Webpack 提供的 webpack.DefinePlugin 插件定义常量解决。

clientHeight() {
  return typeof document === 'object' ? document.body.clientHeight : '';
}

使用 Webpack 提供的 webpack.DefinePlugin 插件定义常量解决。 这里直接使用 easywebpack     https:// github.com/hubcarl/easy    webpack   内置的全局 Webpack 常量 EASY_ENV_IS_BROWSER  http:// hubcarl.github.io/easyw ebpack/webpack/env   进行 判断。 这样在构建压缩期间, 如果是 Node 模式构建, EASY_ENV_IS_BROWSER 会被替换为 false,如果是 Browser 模式构建, EASY_ENV_IS_BROWSER 会被替换为 true,最后构建后代码也就是变成了 true 或者 false 的常量。 因为这个是构建期间执行的,压缩插件剔除永远不会被执行的代码, 也就是

dead_code
clientHeight() {
  return EASY_ENV_IS_BROWSER ? document.body.clientHeight : '';
}

NPM Vue 组件 SSR 支持

针对上面这种自己写的代码,我们可以通过这种方式解决,因为可以直接修改。但如果我们引入的一个 npm Vue 插件想进行SSR渲染, 但这个插件里面使用了 window/docment 等浏览器对象, 并没有对 SSR 模式进行兼容,这个时候该如何解决呢?

一般我们通过 通过 v-if 来决定是否渲染该组件 和 Vue 只在前端挂载组件解决问题 可以解决。

通过 v-if 来决定是否渲染该组件

<template>
 <div v-if="isBrowser">
  <Loading></Loading>
 </div>
</template>
<script type="text/babel">
 export default {
  componets:{
   Loading: () =>import('vue-loading');
  }
  data(){
   return {
    isBrowser: EASY_ENV_IS_BROWSER
   }
  },
  mounted(){
  }
 }
</script>

Vue 只在前端挂载组件解决问题

<template>
 <div>
  <Loading></Loading>
 </div>
</template>

<script type="text/babel">
 export default {
  data(){
   return {
   }
  },
  beforeMount() {
   // 只会在浏览器执行 
   this.$options.components.Loading = () =>import('vue-loading');
  },
  mounted(){
  }
 }
</script>

loading 组件因为没有注册, 在 SSR 模式, <Loading></Loading> 会被原样输出到 HTML 中,不会报错且不能被浏览器识别, 在显示时不会有内容。当 SSR 直出 HTML 后,浏览器模式中执行 beforeMount 挂载组件, 从而达到解决服务端渲染报错的问题

https:// github.com/hubcarl/egg- vue-webpack-boilerplate/blob/master/app/web/page/dynamic/dynamic.vue

总结

以上所述是小编给大家介绍的Vue SSR 组件加载问题,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
JS 实现点击a标签的时候让其背景更换
Oct 15 Javascript
JS实现控制表格只显示行边框或者只显示列边框的方法
Mar 31 Javascript
BootStrap制作导航条实例代码
May 06 Javascript
JavaScript ES5标准中新增的Array方法
Jun 28 Javascript
AngularJS入门教程之数据绑定原理详解
Nov 02 Javascript
微信JS SDK接入的几点注意事项(必看篇)
Jun 23 Javascript
详解如何用模块化的方式写vuejs
Dec 16 Javascript
详解vue+webpack+express中间件接口使用
Jul 17 Javascript
Iview Table组件中各种组件扩展的使用
Oct 20 Javascript
JS中使用react-tooltip插件实现鼠标悬浮显示框
May 15 Javascript
JS实现随机抽取三人
Nov 06 Javascript
js观察者模式的弹幕案例
Nov 23 Javascript
基于jquery实现左右上下移动效果
May 02 #jQuery
关于Vue在ie10下空白页的debug小结
May 02 #Javascript
解析Json字符串的三种方法日常常用
May 02 #Javascript
使用vue-cli创建项目的图文教程(新手入门篇)
May 02 #Javascript
vue中的模态对话框组件实现过程
May 01 #Javascript
vue如何通过id从列表页跳转到对应的详情页
May 01 #Javascript
使用Vue的slot插槽分发父组件内容实现高度复用、更加灵活的组件(推荐)
May 01 #Javascript
You might like
PHP 基本语法格式
2009/12/15 PHP
php+ajax 实现输入读取数据库显示匹配信息
2015/10/08 PHP
Aster vs Newbee BO3 第二场2.18
2021/03/10 DOTA
JavaScript全排列的六种算法 具体实现
2013/06/29 Javascript
jquery查找tr td 示例模拟
2014/05/08 Javascript
JS+Canvas 实现下雨下雪效果
2016/05/18 Javascript
BootStrap selectpicker
2016/06/20 Javascript
node+experss实现爬取电影天堂爬虫
2016/11/20 Javascript
AngularJS基于ui-route实现深层路由的方法【路由嵌套】
2016/12/14 Javascript
angularJS 指令封装回到顶部示例详解
2017/01/22 Javascript
react-router实现按需加载
2017/05/09 Javascript
JavaScript实现表单注册、表单验证、运算符功能
2018/10/15 Javascript
JavaScript数据结构与算法之检索算法实例分析【顺序查找、最大最小值、自组织查询】
2019/02/22 Javascript
ES6 class的应用实例分析
2019/06/27 Javascript
javascript全局自定义鼠标右键菜单
2020/12/08 Javascript
sqlalchemy对象转dict的示例
2014/04/22 Python
python实现的阳历转阴历(农历)算法
2014/04/25 Python
Python中3种内建数据结构:列表、元组和字典
2014/11/30 Python
用Python编写一个每天都在系统下新建一个文件夹的脚本
2015/05/04 Python
python实现下载整个ftp目录的方法
2017/01/17 Python
Python编程实现的图片识别功能示例
2017/08/03 Python
对pandas读取中文unicode的csv和添加行标题的方法详解
2018/12/12 Python
python将字典列表导出为Excel文件的方法
2019/09/02 Python
python爬虫破解字体加密案例详解
2021/03/02 Python
BIBLOO捷克:购买女装、男装、童装、鞋和配件
2017/01/27 全球购物
马来西亚网上购物平台:ezbuy
2018/02/13 全球购物
斯凯奇新西兰官网:SKECHERS新西兰
2018/02/22 全球购物
Gap英国官网:Gap UK
2018/07/18 全球购物
波兰在线杂货店:Polski Koszyk
2019/11/02 全球购物
高中英语教学反思
2014/02/04 职场文书
电力安全事故反思
2014/04/27 职场文书
还款承诺书范文
2014/05/20 职场文书
教师节感想
2015/08/11 职场文书
golang在GRPC中设置client的超时时间
2021/04/27 Golang
在Java中Collection的一些常用方法总结
2021/06/13 Java/Android
Spring Data JPA的Audit功能审计数据库的变更
2021/06/26 Java/Android