尝试 vue 实现 SEO

news2024/11/14 18:44:25

背景:

官网使用 VUE 写的,  且 使用  <component /> 动态创建组件, 通过 手动配置的组件, 动态生成页面内容

然后收到通知, 需要实现 SEO , 于是就开始了 VUE + SEO 的拉锯战.....

第一种尝试 VUE+phantomjs

首先说下原理

phantomjs 是可以部署在服务端的 无头浏览器, 也可以用来做爬虫

pm2 是 服务托管

nginx 作为服务端以及事务转发

利用nginx判断是否是爬虫访问, 将phantomjs 生成的 数据 返回. pm2 则用作托管phantomjs;

那么就开始了....  查了很多资料.  慢慢的在摸索..

2022-11-3 小计

nodeJS + phantomjs +pm2 环境搭建

由于没有弄过, 为了避免弄崩服务器, 选择在 阿里云 上领取免费的服务器,

选择的是  contos7 版本, 创建完后 需要设置 [实例密码]

修改完密码后, 用 xshell 进行连接

连接上后, 就开始配置相关事项

nodejs安装 

首先在 nodejs 官网下载 linux 版 压缩包

Download | Node.js

可以自行选择版本 , 

下载后, 将目录 切换到 /usr/local 下

cd /usr/local/

然后利用 Xftp 工具, 将 node 包 上传到 /usr/local/ 下. 随即重命名 为  nodejs

