SEO 優化 - SPA react-snap 預渲染
前言 : SPA 的 SEO 問題
搜索引擎使用“爬蟲" 來抓取您的網站,它會訪問在您網站上可以找到的每個頁面。然後將這些頁面上的內容添加到搜索索引中。
但是爬蟲在訪問 SPA 時會看到什麼?以 Blazor WebAssembly 為例:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<title>BlazorWasmPrerender</title>
<base href="/" />
<link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
<link href="css/app.css" rel="stylesheet" />
<link href="BlazorWasmPrerender.styles.css" rel="stylesheet" />
</head>
<body>
<div id="app">Loading...</div>
<div id="blazor-error-ui">
An unhandled error has occurred.
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
<script src="_framework/blazor.webassembly.js"><script>
</body>
</html>
像 Blazor 這樣的 SPA 框架需要執行 JavaScript 才能運行。大多數搜索引擎爬蟲不執行 JavaScript,這意味著 JavaScript 生成的內容不會被索引。
Google 的爬蟲確實會執行 JavaScript,它可以成功地索引 Blazor WebAssembly。
react-snap
原理是在背景啟動一個 headless chrome, 把 virtual DOM 的結果先抓出來,重新幫你貼到 html 裡。
而且他會幫你掃專案裡的 route 並產生對應的資料夾,
缺點就是只能用在純靜態網頁。
在此以 Blazor WebAssenbly 為例
將 react-snap 的必要配置 Prerender/package.json 添加到根目錄
{
"reactSnap": {
"source": "output/wwwroot",
"minifyHtml": {
"collapseWhitespace": true,
"removeComments": true
},
"puppeteerArgs": [ "--no-sandbox", "--disable-setuid-sandbox" ],
"skipThirdPartyRequests": true
}
}
修改 main.yml,加入以下片段
如 GutHub Action 不知如何操作,可操考此篇 Deploy To GitHub Pages
# Use NodeJS react-snap utitility to prerender static website
- name: prerender Blazor client
working-directory: Prerender
run: npx react-snap
# Delete script in all html files to include subfolder
- name: Delete script
working-directory: Prerender/output/wwwroot
run: |
find . -name "*.html" | while read htmlFile; do
sed -i 's/<script>var Module; window.__wasmmodulecallback__(); delete window.__wasmmodulecallback__;<\/script>//g' $htmlFile
sed -i 's/<script src="_framework\/dotnet.6.0.14.iiw8sbvu70.js" defer="" integrity="sha256-54cJ6JdGhGbKaLWxHfRYzYbuyRq2wlK\/ZDzfSXD3FEs=" crossorigin="anonymous"><\/script>//g' $htmlFile
done
上述刪除 script tag 的用途 :
在一般 Blazor WebAssembly 程序中,script tag 由腳本 blazor.webassembly.js 在瀏覽器加載腳本時生成。
如果不刪除會導致網頁在執行 JavaScript 時報錯,影響 Blazor 的運作
因為腳本作為預渲染時已經執行一次,但是當瀏覽器加載時腳本又被執行了。
其中要刪除的 script tag 內容,會根據你安裝的 .NET Core SDK 版本而有所不同
完整 main.yml
name: Deploy to GitHub Pages
# 每次程式碼Push到master,執行workflow
on:
push:
branches: [ master ]
jobs:
deploy-to-github-pages:
# 使用ubuntu
runs-on: ubuntu-latest
steps:
# 使用checkout actions
- uses: actions/checkout@v2
# 安裝.NET Core SDK 6.0.x
- name: Setup .NET Core SDK
uses: actions/setup-dotnet@v3
with:
dotnet-version: 6.0.x
# 執行單元測試專案
- name: Run Unit Test
run: dotnet test --no-build
# 發佈程式到Release資料夾
- name: Publish .NET Core Project
run: dotnet publish Blog/Blog.csproj -c Release -o Prerender/output --nologo
# Use NodeJS react-snap utitility to prerender static website
- name: prerender Blazor client
working-directory: Prerender
run: npx react-snap
# Delete script in all html files to include subfolder
- name: Delete script
working-directory: Prerender/output/wwwroot
run: |
find . -name "*.html" | while read htmlFile; do
sed -i 's/<script>var Module; window.__wasmmodulecallback__(); delete window.__wasmmodulecallback__;<\/script>//g' $htmlFile
sed -i 's/<script src="_framework\/dotnet.6.0.14.iiw8sbvu70.js" defer="" integrity="sha256-54cJ6JdGhGbKaLWxHfRYzYbuyRq2wlK\/ZDzfSXD3FEs=" crossorigin="anonymous"><\/script>//g' $htmlFile
done
# 複製index.html內容到404.html
- name: copy index.html to 404.html
run: cp Prerender/output/wwwroot/index.html Prerender/output/wwwroot/404.html
# 加入一個.nojekyll檔案
- name: Add .nojekyll file
run: touch Prerender/output/wwwroot/.nojekyll
# 將release/wwwroot的程式碼,push到gh-pages分支
- name: Commit wwwroot to GitHub Pages
uses: JamesIves/github-pages-deploy-action@3.5.9
with:
GITHUB_TOKEN: ${{ secrets.BLOGTOKEN }}
BRANCH: gh-pages
FOLDER: Prerender/output/wwwroot
完成後再到你的網頁下檢視原始碼,已經可以讀到完整的網頁內容
使用像 react-snap 這樣的預渲染工具,你可以預渲染 Blazor WebAssembly或其他 SPA 框架,將預渲染的應用程序部署到 GitHub Pages 提高 SEO