前言:众所周知,Vue SPA单页面应用对SEO不友好,当然也有相应的解决方案,下面列出几种最近研究和使用过的SEO方案,SRR和静态化基于Nuxt来说。

1.SSR服务器渲染;
2.静态化;
3.预渲染prerender-spa-plugin;
4.使用Phantomjs针对爬虫做处理。

1.SSR服务器渲染

关于服务器渲染:Vue官网介绍 ,对Vue版本有要求,对服务器也有一定要求,需要支持nodejs环境。

使用SSR权衡之处:

  1. 开发条件所限,浏览器特定的代码,只能在某些生命周期钩子函数 (lifecycle hook) 中使用;一些外部扩展库 (external library) 可能需要特殊处理,才能在服务器渲染应用程序中运行;
  2. 环境和部署要求更高,需要Node.js server 运行环境;
  3. 高流量的情况下,请准备相应的服务器负载,并明智地采用缓存策略。

优势:

  1. 更好的 SEO,由于搜索引擎爬虫抓取工具可以直接查看完全渲染的页面;
  2. 更快的内容到达时间 (time-to-content),特别是对于缓慢的网络情况或运行缓慢的设备。

不足:(开发中遇到的坑)

1.一套代码两套执行环境,会引起各种问题,比如服务端没有window、document对象,处理方式是增加判断,如果是客户端才执行:

1
2
3
if(process.browser){
 console.log(window);
}

引用npm包,带有dom操作的,例如: wowjs ,不能用 import 的方式,改用:

1
2
3
4
if (process.browser) {
  var { WOW } = require('wowjs');
  require('wowjs/css/libs/animate.css');
 }

2.Nuxt asyncData方法,初始化页面前先得到数据,但仅限于 页面组件 调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 并发加载多个接口:
 async asyncData ({ app, query }) {
 let [resA, resB, resC] = await Promise.all([
  app.$axios.get('/api/a'),
  app.$axios.get('/api/b'),
  app.$axios.get('/api/c'),
  ])
   
  return {
  dataA: resA.data,
  dataB: resB.data,
  dataC: resC.data,
  }
 }

在asyncData中获取参数:

1.获取动态路由参数,如:

/list/:id' ==>  '/list/123

接收:

1
2
3
async asyncData ({ app, query }) {
 console.log(app.context.params.id) //123
}

2.获取url?获取参数,如:

/list?id=123

接收:

1
2
3
async asyncData ({ app, query }) {
 console.log(query.id) //123
}

3.如果你使用 v-if 语法,部署到线上大概也会遇到这个错误:

Error while initializing app DOMException: Failed to execute 'appendChild' on 'Node': This node type does not support this method.
    at Object.We [as appendChild]

根据github nuxt上的 issue第1552条提示,要将 v-if 改为 v-show 语法。

4.坑太多,留坑,晚点更。

2.静态化

在 Nuxt.js 执行 generate 静态化打包时,动态路由会被忽略。

1
2
3
4
-| pages/
---| index.vue
---| users/
-----| _id.vue

需要动态路由先生成静态页面,你需要指定动态路由参数的值,并配置到 routes 数组中去。

1
2
3
4
5
6
7
8
9
10
// nuxt.config.js
module.exports = {
 generate: {
 routes: [
  '/users/1',
  '/users/2',
  '/users/3'
 ]
 }
}

运行打包,即可看见打包出来的页面。

但是如果路由动态参数的值是动态的而不是固定的,应该怎么做呢?

使用一个返回 Promise 对象类型 的 函数;
使用一个回调是 callback(err, params) 的 函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// nuxt.config.js
import axios from 'axios'
 
export default {
 generate: {
 routes: function () {
  return axios.get('https://my-api/users')
  .then((res) => {
  return res.data.map((user) => {
   return {
   route: '/users/' + user.id,
   payload: user
   }
  })
  })
 }
 }
}

现在我们可以从 /users/_id.vue 访问的 payload ,如下所示:

1
2
3
4
async asyncData ({ params, error, payload }) {
 if (payload) return { user: payload }
 else return { user: await backend.fetchUser(params.id) }
}

如果你的动态路由的参数很多,例如商品详情,可能高达几千几万个。需要一个接口返回所有id,然后打包时遍历id,打包到本地,如果某个商品修改了或者下架了,又要重新打包,数量多的情况下打包也是非常慢的,非常不现实。

优势:

  • 纯静态文件,访问速度超快;
  • 对比SSR,不涉及到服务器负载方面问题;
  • 静态网页不宜遭到黑客攻击,安全性更高。

不足:

  • 如果动态路由参数多的话不适用。

3.预渲染prerender-spa-plugin