然后解压 ( 參考文章 :  tar xvf命令_一朵风中摇曳的水仙花的博客-CSDN博客_tar -xvf

tar xzvf nodejs

然后把 压缩包 删掉. 

接着配置 软连接指向

ln -s /usr/local/nodejs/bin/node /usr/local/bin/node

ln -s /usr/local/nodejs/bin/npm /usr/local/bin/npm

這一步操作, 可以讓全局使用 node  和 npm 命令;

檢查是否成功

 輸出版本號了. 安裝成功

PS: 如果要安裝 淘寶鏡像, 安裝完後, cnpm 包會在  nodejs/bin/cnpm , 也需要用 ln -s 做一下 軟連接

pm2安裝

npm install pm2 -g

ln -s /usr/local/nodejs/bin/pm2 /usr/local/bin/pm2

 phantomjs 安裝

參考文章 : Linux/Centos下安装部署phantomjs 及使用-蒲公英云

 參考文章 : phantomJS+nodeJS+nginx完美解决前后端分离SEO问题_欧阳潇瑞的博客-CSDN博客

 我個人是在 

Download PhantomJS

 下載 linux 安裝包, 通過 和 Nodejs 同樣的 方式安裝,  同樣通過 ln -s 完成軟連接

 至此, 三個小玩意 安裝完成!

2022-11-4 小計

nginx安裝

參考文章 : Linux中搭建nginx(centOS7) - 南城古 - 博客园

跟隨文章操作 後, 我通過ip並不能訪問

於是繼續查資料

參考文章 :  Nginx启动成功但页面访问不到的解决方法_Lucky@Dong的博客-CSDN博客_nginx启动后访问不了web

但是...  還是不行 , 繼續找問題...

哈哈 找到了!

原來是 需要在 阿里雲上 配置 端口, 80 默認沒有配置!!! 

參考文章 :  【Nginx】启动成功无法访问网页(完整的排除方案)_渐暖°的博客-CSDN博客_nginx无法访问

成功訪問! 

配置项目访问

创建一个vue 项目,  设置 publicPath: '/mook/',

打包.  在 服务器根目录创建文件夹

cd ~
cd ../
mkdir pkg
cd /pkg
mkdir mook

通过Xftp 将 dist 下文件 上传到 mook

接着进入 nginx 配置文件

cd /usr/local/nginx/

通过 xftp 将 nginx.conf  下载到本地, 进行修改

 

查看 nginx 端口号

ps aux|grep nginx

如图, 我的是 15138 和 15139 , 接下来 kill 掉

kill -9 15138

kill -9 15139

 再查看一次 , 就只剩下一个

然后启动 nginx 

cd /usr/local/nginx/sbin

./nginx

然后用  ip/mook/  访问

成功!  

linux中文乱码

首先查看是否有中文包

locale -a |grep "zh_CN"

 

如果没有输出 , 则没有安装

yum groupinstall "fonts" -y

 或者 

yum install kde-l10n-Chinese

使用  以下代码  设置中文

localectl set-locale LANG=zh_CN

如果还有乱码, 请检查以下 xshell , 连接时, 是否选择了 utf-8 !!! 

配置域名绑定 

还是在 阿里云  购买一个 便宜的 域名, 也可以选择其他的云服务, 怎么舒服怎么来

购买的时候, 需要实名认证, 需要等很久.....

配置 phantomjs 生成頁面

參考文章 : GitHub - lengziyu/vue-seo-phantomjs: vue seo phantomjs方案

 根据官方说明, 在 根目录  /pkg/ 下 创建  phantomjs 文件夹, 

然后将项目 导入 , cnpm i 装包. 

随机 使用 node server.js 测试是否可以

  然后 ctrl + c 退出, 接着  pm2 托管

pm2 start server.js // 托管

显示成  online 则表示成功, 为了防止是假成功, 我们再次查看

pm2 list

 

 得到的结果一样, 就OK了. 

其中有个  pid 为 0 的, 是我之前弄的, 现在把他删掉

pm2 del 0

就ok ,  想知道更多pm2 语法,  pm2 -h 就可以了!

然后配置 nginx.conf 配置

直接照搬 官网 , 然后重启 nginx , 没问题, 就ok 了 

那么到现在为止,  phantomjs + vue + nginx 就完成了.   具体怎么验证, ........

我得想想..........   毕竟直接访问页面, 也不会被 nginx 抓到 ...

在经过各种尝试, 寻求帮助 , 依旧未果,  这个方案, 宣告失败!!!!

第二个方案 VUE+SSR

第一个失败后, 停滞了一段时间 , 然后 找到了 vue+ssr , 

这个是 官方的 方案,  说白了就是 服务端渲染

官方说明:

Vue.js 服务器端渲染指南 | Vue SSR 指南

关于如何配置, 全程参考 下面这篇文章  (有个/app, 需要改成 /main)

vue2-ssr从vue-cli搭建项目改造服务端渲染+打包上线部署_dlwlrma2022的博客-CSDN博客_vue2服务端渲染

VUE3的看下面这个

vue-cli3搭建的vue改造成SSR项目_Aaron-Lin的博客-CSDN博客

经过一整天的代码校验, 修改,整合, 以及来来回回的重建项目, 我得出了一个结论:

这个方案! 他喵只适合静态的!!!  凡是动态创建组件, 在 CTRL+U 查看源码下, 啥都渲染不出来!!!!!

所以, 宣告失败!!!!!!

第三个方案 VUE+ prerender-spa-plugin

預渲染, 參考文章  

vue SEO的解决方案_是廖一啊的博客-CSDN博客_vue seo

按照这个文章, 可以很简单的 配置出 基础功能. 
 

但是! 有问题!!!!!

他这个帖子 是 基于, 你的项目是发布在 根目录下的情况, 是可以的. 比如 publicPath:"/"

那如果我的项目是 打包到 publicPath:"/aaa" 呢 , 尝试一下就会知道,  根本就打不开,  build 会卡主,

原因是, 项目访问的是 /aaa , 但是 prerender-spa-plugin 只会启动到 localhost:8080 (设置于的端口号) 这时资源访问就有问题了, 

如何解决呢?  这里参考了 下面的 讨论

Configuring for Vue when publicPath is anything but / · Issue #344 · chrisvfritz/prerender-spa-plugin · GitHub

有兴趣的 可以自己研究研究, 看看上面帖子里的套路, 还有启发.

实际是怎么弄呢  上代码

.env.dev  测试环境 打包配置

NODE_ENV = 'development' // 表示是测试环境
VUE_SEO = 'seo' // 表示需要执行seo 打包
VUE_APP_PUBLIC_PATH = '/aaa/' // 指定打包地址



.env.prod  生产环境 打包配置

NODE_ENV = 'production'// 表示是生产环境
VUE_SEO = 'seo' // 表示需要执行seo 打包
VUE_APP_PUBLIC_PATH = '/'  // 指定打包地址

vue.config.js

const webpack = require('webpack');
const path = require('path');
const PrerenderSPAPlugin = require('prerender-spa-plugin');
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer;

let PUBLIC_PATH = process.env.VUE_APP_PUBLIC_PATH;
let target_ = {
  target:
    process.env.NODE_ENV == 'production'
      ? 'https://aaaaa'
      : 'https://bbbbb', // 測試環境
  // 开启代理:在本地会创建一个虚拟服务端,然后发送请求的数据,并同时接收请求的数据,这样服务端和服务端进行数据的交互就不会有跨域问题  必须设置该项
  changeOrigin: true,
};

//

let plugins = [
  new webpack.ProvidePlugin({
    jQuery: 'jquery',
    $: 'jquery',
  }),
];

if (process.env.VUE_SEO) {
  plugins = [
    new webpack.ProvidePlugin({
      jQuery: 'jquery',
      $: 'jquery',
    }),
    new PrerenderSPAPlugin({
      staticDir: path.join(__dirname, 'dist'),
      indexPath: path.join(
        __dirname,
        `dist/${PUBLIC_PATH.substring(1)}index.html`
      ),
      routes: [
        // 需要预渲染的路由地址(需要打包成几个页面就配置几个路由)
        '',
        'products/aaaa',
        'products/bbbb',
        'about',
        'contact',
      ].map((x) => PUBLIC_PATH + x),
      minify: {
        minifyCSS: true, // css压缩
        removeComments: true, // 移除注释
      },
      server: {
        proxy: {
          // 配制代理,有些情况下很有用,他在模拟浏览器访问的时候讲采用以下配制的代理方案,看情况自选,不是必须
          '/server-aaa': target_,
          '/server-bbb': target_,
        },
        // 更改端口
        port: '9851',
      },
      renderer: new Renderer({
        inject: {
          foo: 'bar',
        },
        renderAfterElementExists: '#app',
        // 渲染时显示浏览器窗口,调试时有用
        headless: false,
        renderAfterTime: 5000,
        // 等待触发目标时间后,开始预渲染
        renderAfterDocumentEvent: 'render-event',
      }),
    }),
  ];
}

const Timestamp = new Date().getTime(); //时间戳

module.exports = {
  devServer: {
    port: 8110,
    open: false,
    overlay: {
      warnings: false,
      errors: true,
    },
    // 配置代理
    proxy: {
      '/server-aaaa': target_,
      '/server-bbbb': target_,
    },
  },
  lintOnSave: false,
  publicPath: PUBLIC_PATH, // 項目地址  正式環境
  outputDir: `dist${PUBLIC_PATH}`, // 打包輸出地址
  // outputDir: 'dist', // 打包輸出地址
  assetsDir: 'static', // 資源文件夾
  productionSourceMap: true,
  pages: {
    index: {
      // page 的入口
      entry: 'src/main.js',
      // 模板来源
      template: 'public/index.html',
      // 在 dist/index.html 的输出
      filename: 'index.html',
      // 当使用 title 选项时,
      // template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
      title: '首頁',
      // 在这个页面中包含的块,默认情况下会包含
      // 提取出来的通用 chunk 和 vendor chunk。
      chunks: ['chunk-vendors', 'chunk-common', 'index'],
    },
  },
  filenameHashing: false, // 打包的时候不使用hash值.因为我们有时间戳来确定项目的唯一性了.
  configureWebpack: {
    output: {
      filename: 'static/js/[name].' + Timestamp + '.js',
      chunkFilename: 'static/js/[name].' + Timestamp + '.js',
    },
    plugins: plugins,
  },
  css: {
    extract: {
      // 打包后css文件名称添加时间戳
      filename: `static/css/[name].${Timestamp}.css`,
      chunkFilename: `static/css/chunk.[id].${Timestamp}.css`,
    },
    loaderOptions: {
      postcss: {
        plugins: [
          require('postcss-pxtorem')({
            // 把px单位换算成rem单位
            rootValue: 192, // 96, // 换算的基数(设计图750的根字体为32)
            selectorBlackList: ['el-', 'px-', 'menu_', 'v-'], // 忽略转换正则匹配项
            propList: ['*'], // 需要做转化处理的属性,如`hight`、`width`、`margin`等,`*`表示全部
            minPixelValue: 0, //设置要替换的最小像素值(3px会被转rem)。 默认 0
          }),
        ],
      },
    },
  },
};

说白了就是让 项目打包, 和 预渲染 打包 的  输入 和 输出, 保持同步就可以. 

这个时候, 通过测试环境 打包,  就会在 dist 下生成,  dist/aaa/...  的目录结构,  实际发布到 服务器时,  只需要 将 aaa 下的文件转移就可以

多数情况,  发布到测试 , 或者生产环境,  是使用  Jenkins 来打包的,  xshell + xftp 传包的, 可以略过了.

直接打包,  Jenkins 会爆出一个 异常 

 找不到 chrome , 因为是在 linux 下打包,  肯定是找不到  chrome 的, 这个时候就要做处理了

prerender-spa-plugin出现Failed to launch chrome 解决方案 - 码农教程

看上面這個帖子, 基本上就可以解決了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/59805.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

最强大脑记忆曲线(12)-- 录入数据修改

录入数据修改一、设计思路二、解决过程2.1 设计修改窗口2.2 转成py文件2.3 写业务逻辑1、先显示一下基础页面2、配合适配器&#xff0c;自动调整窗口大小3、在数据录入窗口或背记窗口双击某条记录3.1 增加信号3.2 在槽函数中打开修改页面**3.3 两个页面之间传递信号**3.4 在子窗…

24点问题(带输出构造方式)

问题描述&#xff1a; 在屏幕上输入1〜10范围内的4个整数&#xff08;可以有重复&#xff09;&#xff0c;对它们进行加、减、乘、除四则运算后&#xff08;可以任意的加括号限定计算的优先级&#xff09;&#xff0c;寻找计算结果等于24的表达式。 例如输入4个整数4、5、6、7…

1. RabbitMq 的基本概念

参考使用: 尚硅谷 消息中间件 RabbitMQ 课件 MQ 的概念 什么是 MQ MQ(message queue)&#xff0c;从字面意思上看&#xff0c;本质是个队列&#xff0c;FIFO 先入先出&#xff0c;只不过队列中存放的内容是 message 而已&#xff0c;还是一种跨进程的通信机制&#xff0c;用…

[附源码]计算机毕业设计毕业生就业管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Minecraft 1.19.2 Forge模组开发 05.矿石生成

我们本次尝试在主世界生成模组中自定义的矿石 1.由于1.19的版本出现了深板岩层的矿石&#xff0c;我们要在BlockInit类中声明一个矿石的两种岩层形态&#xff1a; BlockInit.java package com.joy187.re8joymod.init;import com.joy187.re8joymod.Main; import net.minecraf…

微服务框架 SpringCloud微服务架构 10 使用Docker 10.8 数据卷挂载案例1

微服务框架 【SpringCloudRabbitMQDockerRedis搜索分布式&#xff0c;系统详解springcloud微服务技术栈课程|黑马程序员Java微服务】 SpringCloud微服务架构 文章目录微服务框架SpringCloud微服务架构10 使用Docker10.8 数据卷挂载案例110.8.1 挂载数据卷10.8.2 案例10.8.3 总…

Pr:导出设置之高级设置及 VR 视频

视频 VIDEO设置因所选导出格式而异。每种格式都有独特的要求&#xff0c;这些要求决定了哪些设置可用。以导出文件格式为 H.264 为例&#xff0c;下面给出有关高级设置 Advanced Settings以及 VR 视频 VR Video的选项及说明。高级设置 Advanced Settings关键帧距离Key Frame Di…

期末复习-软件体系结构

软件体系结构一、软件重用与构件技术软件重用的定义重用驱动的软件的开发过程构件的三种描述模型三种构件分类方法的组织方式&#xff0c;检索方式&#xff0c;刻面分类法二、软件体系结构概述软件体系结构 构件 连接件 约束软件体系结构的四个发展阶段三、软件体系结构风格…

塔望3W消费战略全案丨牛小范低脂即食肉蛋白 行走的米其林牛排

牛小范 客户&#xff1a;山东如康集团 品牌&#xff1a;牛小范 服务&#xff1a;3W消费战略 品牌全案 项目背景 山东如康集团是一家集牛羊肉生产、加工与销售等为一体的大型综合性集团企业&#xff0c;是山东省级“专精特新”企业、农业产业化市级龙头企业和山东省"十三…

Linux命令:scp

目录 简介 一、语法 二、示例 2.1 将本地文件复制到远程主机目录 2.2 将本地目录复制到远程主机目录 2.3 将远程主机的文件复制到本机 2.4 复制远程主机目录到本机 简介 今天我们来介绍一个Linux命令&#xff1a;scp scp — secure copy (remote file copy program)&am…

Vue实现手机端界面的购物车案例

目录 前期准备 Header Goods Footer Counter 今天用Vue实现的一个手机端的购物车案例&#xff0c;着重阐述组件化思想的优势&#xff0c;将页面的内容分成各个模块进行书写&#xff0c;然后数据传输&#xff0c;父传子、子传父、兄弟数据共享等&#xff0c;这方面知识不牢…

[附源码]计算机毕业设计springboot游戏商城平台论文

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

PHP 经纬度坐标相关计算方法

1. 前言 2. 计算经纬度坐标间的距离 3. 根据经纬度坐标距离排序 4. 经纬度范围查询 1. 前言 想要测试本文提供的几个功能函数&#xff0c;可以使用下面这个数据表结构及其数据 CREATE TABLE user ( id int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 用户id, name v…

html静态网站基于游戏网站设计与实现共计10个页面 (仿地下城与勇士游戏网页)

&#x1f389;精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

UDS(83服务-AccessTimingParameter)

诊断协议那些事儿 诊断协议那些事儿专栏系列文章,本文介绍诊断和通讯管理功能单元下的83服务AccessTimingParameter,该服务的目的是读取/修改有效通信的计时参数。 文章目录 诊断协议那些事儿一、83服务-AccessTimingParameter二、请求格式子功能参数定义-timingParameterA…

Java并发编程—死锁

文章目录死锁什么叫做加锁&#xff1f;死锁代码理解&#xff1a;如何避免死锁&#xff1f;资源限制的挑战什么是资源限制&#xff1f;资源限制引发的问题&#xff1f;如何解决资源限制的问题&#xff1f;在资源限制情况下进行并发编程————————————————————…

物联网 (IoT) 为何如此重要?哪些技术让物联网成为了可能?

随着社会的进步和科技的发展&#xff0c;定位技术在技术手段、定位精度、可用性等方面均取得质的飞越&#xff0c;并且逐步从航海、航天、航空、测绘、军事、自然灾害预防等“高大上”的领域逐步渗透社会生活的方方面面&#xff0c;成为人们日常中不可或缺的重要应用——比如人…

[附源码]计算机毕业设计基于SpringBoot的剧本杀管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

用Python画出圣诞树,瞧瞧我这简易版的吧

前言 嗨嗨&#xff0c;大家好&#xff0c;我是小圆 今天来实现一下 用python画出圣诞树 代码 模块 源码.点击领取即可 import turtle as t from turtle import * import random as r import time圣诞树细节以及画布大小 画布大小&#xff0c;背景颜色都可以改&#xff0c;…

数据结构——链表

目录 一、链表概述 二、模拟实现链表 1、结点 2、遍历链表 3、获取链表的长度 4、添加元素 &#xff08;1&#xff09;、头插法 &#xff08;2&#xff09;、尾插法 &#xff08;3&#xff09;、在指定位置插入元素 5、删除元素 &#xff08;1&#xff09;、删…