• 尝试 vue 实现 SEO


    背景:

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

    然后收到通知, 需要实现 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

    然后把 压缩包 删掉. 

    接着配置 软连接指向

    1. ln -s /usr/local/nodejs/bin/node /usr/local/bin/node
    2. ln -s /usr/local/nodejs/bin/npm /usr/local/bin/npm

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

    檢查是否成功

     輸出版本號了. 安裝成功

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

    pm2安裝

    1. npm install pm2 -g
    2. 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/',

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

    1. cd ~
    2. cd ../
    3. mkdir pkg
    4. cd /pkg
    5. mkdir mook

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

    接着进入 nginx 配置文件

    cd /usr/local/nginx/

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

     

    查看 nginx 端口号

    ps aux|grep nginx

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

    1. kill -9 15138
    2. kill -9 15139

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

    然后启动 nginx 

    1. cd /usr/local/nginx/sbin
    2. ./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  测试环境 打包配置

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

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

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

    vue.config.js

    1. const webpack = require('webpack');
    2. const path = require('path');
    3. const PrerenderSPAPlugin = require('prerender-spa-plugin');
    4. const Renderer = PrerenderSPAPlugin.PuppeteerRenderer;
    5. let PUBLIC_PATH = process.env.VUE_APP_PUBLIC_PATH;
    6. let target_ = {
    7. target:
    8. process.env.NODE_ENV == 'production'
    9. ? 'https://aaaaa'
    10. : 'https://bbbbb', // 測試環境
    11. // 开启代理:在本地会创建一个虚拟服务端,然后发送请求的数据,并同时接收请求的数据,这样服务端和服务端进行数据的交互就不会有跨域问题 必须设置该项
    12. changeOrigin: true,
    13. };
    14. //
    15. let plugins = [
    16. new webpack.ProvidePlugin({
    17. jQuery: 'jquery',
    18. $: 'jquery',
    19. }),
    20. ];
    21. if (process.env.VUE_SEO) {
    22. plugins = [
    23. new webpack.ProvidePlugin({
    24. jQuery: 'jquery',
    25. $: 'jquery',
    26. }),
    27. new PrerenderSPAPlugin({
    28. staticDir: path.join(__dirname, 'dist'),
    29. indexPath: path.join(
    30. __dirname,
    31. `dist/${PUBLIC_PATH.substring(1)}index.html`
    32. ),
    33. routes: [
    34. // 需要预渲染的路由地址(需要打包成几个页面就配置几个路由)
    35. '',
    36. 'products/aaaa',
    37. 'products/bbbb',
    38. 'about',
    39. 'contact',
    40. ].map((x) => PUBLIC_PATH + x),
    41. minify: {
    42. minifyCSS: true, // css压缩
    43. removeComments: true, // 移除注释
    44. },
    45. server: {
    46. proxy: {
    47. // 配制代理,有些情况下很有用,他在模拟浏览器访问的时候讲采用以下配制的代理方案,看情况自选,不是必须
    48. '/server-aaa': target_,
    49. '/server-bbb': target_,
    50. },
    51. // 更改端口
    52. port: '9851',
    53. },
    54. renderer: new Renderer({
    55. inject: {
    56. foo: 'bar',
    57. },
    58. renderAfterElementExists: '#app',
    59. // 渲染时显示浏览器窗口,调试时有用
    60. headless: false,
    61. renderAfterTime: 5000,
    62. // 等待触发目标时间后,开始预渲染
    63. renderAfterDocumentEvent: 'render-event',
    64. }),
    65. }),
    66. ];
    67. }
    68. const Timestamp = new Date().getTime(); //时间戳
    69. module.exports = {
    70. devServer: {
    71. port: 8110,
    72. open: false,
    73. overlay: {
    74. warnings: false,
    75. errors: true,
    76. },
    77. // 配置代理
    78. proxy: {
    79. '/server-aaaa': target_,
    80. '/server-bbbb': target_,
    81. },
    82. },
    83. lintOnSave: false,
    84. publicPath: PUBLIC_PATH, // 項目地址 正式環境
    85. outputDir: `dist${PUBLIC_PATH}`, // 打包輸出地址
    86. // outputDir: 'dist', // 打包輸出地址
    87. assetsDir: 'static', // 資源文件夾
    88. productionSourceMap: true,
    89. pages: {
    90. index: {
    91. // page 的入口
    92. entry: 'src/main.js',
    93. // 模板来源
    94. template: 'public/index.html',
    95. // 在 dist/index.html 的输出
    96. filename: 'index.html',
    97. // 当使用 title 选项时,
    98. // template 中的 title 标签需要是 <%= htmlWebpackPlugin.options.title %>
    99. title: '首頁',
    100. // 在这个页面中包含的块,默认情况下会包含
    101. // 提取出来的通用 chunk 和 vendor chunk。
    102. chunks: ['chunk-vendors', 'chunk-common', 'index'],
    103. },
    104. },
    105. filenameHashing: false, // 打包的时候不使用hash值.因为我们有时间戳来确定项目的唯一性了.
    106. configureWebpack: {
    107. output: {
    108. filename: 'static/js/[name].' + Timestamp + '.js',
    109. chunkFilename: 'static/js/[name].' + Timestamp + '.js',
    110. },
    111. plugins: plugins,
    112. },
    113. css: {
    114. extract: {
    115. // 打包后css文件名称添加时间戳
    116. filename: `static/css/[name].${Timestamp}.css`,
    117. chunkFilename: `static/css/chunk.[id].${Timestamp}.css`,
    118. },
    119. loaderOptions: {
    120. postcss: {
    121. plugins: [
    122. require('postcss-pxtorem')({
    123. // 把px单位换算成rem单位
    124. rootValue: 192, // 96, // 换算的基数(设计图750的根字体为32)
    125. selectorBlackList: ['el-', 'px-', 'menu_', 'v-'], // 忽略转换正则匹配项
    126. propList: ['*'], // 需要做转化处理的属性,如`hight`、`width`、`margin`等,`*`表示全部
    127. minPixelValue: 0, //设置要替换的最小像素值(3px会被转rem)。 默认 0
    128. }),
    129. ],
    130. },
    131. },
    132. },
    133. };

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

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

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

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

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

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

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

  • 相关阅读:
    LeetCode刷题之数组篇(三)
    Word处理控件Aspose.Words功能演示:使用 Python 在 Word 文档中创建表格
    全网最详细的本地搭建GitLab代码仓库教学
    pandas_datareader读取yahoo金融数据超时问题timeout解决方案
    Java读取并转换字符串中的浮点数
    多大适合学习软件测试?
    运维工作的“本手、妙手、俗手”
    计算机毕设(附源码)JAVA-SSM基于JAVA的求职招聘网站的设计与实现
    Flume学习笔记:01-Flume的安装与简单入门示例
    解决VMware虚拟机更新17.5.0版本后,启动虚拟机导致电脑重启的问题。(建议收藏)
  • 原文地址:https://blog.csdn.net/qq_37802298/article/details/127684869