VUE SEO方案一 - 预渲染及其cdn配置

项目接入VUE这样的框架后,看起来真是太漂亮了,奈何与MCV框架比起来,单页应用程序却满足不了SEO的业务需求,首屏渲染时间也是个问题。总不能白学VUE,预渲染和SSR还是要搞起来。

1.原理

为什么做服务端渲染之前先去了解了预渲染呢?因为预渲染方案相比服务端渲染简单太多了,而且并不是所有项目都需要服务端渲染的。

预渲染是怎么实现的呢?原理很简单,在项目开发完成之后,将有限的需要SEO的页面挑选出来,借助prerender-spa-plugin插件实行一次浏览器渲染,再将渲染好的源代码(.html)打包到项目包中,为这些页面在服务端额外配置路由(不再返回首页模板index.html)。这样这些页面就有单独的静态页面,从而解决了SEO和首屏问题。

2.适用场景及其优劣

预渲染适合那些SEO需求页面有限的应用,比如一个功能型的app。当只有一些推广页面需要SEO的时候,针对这些页面预渲染就非常方便了。相反,如果是一个资讯型的app,有成千上万的文章页面,这时再去做预渲染就比较坑了。

另外,如果预渲染的页面中含有一些动态的数据,那么预渲染的页面首屏数据不会自动更新(因为那是我们已经事先渲染好的,当然不会和用户需要的一致)。这种情况就需要事先布置好骨架屏,等等页面vue接管后重新渲染正确的数据,以免出现不对的数据。当然如果这些数据是SEO相关的,那预渲染就解决不了了。

所以个人认为,预渲染已经可以解决多数SEO问题已经首屏速度问题了,实在不行再上SSR。

3.开始配置

首先我们需要安装预渲染插件prerender-spa-plugin

prerender-spa-plugin文档

1npm i -D prerender-spa-plugin

对于整个项目都部署在静态服务根目录下的只要简单的配置就好了

1// vue.config.js
2const path = require('path')
3const resolve = dir => path.join(__dirname, dir)
4const PrerenderSPAPlugin = require('prerender-spa-plugin')
5const Renderer = PrerenderSPAPlugin.PuppeteerRenderer
6
7module.exports = {
8    outputDir: resolve('dist'),
9    publicPath: '/',
10    indexPath: resolve('dist/index.html'),
11    ...
12    chainWebpack: config => {
13        if(process.env.NODE_ENV === 'production'){
14            config.plugin('prerender-spa-plugin')
15                .use(PrerenderSPAPlugin, [{
16                    // 必须 - app出口,和outputDir一致就好.
17                    staticDir: resolve('dist'),
18                    // 必须 - 需要预渲染的路由.
19                    routes: ['/', '/about/'],
20                    // 必须 - 模拟浏览器渲染
21                    renderer: new Renderer({
22                        // 渲染时打开浏览器debug
23                        headless: false,
24                        // 渲染时机,正确的时机保证渲染页面的完整性
25                        renderAfterDocumentEvent: 'render-event'
26                    })
27                }])
28        }
29    }
30}
31
32//main.js
33new Vue({
34    router,
35    store,
36    render: h => h(App)
37    mounted () {
38        // 这里的触发事件就是renderAfterDocumentEvent中的事件
39         document.dispatchEvent(new Event('render-event'))
40    }
41})

4.cdn的坑

大部分情况下,上面的配置是无法满足项目需求的,因为一般我们会把模板和静态资源分开部署,使用cdn加速。这时候配置就有一点繁琐了。

