Skip to content

Commit 14cbdea

Browse files
committedMar 7, 2021
chore: update crd support seo
1 parent 8a26420 commit 14cbdea

33 files changed

+278
-54
lines changed
 

‎BasicSkill/Shorcuts/host_modify.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,6 @@
22

33
```
44
sudo vi /etc/hosts
5-
```
5+
```
6+
7+
> github 访问慢一般可以修改该目录。[方法](https://zhuanlan.zhihu.com/p/94521827)

‎BasicSkill/fe_cloud/seo.md

-22
This file was deleted.

‎BasicSkill/life/sport/jump.md

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
### Sport
2+
3+
* [每天坚持跳绳 1000 个,一个月后会有什么变化?](https://www.zhihu.com/question/400648101/answer/1680793795) - 小婉青青的回答 - 知乎
4+
- [ ] 购买磨砂膏
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

‎FeCloud/seo_in_spa_site.md

+213
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
## SEO 在 SPA 站点中的实践
2+
3+
### 背景
4+
5+
![](http://with.muyunyun.cn/c03d8772da6d57e47c55044aee364103.jpg)
6+
7+
观察基于 [create-react-doc](https://github.com/MuYunyun/create-react-doc) 搭建的[文档站点](http://muyunyun.cn/create-react-doc/), 发现网页代码光秃秃的一片(见下图)。这显然是单页应用 (SPA) 站点的通病 —— 不利于文档被搜索引擎搜索 (SEO)。
8+
9+
![](http://with.muyunyun.cn/0ba88a7544efe0e1978e6c8d8b7775a6.jpg)
10+
11+
难道 SPA 站点就无法进行 SEO 了么, 那么 [Gatsby](https://github.com/gatsbyjs/gatsby)[nuxt](https://github.com/nuxt/nuxt.js) 等框架又为何能作为不少博主搭建博客的首选方案呢, 此类框架赋能 SEO 的技术原理是什么呢? 在好奇心的驱动下, 笔者尝试对 [creat-react-doc](https://github.com/MuYunyun/create-react-doc) 进行赋能 SEO 之旅。
12+
13+
### 搜索引擎优化
14+
15+
在实践之前, 先从理论上分析为何单页应用不能被搜索引擎搜索到。核心在于 `爬虫蜘蛛在执行爬取的过程中, 不会去执行网页中的 JS 逻辑`, 所以`隐藏在 JS 中的跳转逻辑也不会被执行`
16+
17+
查看当前 SPA 站点打包后的代码, 除了一个根目录 index.html 外, 其它都是注入的 JS 逻辑, 因此浏览器自然不会对其进行 SEO。
18+
19+
![](http://with.muyunyun.cn/0d15d4e3a62516da7c301e8f1c9228d6.jpg)
20+
21+
此外, 搜索引擎详优化是一门较复杂的学问。如果你对 SEO 优化比较陌生, 建议阅读[搜索引擎优化 (SEO) 新手指南](https://developers.google.com/search/docs/beginner/seo-starter-guide) 一文, Google 搜索中心给出了全面的 **17 个**最佳做法, 以及 **33 个**应避免的做法, 这也是笔者近期在实践的部分。
22+
23+
### SEO 在 SPA 站点中的实践案例
24+
25+
在轻文档站点的背景前提下, 我们暂不考虑 SSR 方案。
26+
27+
对市面上文档站点的 SEO 方案调研后, 笔者总结为如下四类:
28+
29+
* 静态模板渲染方案
30+
* 404 重定向方案
31+
* SSG 方案
32+
* 预渲染方案
33+
34+
#### 静态模板渲染方案
35+
36+
静态模板渲染方案以 [hexo](https://github.com/hexojs/hexo) 最为典型, 此类框架需要指定特定的模板语言(比如 [pug](https://github.com/pugjs/pug))来开发主题, 从而达到网页内容直出的目的。
37+
38+
#### 404 重定向方案
39+
40+
404 重定向方案的原理主要是利用 GitHub Pages 的 404 机制进行重定向。比较典型的案例有 [spa-github-pages](https://github.com/rafgraph/spa-github-pages)[sghpa](https://github.com/csuwildcat/sghpa)
41+
42+
但是遗憾的是 2019 年 Google [调整了爬虫算法](https://github.com/rafgraph/spa-github-pages#seo), 因此此类重定向方案在当下是无利于 SEO 的。spa-github-pages 作者也表示如果需要 SEO 的话, 使用 SSG 方案或者付费方案 [Netlify](https://www.netlify.com/blog/2020/04/07/creating-better-more-predictable-redirect-rules-for-spas/)
43+
44+
![](http://with.muyunyun.cn/bbb5ed8bce1e0c08dae94df98ff33262.jpg)
45+
46+
#### SSG 方案
47+
48+
SSG 方案全称为 static site generator, 中文可译为`路由静态化方案`。社区上 [nuxt](https://github.com/nuxt/nuxt.js)[Gatsby](https://github.com/gatsbyjs/gatsby) 等框架赋能 SEO 的技术无一例外可以归类此类 SSG 方案。
49+
50+
以 nuxt 框架为例, 在`约定式路由`的基础上, 其通过执行 `nuxt generate` 命令将 vue 文件转化为静态网页。
51+
52+
例子:
53+
54+
```bash
55+
-| pages/
56+
---| about.vue/
57+
---| index.vue/
58+
```
59+
60+
静态化后变成:
61+
62+
```bash
63+
-| dist/
64+
---| about/
65+
-----| index.html
66+
---| index.html
67+
```
68+
69+
经过路由静态化后, 此时的文档目录结构可以托管于任何一个静态站点服务商。
70+
71+
#### 预渲染方案
72+
73+
经过上文对 SSG 方案的分析, 此时 SPA 站点的优化关键已经跃然纸上 —— `静态化路由`。相较于 nuxt、Gatsby 等框架存在约定式路由的限制, [create-react-doc](https://github.com/MuYunyun/create-react-doc) 在目录结构上的组织灵活自由。它的建站理念是`文件即站点`, 同时它对存量 markdown 文档的迁移也十分便捷。
74+
75+
[blog](https://github.com/MuYunyun/blog) 项目结构为例:
76+
77+
```bash
78+
-| BasicSkill/
79+
---| basic/
80+
-----| DOM.md
81+
-----| HTML5.md
82+
```
83+
84+
静态化后应该变成:
85+
86+
```bash
87+
-| BasicSkill/
88+
---| basic/
89+
-----| DOM
90+
-------| index.html
91+
-----| HTML5
92+
-------| index.html
93+
```
94+
95+
经过调研, 该构思与 [prerender-spa-plugin](https://github.com/chrisvfritz/prerender-spa-plugin) 预渲染方案一拍即合。预渲染方案的原理可以见如下图:
96+
97+
![](http://with.muyunyun.cn/f3eb18c162a31fb155fd9f4a364f7fb9.jpg)
98+
99+
至此技术选型定下为使用预渲染方案实现 SSG。
100+
101+
### 预渲染方案实践
102+
103+
create-react-doc 在预渲染方案实践的步骤简单概况如下(完整改动可见 [mr](https://github.com/MuYunyun/create-react-doc/pull/95/files)):
104+
105+
* 改造 hash 路由为 history 路由。因为 history 路由结构与文档静态化目录结构天然匹配。
106+
107+
```diff
108+
export default function RouterRoot() {
109+
return (
110+
- <HashRouter>
111+
+ <BrowserRouter>
112+
<RoutersContainer />
113+
- </HashRouter>
114+
+ </BrowserRouter>
115+
)
116+
}
117+
```
118+
119+
* 在开发环境、生成环境的基础上新增`预渲染环境`, 同时对路由进行环境匹配。其主要解决了`资源文件``主域名下的子路径`的对应关系。过程比较曲折, 感兴趣的同学可以见 [issue](https://github.com/chrisvfritz/prerender-spa-plugin/issues/215#issuecomment-415942268)
120+
121+
```diff
122+
const ifProd = env === 'prod'
123+
+ const ifPrerender = window.__PRERENDER_INJECTED && window.__PRERENDER_INJECTED.prerender
124+
+ const ifAddPrefix = ifProd && !ifPrerender
125+
126+
<Route
127+
key={item.path}
128+
exact
129+
- path={item.path}
130+
+ path={ifAddPrefix ? `/${repo}${item.path}` : item.path}
131+
render={() => { ... }}
132+
/>
133+
```
134+
135+
* 兼容 prerender-spa-plugin 在 webpack 5 的使用。
136+
137+
官方版本当前未支持 webpack 5, 详见 [issue](https://github.com/chrisvfritz/prerender-spa-plugin/issues/414), 同时笔者存在对预渲染后执行回调的需求。因此当前 fork 了一份[版本](https://github.com/create-react-doc/prerender-spa-plugin) 出来, 解决了以上问题。
138+
139+
### SEO 优化附加 buff, 站点秒开?
140+
141+
SEO 优化至此, 来看下站点优化前后 FP、FCP、LCP 等指标数据的变化。
142+
143+
[blog](https://muyunyun.cn/blog) 站点为例, 优化前后的指标数据如下(数据指标统计来自未使用梯子访问 gh-pages):
144+
145+
优化前: 接入预渲染方案前, 首次绘制(FP、FCP) 的时间节点在 8s 左右, LCP 在 17s 左右。
146+
147+
![](http://with.muyunyun.cn/23d56cc42fd778c23d8ed80331334343.jpg)
148+
149+
优化后: 接入预渲染方案后, 首次绘制时间节点在 `1s` 之内开始, LCP 在 1.5s 之内。
150+
151+
![](http://with.muyunyun.cn/9c551d29943c3d76700782374d86c37b.jpg)
152+
153+
对比优化前后: 首屏绘制速度提升了 `8` 倍, 最大内容绘制速度提升 `11` 倍。本想优化 SEO, 结果站点性能优化的方式又 get 了一个。
154+
155+
### 生成站点地图 Sitemap
156+
157+
在完成预渲染实现站点路由静态化后, 距离 SEO 的目标又近了一步。暂且抛开 [SEO 优化细节](https://developers.google.com/search/docs/beginner/seo-starter-guide), 单刀直入 SEO 核心腹地 [站点地图](https://developers.google.com/search/docs/advanced/sitemaps/overview)
158+
159+
站点地图 Sitemap 格式与各字段含义简单说明如下:
160+
161+
```xml
162+
<?xml version="1.0" encoding="utf-8"?>
163+
<urlset>
164+
<!-- 必填标签, 这是具体某一个链接的定义入口,每一条数据都要用 <url> 和 </url> 包含在里面, 这是必须的 -->
165+
<url>
166+
<!-- 必填, URL 链接地址,长度不得超过 256 字节 -->
167+
<loc>http://www.yoursite.com/yoursite.html</loc>
168+
<!-- 可以不提交该标签, 用来指定该链接的最后更新时间 -->
169+
<lastmod>2021-03-06</lastmod>
170+
<!-- 可以不提交该标签, 用这个标签告诉此链接可能会出现的更新频率 -->
171+
<changefreq>daily</changefreq>
172+
<!-- 可以不提交该标签, 用来指定此链接相对于其他链接的优先权比值,此值定于 0.0-1.0 之间 -->
173+
<priority>0.8</priority>
174+
</url>
175+
</urlset>
176+
```
177+
178+
> 上述 sitemap 中, lastmod、changefreq、priority 字段对 SEO 没那么重要, 可以见 [how-to-create-a-sitemap](https://ahrefs.com/blog/zh/how-to-create-a-sitemap/)
179+
180+
根据上述结构, 笔者开发了 create-react-doc 的站点地图生成包 [crd-generator-sitemap](https://github.com/MuYunyun/create-react-doc/tree/main/packages/crd-generator-sitemap), 其逻辑就是将预渲染的路由路径拼接成上述格式。
181+
182+
使用方只需在站点根目录的 `config.yml` 添加如下参数便可以在自动化发版过程中自动生成 [sitemap](http://muyunyun.cn/create-react-doc/sitemap.xml)
183+
184+
```bash
185+
seo:
186+
google: true
187+
```
188+
189+
将生成的站点地图往 [Google Search Console](https://search.google.com/search-console/sitemaps) 中提交试试吧,
190+
191+
![](http://with.muyunyun.cn/97c21838a1e3310b3c1259e30ab85f3b.jpg)
192+
193+
最后验证下 Google 搜索[站点](https://www.google.com/search?q=site%3Amuyunyun.cn%2Fcreate-react-doc&ie=UTF-8)优化前后效果。
194+
195+
优化前: 只搜索到一条数据。
196+
197+
![](http://with.muyunyun.cn/aea3401e5a31587deb8d93a14f32b011.jpg)
198+
199+
优化后: 搜索到站点地图中声明的位置数据。
200+
201+
![](http://with.muyunyun.cn/6df1536366c7d45e0f6418af03a7d948.jpg)
202+
203+
至此使用 SSG 优化 SPA 站点实现 SEO 的完整流程完整实现了一遍。后续便剩下参照 [搜索引擎优化 (SEO) 新手指南](https://developers.google.com/search/docs/beginner/seo-starter-guide) 做一些 SEO 细节方面的优化以及支持更多搜索引擎了。
204+
205+
### 小结
206+
207+
本文从 SPA 站点实现 SEO 作为切入点, 先后介绍了 SEO 的基本原理, SEO 在 SPA 站点中的 4 种实践案例, 并结合 [create-react-doc](https://github.com/MuYunyun/create-react-doc) SPA 框架进行完整的 SEO 实践。
208+
209+
如果本文对您有所帮助, 欢迎 [star](https://github.com/MuYunyun/create-react-doc)[反馈](https://github.com/MuYunyun/create-react-doc/issues/new)
210+
211+
### 相关链接
212+
213+
- [google:how-to-create-a-sitemap](https://ahrefs.com/blog/zh/how-to-create-a-sitemap/)
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

‎config.yml

+13-4
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,27 @@ menu: [
99
'React',
1010
'BasicSkill',
1111
'Algorithm',
12-
'LeetCode'
12+
'FeCloud',
13+
'LeetCode',
14+
'Product'
1315
]
1416
## set init open menu keys
1517
menuOpenKeys: /BasicSkill
1618

19+
# used theme
20+
theme: crd-seed
21+
1722
# Github
1823
## if you want to editing pages on github, you should config these arguments.
1924
user: MuYunyun
2025
repo: blog
21-
branch: master # the default value of branch is master
26+
branch: main # the default value of branch is main
2227
deploy_branch: gh-pages # which branch to deploy.(default: gh-pages)
2328
# publish: # if you want upload to gitlab or other git platform, you can set full git url in it
29+
github-ribbons: true
30+
domain: https://muyunyun.cn
31+
seo:
32+
google: true
2433

2534
# use search plugin: provide ability for searching site globally in the site.
2635
# default value: true
@@ -36,5 +45,5 @@ deploy_branch: gh-pages # which branch to deploy.(default: gh-pages)
3645
# Available values: en | zh-cn
3746
language: en
3847

39-
# used theme
40-
theme: crd-seed
48+
# Inject Custom Logic
49+
inject: injectLogic.js

‎injectLogic.js

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/* eslint-disable no-empty */
2+
// seo: perf inject logic only once
3+
const inject = () => {
4+
// SEO for Google through https://search.google.com/search-console/welcome
5+
const meta = document.createElement('meta')
6+
meta.name = 'google-site-verification'
7+
meta.content = '7fyp1NuvXSRLM9KpMq5_YNE_0zFZkPnuV-SbVVFgWbI'
8+
document.head.appendChild(meta)
9+
}
10+
11+
module.exports = { inject }

‎package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@
3535
},
3636
"devDependencies": {
3737
"commitlint": "^11.0.0",
38-
"crd-seed": "^1.0.0",
39-
"create-react-doc": "^1.0.0",
38+
"crd-seed": "^1.1.3",
39+
"create-react-doc": "^1.1.3",
4040
"husky": "^4.3.8",
4141
"lint-md": "^0.2.0",
4242
"lint-md-cli": "^0.1.1",

0 commit comments

Comments
 (0)
Please sign in to comment.