Angular - ลอง SSR บน v17
Published: 2023-12-17 06:59:27

จำได้ว่าสมัยก่อน v17 เคยพยายามลองเล่น SSR ผ่านโปรเจคที่ชื่อว่า Universal มาก่อน ได้พี่ต้นมาช่วย 🙏 พอมา v17 นี้ ทีม Angular เห็นว่าทำได้สะดวกและง่ายขึ้น งั้นมาลองกัน


## ก่อนจะไป SSR
ก่อนจะรู้จัก SSR เรามารู้จักท่ามาตราฐานของ Angular ก่อนนั้นก็คือ **CSR (Client Side Rendering)** ตาม concept ของมัน คือ

![Sequence Diagram of CSR](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c4wsstdqntznb3c53gc2.png)

หลังจาก user ใส่ url แล้ว Browser ก็จะได้ HTML กลับมา แต่.. HTML นั้นไม่ได้มี content อะไรเลยเพราะ content จริงๆแล้วอยู่ใน JS จากนั้น browser ก็จะทำดึง JS&CSS มาเพิ่ม คราวนี้ browser ถึงจะเริ่ม render content จาก JS แล้วแสดงผลได้จริงๆ

ซึ่งโดยถ้าเราสร้างเวปแอปด้วยคำสั่ง `ng new my-app` โดย default Angular จะสร้าง project เป็น CSR ซี่งก็มีความสุขดี  ข้อดีของ CSR คือเรียบง่าย ไม่ซับซ้อน วิธี deploy ก็แค่ build ให้ได้ HTML, JS, &CSS ไปวางที่ web server เช่นพวก nginx ก็พอ เดี๋ยว Browser จะหอบเอาไฟล์ไปวาดเองสวยๆ แต่ว่า...


## เมื่อ Client ไม่ได้มีแต่ Browser
คือถ้าเวปเราเป็นแนว login มาทำงาน กด next, next, submit ก็ไม่ได้มีปัญหาอะไรเลย แต่ถ้าเริ่มจะมีการให้ติดอันดับในค้นหาใน Search Engine หรือจะต้องโพส URL ประชาสัมพันธ์ใน Social media ต่างๆ ปัญหาจะเริ่มเกิดขึ้นละ

![Sequence Diagram of CSR with Spider Bot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m2fnwuas357dcno4ecqz.png)

ใน CSR นั้น server จะทำการส่งมาแค่ HTML(no content) โปรแกรมพวก Spider Bot ที่คอยวิ่งไปตามเวปต่างๆ ทำการแกะ content เพื่อไว้ทำข้อมูลให้ Search Engine จะเกิดอาการงง เพราะ HTML ไม่มี content อะไรเลย ดังนั้นการจะติดอันดับค้นหาต้นๆ จะยากมาก นี่ยังไม่รวมเวลาเราเอา URL ของเวปเราไปโพสใน Social media ที่จะมีการเอารูปในเวปของเราไปแสดง (เพราะมีแต่ HTML ไม่มี content) ก็จะไม่สามารถแสดงได้เช่นกัน


## SSR มาตอนนี้แหละ
เพื่อแก้ปัญหานี้ Angular ก็เลยมีท่า render HTML(with content) ในทางเทคนิคเวปเราก็เป็น JS อยู่แล้ว เราก็เลยสามารถใช้ JS Engine อย่างเช่น NodeJS มาทำตัวเปรียบเสมือน browser จอมปลอมช่วย render HTML(with content) ขึ้นมาได้ เราจึงเรียกขั้นตอนนี้ว่า Server Side Rendering นั้นเอง 

![Sequence Diagram of SSR](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d7ximfmegdcjuawfw5eh.png)


## SSR ใน Angular
ใน v17 ทีมได้เพิ่ม option ในตอนสร้างเวปแอปให้สามารถเลือกได้เลยว่าอยากได้เป็น SSR หรือเปล่า ซึ่งสะดวกกว่าเดิมมาก ๆ

![ng new with SSR Option](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1w6oqyuowtgnp3xg5v7l.png)


## ว่าแล้วก็ Build & Run 🏃
ก่อนจะ implement อะไร เราลอง build & run กันก่อนเลยครับ


![build command](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rmuursz0d2lu8bihj615.png)


![build results](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ckkhzycrkj4kg0jo6pd1.png)

สังเกตว่าหลังจาก build เราจะ folder ตามชื่อโปรเจค และด้านในจะแบ่งเป็น browser (สำหรับ CSR) และ server (สำหรับ run SSR) จากนั้นเรามาลอง run file ที่ build มาได้กัน โดยส่วนที่เป็น _Render Process_ จะใช้ NodeJS ทำการ run server (Express.js) มาเพื่อหยิบไฟล์ใน browser (CSR) มา render ก่อนส่งไปให้ client นั้นเอง

> node ./dist/ng17-ssr-demo/server/server.mjs

![run node](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cqo1qxbtnt4gcrwbdsc7.png)

![home page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/za20nu93jdml4goc0n2t.png)

![view-source of home page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yf5v2kqgkyns80v4fx7e.png)

เราก็จะได้ HTML ที่ render มาให้เรียบร้อย จบปิ๊ง ~


### Bonus
ในส่วนของ deployment ถ้าเราใช้ docker เราก็เขียน Dockerfile ท่า multi-stages ประมาณนี้ได้เลย

```Dockerfile
# builder
FROM node:20.10-alpine as builder

WORKDIR /app

COPY package*.json ./

RUN npm ci

COPY . .

RUN npm run build

# production
FROM node:20.10-alpine

WORKDIR /app

COPY package*.json ./

RUN npm ci --omit=dev

COPY --from=builder /app ./

EXPOSE 4000

ENTRYPOINT ["node","/app/dist/ng17-ssr-demo/server/server.mjs"]
```

Refs: 
- [Angular.dev Server-side rendering](https://angular.dev/guide/ssr#enable-server-side-rendering)
- [Angular 17 SSR - Angular Server Side Rendering in a New Way](https://www.youtube.com/watch?v=4KH-TStaiGw)