1// vue.config.js
2const path = require('path')
3const resolve = dir => path.join(__dirname, dir)
4const PrerenderSPAPlugin = require('prerender-spa-plugin')
5const Renderer = PrerenderSPAPlugin.PuppeteerRenderer
6
7module.exports = {
8    outputDir: process.env.NODE_ENV === 'production' ? resolve('dist') : resolve('/www/statics/'),
9    publicPath: process.env.NODE_ENV === 'production' ? 'http://localhost/' : '/',
10    indexPath: resolve('dist/index.html'),
11    ...
12    if(process.env.NODE_ENV === 'production'){
13        config.plugin('prerender-spa-plugin')
14            .use(PrerenderSPAPlugin, [{
15                staticDir: resolve('dist'),
16                indexPath: resolve('/www/statics/index.html'),
17                routes: ['/', '/about/'],
18                postProcess (renderedRoute) {
19                    renderedRoute.html = renderedRoute.html.replace(/http:\/\/localhost/g, 'http://cdn.path/')
20                    return renderedRoute
21                },
22                renderer: new Renderer({
23                    injectProperty: '__PRERENDER_INJECTED__',
24                    inject: 'prerender',
25                    headless: false,
26                    renderAfterDocumentEvent: 'render-event'
27                })
28            }])
29    }
30}

  • 首先我们将输出模板配置到indexPath: resolve('dist/index.html')中

  • 但是我们分离了静态资源,outputDir: resolve('/www/statics/')

  • 分离了静态资源后,预渲染入口index.html也会打包到resolve('/www/statics/')中,因此要为PrerenderSPAPlugin配置indexPath: resolve('/www/statics/index.html')

  • 这时,按理我们应该将静态资源配置为publicPath:http://cdn.path/。但是这样预渲染的时候因为线上cdn中并没有对应的资源,因此会渲染失败。我们需要预先配置一个能够访问到本地资源的地址,比如publicPath:http://localhost/(这边的http://localhost/是我项目中自己开的本地服务),这样预渲染服务器就能渲染成功了,但是静态html中的静态资源地址都变成了http://localhost/,因此我们在PrerenderSPAPlugin中配置postProcess,在其中将http://localhost/替换为http://cdn.path/,再返回出的html就是拥有正确cdn地址的文件了,如果其中有多个cdn或者其他需求也可以自行匹配替换。

  • 看似成功了,但是我们发现,页面中vue接管的时候,webpack中的baseUrl也成了http://localhost/,因此从chunk-vendors.js中异步加载的组件.js的下载域名也是http://localhost/,因此加载错误,所以这边我们需要额外配置webpack。

  • 首先配置PrerenderSPAPlugin的renderer属性injectProperty: 'PRERENDER_INJECTED__'`与`inject: 'prerender'`,这样,在预渲染的时候会配置参数`window.__PRERENDER_INJECTED = prerender

  • 在入口页面的最上方我们引入配置文件@/common/prerender.js

    1import '@/common/prerender'
    2import Vue from 'vue'
    3import App from './App.vue'
    4import { createRouter } from './router'
    5import { createStore } from './store'
    6...
    7
    8// prerender.js
    9/* eslint camelcase: "off" */
    10if (process.env.NODE_ENV === 'production') {
    11    let isPrerender = window.__PRERENDER_INJECTED__ === 'prerender'
    12    __webpack_public_path__ = isPrerender ? 'http://localhost/' : 'http://cdn.path/'
    13}
    14// 此配置在预渲染模式下继续使用'http://localhost/'这样的本地域名,而正常打包时,这替换为'http://cdn.path/',这样项目就可以正常运行了
    15// 因为'__webpack_public_path__'命名不符合eslint,但是我们又需要此规则,所以'prerender.js'第一行加注释'/* eslint camelcase: "off" */'
    16//同时因为'__webpack_public_path__'变量是webpack的全局属性,所以配置:
    17globals: {
    18    __webpack_public_path__: 'writable'
    19},

5.最后

预渲染的页面被服务器返回之后,浏览器就会自动抓取页面信息,首屏渲染之后,vue引擎启动并接管页面,这时vue会根据自己加载的组件.js重新渲染页面,这显然是不必要的,因此我们需要在layout-App.vue的根元素(<div>)中添加data-server-rendered="true"属性,这样vue就知道dom是服务端渲染的,它会自动比较并更新需要更新的dom,不会全部重新渲染