如果你只是用来改善少数营销页面(例如 /, /about, /contact 等)的 SEO,那么你可能需要预渲染。无需使用 web 服务器实时动态编译 HTML,而是使用预渲染方式,在构建时 (build time) 简单地生成针对特定路由的静态 HTML 文件。优点是设置预渲染更简单,并可以将你的前端作为一个完全静态的站点。

1
$ cnpm install prerender-spa-plugin --save

vue cli 3 vue.config.js 配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const PrerenderSPAPlugin = require('prerender-spa-plugin');
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer;
const path = require('path');
module.exports = {
 configureWebpack: config => {
  if (process.env.NODE_ENV !== 'production') return;
  return {
   plugins: [
    new PrerenderSPAPlugin({
     // 生成文件的路径,也可以与webpakc打包的一致。
     // 下面这句话非常重要!!!
     // 这个目录只能有一级,如果目录层次大于一级,在生成的时候不会有任何错误提示,在预渲染的时候只会卡着不动。
     staticDir: path.join(__dirname,'dist'),
     // 对应自己的路由文件,比如a有参数,就需要写成 /a/param1。
     routes: ['/', '/product','/about'],
     // 这个很重要,如果没有配置这段,也不会进行预编译
     renderer: new Renderer({
      inject: {
       foo: 'bar'
      },
      headless: false,
      // 在 main.js 中 document.dispatchEvent(new Event('render-event')),两者的事件名称要对应上。
      renderAfterDocumentEvent: 'render-event'
     })
    }),
   ],
  };
 }
}

在main.js中添加:

1
2
3
4
5
6
7
new Vue({
 router,
 render: h => h(App),
 mounted () {
 document.dispatchEvent(new Event('render-event'))
 }
}).$mount('#app')

注意:router中必须设置 mode: “history” 。

打包出来可以看见文件,打包出文件夹 /index.html ,例如: about => about/index.html ,里面有html内容。

优势:

  • 改动小,引入个插件就完事;

不足:

  • 无法使用动态路由;
  • 只适用少量页面的项目,页面多达几百个的情况下,打包会很很很慢;

4.使用Phantomjs针对爬虫做处理

Phantomjs是一个基于webkit内核的无头浏览器,即没有UI界面,即它就是一个浏览器,只是其内的点击、翻页等人为相关操作需要程序设计实现。

虽然“PhantomJS宣布终止开发”,但是已经满足对Vue的SEO处理。

这种解决方案其实是一种旁路机制,原理就是通过Nginx配置, 判断访问的来源UA是否是爬虫访问,如果是则将搜索引擎的爬虫请求转发到一个node server,再通过PhantomJS来解析完整的HTML,返回给爬虫。

具体代码戳这里: vue-seo-phantomjs

要安装全局 phantomjs ,局部 express ,测试:

1
$ phantomjs spider.js 'https://www.baidu.com'

如果见到在命令行里出现了一推html,那恭喜你,你已经征服PhantomJS啦。

启动之后或者用postman在请求头增加 User-Agent 值为 Baiduspider ,效果一样的。

部署上线

线上要安装 node  pm2 、 phantomjs ,nginx相关配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
upstream spider_server {
 server localhost:3000;
}
 
server {
 listen  80;
 server_name example.com;
  
 location / {
  proxy_set_header Host   $host:$proxy_port;
  proxy_set_header X-Real-IP  $remote_addr;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 
  if ($http_user_agent ~* "Baiduspider|twitterbot|facebookexternalhit|rogerbot|linkedinbot|embedly|quora link preview|showyoubot|outbrain|pinterest|slackbot|vkShare|W3C_Validator|bingbot|Sosospider|Sogou Pic Spider|Googlebot|360Spider") {
  proxy_pass http://spider_server;
  }
 }
}

优势:

  • 完全不用改动项目代码,按原本的SPA开发即可,对比开发SSR成本小不要太多;
  • 对已用SPA开发完成的项目,这是不二之选。

不足:

  • 部署需要node服务器支持;
  • 爬虫访问比网页访问要慢一些,因为定时要定时资源加载完成才返回给爬虫;
  • 如果被恶意模拟百度爬虫大量循环爬取,会造成服务器负载方面问题,解决方法是判断访问的IP,是否是百度官方爬虫的IP。

总结

如果构建大型网站,如商城类,别犹豫,直接上SSR服务器渲染,当然也有相应的坑等你,社区较成熟,英文好点,一切问题都迎刃而解。

如果只是个人博客、公司官网这类,其余三种都可以。

如果对已用SPA开发完成的项目进行SEO优化,而且支持node服务器,请使用 Phantomjs 。

很少写文章,这是我这个月对Vue SEO方案的探索,写的不对的地方请指出,谢谢理解~

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

摘至https://www.jb51.net/article/164285.htm

