Vue2 with PhantomJS Server Side Render

建立時間: 2017-06-20 23:57:10
更新時間: 2017-06-29 13:41:42

 

概要

Introduction

How it work

佈署

容易踩到的雷

 

Introduction

Single Page Web最令人頭痛的問題就是SEO

雖然這幾年Google已經能夠正確的檢索Single Page Web

但是遇到不支援JS的搜尋引擎

Single Page對它們來說爬出來是一片空白的

 

另外Facebook雖然有支援hashbang(#!)

但是vue在2.x版本表示Google已經拿掉hashbang

所以vue-router也把hashbang給拿了

結果這樣一來我原本網站非同步設定的Open Graph Tag Facebook全部爬不到

 

為了這個問題在學vue.js的期間

還會一直懷疑自己對vue.js的投資到底正不正確

研究了PhantomJS的Server Side Render後

寫了個Laravel + PhantomJS的專案

才得以完全解決這個問題

也讓我覺得這陣子對vue.js的投資至少不算白費

畢竟SEO也是Web很重要的一環

 

How it work?

Server Side Render的流程大約可分為下列6個步驟

 

1. 判斷user-agent

.htaccess判斷瀏覽器的user-agent

如果不是chrome, firefox, opera, edge等支援js的瀏覽器

頁面將會導向client folder中的seo.php

它會向Server Side Render主機發出請求

直接做Server Side Render

並echo出來給瀏覽器爬

 

2. 使用symfony process執行PhantomJS

這邊使用symfony process來執行PhantomJS的指令

 

3. client端回傳Page done

在專案的client folder內有一支phantom.js

我們可以在vue的main.js中import這支library

 class Phantom {
   constructor() {
     if(!(typeof(window.callPhantom) == 'function')) return
     $(document).ajaxComplete(() => {
       if($.active <= 1) {
         this.callPhantom()
         $(document).ajaxComplete(null)
       }
       return
   	})
   }
 
   callPhantom() {
     window.callPhantom('pageDone')
   }
 }
 
 export default new Phantom()

 

這邊主要是利用jQuery的AJAX Complete

當所有非同步的請求完成後

告訴PhantomJS可以開始爬網頁

這邊可以參考PhantomJS的官方文件

 

當然如果專案不是使用AJAX來做非同步請求(例如axios)

那也可以修改一下這支client library

只要確定請求完成

就可以使用window.callPhantom('pageDone')告訴PhantomJS頁面render完成

 

4. PhantomJS開始爬網頁

在專案的/server/resources/crawler中有一支render.js

當他接收到前端的window.callPhantom('pageDone')

就會開始爬頁面

並將爬到的內容跟狀態寫成json存到/tmp

 

6. 回傳給瀏覽器或是bot

當PhantomJS將頁面結果寫到/tmp

SEOController會取出這個json

將json回給client端的seo.php

最後seo.php再視回傳狀態的代碼

決定echo出網站內容

或是直接回HTTP 404狀態給瀏覽器或bot

 

佈署

詳見Github文件

 

容易踩到的雷

 

GTM

如果有使用GTM(Google Tag Manager)

要小心不能有JS錯誤

否則PhantomJS會爬出一片空白

 

ES6

因為phantomjs並不支援ES6

所以如果網站有使用ES6(只要使用vue-cli webpack template都會用到)

必須幫web裝上babel-polyfill

不然PhantomJS一樣會爬不到任何內容