vue预渲染及其cdn配置的更多相关文章

  1. vue 预渲染遇到的坑

    前言: 最近公司项目需要增加seo搜索引擎优化,到网上找了下资料,有预渲染和服务端渲染两种方式,考虑到只需要渲染首页所以我选择了先启用比较简单的预渲染方式来做seo! 步骤: 1.安装 prerend ...

  2. vue预渲染实践总结

    # 预渲染 ## 预渲染简介 SEO和首屏加载速度慢的问题,社区讨论最多的解决方案是同构 SSR,即首屏使用服务端渲染,之后的交互逻辑交给客户端处理,解决了单页应用带来的两个问题,但是也带来了服务器压 ...

  3. prerender-spa-plugin Vue预渲染配合meta-info优化seo

    记录一下解决方案的过程 先安装prerender和puppeteer插件  这个国外大神写的  github地址就不附上了(百度有) cnpm install prerender-spa-plugin ...

  4. vue 预渲染 prerender-spa-plugin

    1.预渲染说明 https://ssr.vuejs.org/zh/#为什么使用服务器端渲染-ssr-? 如果你调研服务器端渲染(SSR)只是用来改善少数营销页面(例如 /, /about, /cont ...

  5. prerender-spa-plugin预渲染踩坑

    为什么要使用预渲染? 为了应付SEO(国内特别是百度)考虑在网站(vue技术栈系列)做一些优化.大概有几种方案可以考虑: 服务端做优化: 第一,ssr,vue官方文档给出的服务器渲染方案,这是一套完整 ...

  6. Vue-cli使用prerender-spa-plugin插件预渲染和配置cdn

    参考:https://www.jianshu.com/p/6a4c0b281e7f 使用vue-cli打包项目一般为spa项目,众所周知单页面应用不利于SEO,有ssr和预渲染两种解决方案,这里我们只 ...

  7. vue项目使用 prerender-spa-plugin 预渲染

    由于项目要做seo优化,而用vue写成的spa页面谷歌浏览器等是抓取不到数据的.介于ssr和预渲染来说,后者相对来说要简单许多.所以采用了预渲染方式.采用插件prerender-spa-plugin使 ...

  8. vue(初探预渲染)

    ---恢复内容开始--- 一.前言 1.简介预渲染                     2.案例演示(不配置预渲染)                     3.配置预渲染, 二.主要内容 1.简 ...

  9. Vue项目预渲染机制引入实践

    周末想顺便把已经做好静态页面的webApp项目做一下SEO优化,由于不想写蹩脚的SSR代码,所以准备采用预渲染,本来想着网上有这么多预渲染的文章,随便找个来跟着做不就完了嘛,结果年轻的我付出了整个周末 ...

随机推荐

  1. MSSQL得知密码后getshell

    本文用了 sql server 2000和sql server 2008 MSSQL连接 连接MSSQL 2000 新建连接: 填写目的IP.目的端口.用户名.密码: 一直下一步,完成后,数据库导航窗 ...

  2. [转载]我的WafBypass之道(upload篇)

    现在位置: 首页 > 文章 > Web安全 > 正文 我的WafBypass之道(upload篇) 2016 /11/30 15:20 4,901 沙发 0x00 前言 玩waf当然 ...

  3. 寻路算法之A*算法详解

    前言 在实际开发中我们会经常用到寻路算法,例如MMOARPG游戏魔兽中,里面的人物行走为了模仿真实人物行走的体验,会选择最近路线达到目的地,期间会避开高山或者湖水,绕过箱子或者树林,直到走到你所选定的 ...

  4. 实践丨SpringBoot整合Mybatis-Plus项目存在Mapper时报错

    摘要:在SpringBoot运行测试Mybatis-Plus测试的时候报错的问题分析与修复 本文分享自华为云社区<SpringBoot整合MybatisPlus项目存在Mapper时运行报错的问 ...

  5. 半吊子菜鸟学Web开发 -- PHP学习 1-基础语法

    1索引数组 $fruit = array("苹果","香蕉","菠萝"): print_r($fruit); 索引数组的初始化,有三种方式: ...

  6. SpringBoot 多环境配置文件切换

    背景 很多时候,我们项目在开发环境和生成环境的环境配置是不一样的,例如,数据库配置,在开发的时候,我们一般用测试数据库,而在生产环境的时候,我们是用正式的数据,这时候,我们可以利用profile在不同 ...

  7. requests库获取响应流进行转发

    遇到了一个问题,使用requests进行转发 requests响应流的时候,出现各种问题,问题的描述没有记录,不过Debug以下终于解决了问题.......下面简单的描述解决方案 response = ...

  8. 讲讲 kafka 维护消费状态跟踪的方法?

    大部分消息系统在 broker 端的维护消息被消费的记录:一个消息被分发到 consumer 后 broker 就马上进行标记或者等待 customer 的通知后进行标记.这 样也可以在消息在消费后立 ...

  9. 哪一个List实现了最快插入?

    LinkedList和ArrayList是另个不同变量列表的实现.ArrayList的优势在于动态的增长数组,非常适合初始时总长度未知的情况下使用.LinkedList的优势在于在中间位置插入和删除操 ...

  10. Spring-boot-菜鸟-快速创建应用

    file-new-project 选择Spring boot ,然后选择自己的配置类型,maven  jdk版本等 结果: 目录解析: resources文件夹中目录结构 static:保存所有的静态 ...