(SSR) Server-Side Rendering with Angular

Bibby Chung
my-coding-life
Published in
7 min readMar 31, 2018

--

image from: https://www.sitepoint.com/website-usability-page-speed-birds-feather/

如果你是寫 web 的,Server-Side Rendering (SSR) 這個詞,相信你應該聽過了,或是使用 Single-Page Application (SPA) 方式寫 web,在最佳化您的 web application 或解決 Search engine optimization (SEO) 的問題時,應該也會找到這個…

其實大約在兩年前的時候,這東西就出現了,然後我有稍微研究一下,只是當時覺得好麻煩,又感覺還沒有很成熟,所以就暫時放著了…但是現在這東西在 Angular 5 後,設定一整個方便又簡單,所以今天來簡單記錄一下要怎麼使用在 Angular 5 裡面…不過先來用圖片解釋一下這東西…

image from: https://www.upwork.com/hiring/development/server-side-rendering/

這張圖是一個比較 Client-Side Rendering (CSR) 跟 Server-Side Rendering (SSR) 的不同,看 SSR 的部份可以看到在第二步的時候,已經丟出大致的 HTML,使用者就可以看到初步的畫面了,不過在這時候,因為 JavaScript 還沒有下載完成,所以還是不能互動,但是對使用者來說,畫面已經出現了,所以使用者的「觀感」會比原先 CSR 的好很多…此外,因為 SSR 在初步就丟出 HTML 了,所以對於 Crawler 來說就是原生的支援了,也解決了 SEO 的問題…

所以總結來說,SSR 解決了…

  1. 縮短首屏顯示時間
  2. Client-Side Rendering 時 SEO 無法解析的問題 ( google 說會它 SEO Engine 很聰明會自己 parse 了,但… )

這兩個大問題,一直是 SPA 或是 大量使用 JavaScript 專案的痛點,但是對於 Angular 5 後的使用者,變成很簡單,只要設定一下,幾個步驟就可以簡單使用了…

首先建立個空白專案吧…(先確認一下 Angular CLI 1.6 以上)

ng new ssr-demo && cd ssr-demo

加入 SSR

ng g universal universal && npm i

修改 package.json 的 build

"build": "ng build --prod && ng build --prod --app universal --output-hashing=none"

然後你就可以 build 一下你的 project

npm run build

這裡用 node 做 Server-Side 的部份,先裝 express 及相關套件

npm i express @nguniversal/express-engine

然後在根目錄下加入「server.js」

'use strict';/* Server specific version of Zone.js */require('zone.js/dist/zone-node');const express = require('express');const ngUniversal = require('@nguniversal/express-engine');/* The server bundle is loaded here, it's why you don't want a changing hash in it */const appServer = require('./dist-server/main.bundle');/* Server-side rendering */function angularRouter(req, res) {/* Server-side rendering */res.render('index', { req, res });}const app = express();/* Root route before static files, or it will serve a static index.html, without pre-rendering */app.get('/', angularRouter);/* Serve the static files generated by the CLI (index.html, CSS? JS, assets...) */app.use(express.static(`${__dirname}/dist`));/* Configure Angular Express engine */app.engine('html', ngUniversal.ngExpressEngine({bootstrap: appServer.AppServerModuleNgFactory}));app.set('view engine', 'html');app.set('views', 'dist');/* Direct all routes to index.html, where Angular will take care of routing */app.get('*', angularRouter);app.listen(3000, () => {console.log(`Listening on http://localhost:3000`);});

這樣就可以執行了

node server.js

如果看到這樣的 source code 那就表示成功啦! ^&^…恭喜恭喜…

不過在實作上,還是有一些雷要踩的,名言都這樣說的「理想是豐滿的,現實是骨感的」,所以…這裡分享一下遇到的小小問題 =.=…

  1. — prod 模式下才可以使用,除了要 build 出 dist-server 這個 folder , ng 還要加上 — prod 這個參數,沒加就壞掉給你看
  2. server.js 裡面的 app.get(‘/’, angularRouter) 一定要在app.use(exp.static(`${__dirname}/dist`)) 之上,不然跑出來還是沒有 SSR
  3. 在使用一些套件的時候,如果套件使用 es6 es7 瀏覽器不支援的 features,那就會爆掉,可以使用 babel 來 compile 你用的套件,我貼一下我的 code
// 安裝
npm i babel-cli, babel-preset-es2015
// 用 babel 來編譯你的套件
./node_modules/.bin/babel node_modules/<your component> -d node_modules/<your component> — presets es2015

以上應該就是目前遇到的,如果還有遇到新的,我在來補上…

references:
https://medium.com/walmartlabs/the-benefits-of-server-side-rendering-over-client-side-rendering-5d07ff2cefe8
https://medium.com/@cyrilletuzi/angular-server-side-rendering-in-node-with-express-universal-engine-dce21933ddce
https://www.upwork.com/hiring/development/server-side-rendering/

--

--