83.基于Vue SEO的四种方案(小结)的更多相关文章

  1. 基于Vue SEO的四种方案

    基于Vue SEO的四种方案 https://segmentfault.com/a/1190000019623624?utm_source=tag-newest

  2. Vue 封装axios(四种请求)及相关介绍(十三)

    Vue 封装axios(四种请求)及相关介绍 首先axios是基于promise的http库 promise是什么? 1.主要用于异步计算 2.可以将异步操作队列化,按照期望的顺序执行,返回符合预期的 ...

  3. 四种方案:将OpenStack私有云部署到Hadoop MapReduce环境中

    摘要:OpenStack与Hadoop被誉为继Linux之后最有可能获得巨大成功的开源项目.这二者如何结合成为更猛的新方案?业内给出两种答案:Hadoop跑在OpenStack上或OpenStack部 ...

  4. OpenStack部署到Hadoop的四种方案

    随着企业開始同一时候利用云计算和大数据技术.如今应当考虑怎样将这些工具结合使用.在这样的情况下,企业将实现最佳的分析处理能力.同一时候利用私有云的高速弹性 (rapid elasticity) 和单一 ...

  5. http无状态和鉴权解决四种方案

    http协议本身是无状态的,但是在实际的web开发中常有一些操作需要有状态.比如想要访问一些私人访问权限的文章,或者这种操作需要明确当前用户身份. 显然,最简单的方案就是每次都发送账户和密码,但是这样 ...

  6. 基于redis实现的四种常见的限流策略

    引言 在web开发中功能是基石,除了功能以外运维和防护就是重头菜了.因为在网站运行期间可能会因为突然的访问量导致业务异常.也有可能遭受别人恶意攻击 所以我们的接口需要对流量进行限制.俗称的QPS也是对 ...

  7. Vue+axios的四种异步请求,参数的携带以及接收

    Vue中axios发送GET, POST, DELETE, PUT四种异步请求,参数携带和接收问题 web.xml配置如下 1.GET请求 发送GET请求: <!--params是关键字,说明所 ...

  8. Netty解决粘包和拆包问题的四种方案

    在RPC框架中,粘包和拆包问题是必须解决一个问题,因为RPC框架中,各个微服务相互之间都是维系了一个TCP长连接,比如dubbo就是一个全双工的长连接.由于微服务往对方发送信息的时候,所有的请求都是使 ...

  9. vue路由的四种传值

    第一种:props 配置: 组件内定义: props: ['id'] 路由映射配置,开启props:true : { path: '/user/:id', component: User, props ...

随机推荐

  1. Refused to execute script from '...' because its MIME type ('') is not executable, and strict MIME type checking is enabled.

    写在前面 部署项目到weblogic上启动首页访问空白, 浏览器控制台报如题错误. web.xml中把响应头添加防止攻击的报文过滤器禁用就行了(仅仅是为了启动), 以下为转载内容, 可以根据需要自行测 ...

  2. vue路由的异步加载(懒加载)方法

    vue路由的异步加载(懒加载)方法. javascriptvue.jsvue-router  阅读约 2 分钟 vue本身不多介绍.直接说问题,因为vue的所有路由都是加载在一个app.js里的,如果 ...

  3. windows7平台android studio新建Android项目,报错

    Failed to install the following Android SDK packages as some licences have not been accepted. platfo ...

  4. SearchLookupEdit 选择后联动

    直接改绑定数据源--实体的属性会导致选择内容变空 所有改相应控件的text然后再写入数据源 最好将需要联动的控件设置成只读 mNoTextEdit.EditValueChanged += (s, e) ...

  5. Spark程序打包

    背景: spark程序,使用scala语言开发.整个项目中包含多个子模块,依赖包文件使用maven来管理. 打包: 方法一:使用artifacts来 选择模块,选择对应的主函数: 点ok保存. 由于s ...

  6. android 桌面图标添加数字角标

    是否支持角标并不与手机厂商有关,而是你当前使用的launcher开发厂商有关. 方法实现: import android.app.Application; import android.app.Not ...

  7. spring cloud java: 无法访问redis.clients.jedis.JedisPoolConfig 找不到redis.clients.jedis.JedisPoolConfig的类文件

    spring cloud <spring-cloud.version>Greenwich.SR3</spring-cloud.version> 注入Redis 时候: @Bea ...

  8. PHP 简易网页访问统计

    传统的网页访问统计,已经有很多,如 51la.百度统计.站长统计 一般都需要引用JS,在你的网页内嵌入JS,这个操作存在风险,并且不可控. 可以考虑使用 [img src.css src.link h ...

  9. IfcBeam属性

    IfcBeam属性和结构 <xs:element name="IfcBeam" type="ifc:IfcBeam" substitutionGroup= ...

  10. Swift编码总结10

    1.打开App显示文件已损坏,打不开,您应该将它移到废纸篓,怎么办? 终端输入执行:sudo spctl --master-disable 2.Mac的Siri打开网页控制台,进入开发中模式:不过我觉 ...