Angular Universal教學-將現有專案導入Server Side Render

找了各式各樣的文章,一直沒有看到完整關於Angular Univeral的詳細步驟教學

而在設定時也會有一些小細節需要處理,因此本文將完整從 Client Side Render 如何成功導入 Server Side Render

讓 Google的爬蟲能夠搜尋的到使用 Angular開發的網站。

在2020的今天,隨著Web Framework的竄起,使用前端框架 如:Angular,React,Vue開發系統早已是見怪不怪的事。

但這種前端主流框架,對於 SPA 沒辦法進行SEO一直以來都是開發者最為頭痛的事。

因此就有 Next.js 這類的工具可以協助我們進行Server-Side-Render。

而在Angular中,則有Angular Universal可以幫助我們解決問題。

早期 Angular 要使用 SSR 技術要新增不少的檔案與內容,但現在只需要使用cli的指令就可以達成。

加入 @nguniversal/express-engine 到專案中

在Angular專案下,我們可以安裝

ng add @nguniversal/express-engine --clientProject 專案名稱(可以由angular.json查看名稱)

執行指令後的異動

安裝後,我們會發現cli指令幫我們建立了不少檔案。

其中最主要的部份則以server.ts 以及 app.server.module.ts這兩支檔案為主。

這邊簡單說明一下:

server.ts主要是運行我們SSR最主要的程式,透過這支程式,會自動在部屬時自動將首頁進行編譯,讓我們的angular的程式,能夠預先載入到index.html中

而不是透過瀏覽器執行的時候才將js渲染到畫面上。簡單來說,就是該程式就是將首頁的js進行編譯,並載入到html中回傳靜態的網頁內容。

app.server.module.ts 則是與app.module.ts相同,但不同的是,透過ssr編譯時,會採用的是app.server.module.ts進行呼叫。

在安裝好express-engine 套件後,接下來要運行 Universal Web Server。

這裡跟一般我們平時在使用 ng serve 一樣,都是去呼叫 node.js的express起來,進行監聽。

輸入以下指令

npm run build:ssr;npm run serve:ssr

就會執行 ssr 的build(部屬)以及serve(運行)。

如果正確無誤的話,那麼你將會看到以下畫面:

但如果不能build 出現 can't find window / localstorage的話。由於SSR是透過nodejs預先將頁面進行編譯以及載入。

因此在nodejs中並沒有 windows 或是 localStorage等其他在Web上的功能。

儘管可以透過 nodeJS進行部分模擬,放入到 server.ts中,讓node.js讀懂這些語法是什麼。

但大多數在Client Side中的語法,還是得需要透過瀏覽器去運行。

讓node.js讀懂的語法如下:

import 'localStorage-polyfill';
global['localStorage'] = localStorage;

但如果是其他的套件,例如應該要在Client端運行的 Ex: jQuery/scroll ...等
就不應該由Server編譯的時候執行。

必須區分哪些程式碼應該要在Server進行SSR編譯時執行,哪些該由Client執行的時候運行。

因此我們需要在 Component的 constructor 中 注入:

constructor(@Inject(PLATFORM_ID) private platformId: any) { }

並且在需要由Client端執行的程式碼加入以下判斷:

    if (isPlatformBrowser(this.platformId)) {
      const anchorOffset = $('div.anchor-' + this.anchor);
      $('html,body').animate({
        scrollTop: anchorOffset.offset().top - 100
      }, 100);
    }

像上面這種有使用到 jQuery還有scroll,牽涉到畫面甚至是動畫效果的,都應該由Client端執行,而非在 Server端中執行。

因此我們就需要透過 isPlatformBrowser(this.platformId) 來判斷當前執行此段程式碼是否為Browser

若是在SSR編譯時期,則該段程式就不會被運行。

註記: 若使用 ngModel的話,使用到該物件的所有兜必須要先初始化 才能使用,讓nodejs編譯。

若上述都完成,則會在dist建立browser以及server這兩個資料夾 。
browser:編譯完後所產生的程式碼,內含有index.html (和過去使用 ng build --prod相同)
server =>在SSR渲染的第一頁中,所有用到的圖檔,以及js都會在這裡

若正常完成的話,會自動在 localhost端 監聽 4000 port 來運行SSR
Node Express server listening on http://localhost:4000

此時將網頁按右鍵檢視原始碼,將會看到 在 <app-root></app-root> 中的程式碼已經被自動帶入。

 

以上文章敘述如有錯誤及觀念不正確,請不吝嗇指教:)

有任何家教、案子 或技術相關問題 請都歡迎聯繫我

http://www.zhenghui.idv.tw/