Deploying Static React Next.js to AWS S3


สวัสดีครับ บล็อกนี้จะมาแนะนำ host ดีๆสำหรับคนทำ static website เช่น single page, landing page, personal blog หรือจะเป็นเว็บอะไรก็ได้ที่เป็น website แบบ static เช่นเว็บที่สร้างด้วย React, Next หรือ Framwork ตัวอื่นที่สามารถ export ออกมาเป็บ static website ได้คือได้เป็นไฟล์ html css javascript และไม่ได้เชื่อมต่อกับฐานข้อมูลใดๆ
เนื้อหา
สร้างโปรเจคด้วย Next.js
npx create-next-app
จากคำสั่งนี้จะมีคำถามอยู่ 2 คำถามเกี่ยวกับการสร้างโปรเจคคือ
- Need to install the following packages คือถ้าจะสร้างจะต้องติดตั้ง package create-next-app ตกลงไหม
- What is your project named? คือตั้งชื่อโปรเจคอะไรก็ได้ ถ้าไม่ใส่จะได้ชื่อ my-app โดยอัตโนมัติ
หลังจากติดตั้งเสร็จ มาลองสั่ง start โปรเจคด้วยคำสั่ง npm run dev
cd my-appnpm run dev
จากนั้นสามารถเข้าตัว website ได้จาก http://localhost:3000 ไปที่ browser แล้วลองเข้าตาม url จะเจอหน้าเว็บแบบนี้
AWS S3
เราจะใช้ service ตัวนึงของ AWS ที่ชื่อ S3 เป็น Bucket Storage สำหรับเก็บไฟล์แบบ Object สามารถเข้าถึงได้ผ่านทาง HTTPS จะใช้เป็นตัวเก็บไฟล์ website ของเรา ความสามารถของ S3 bucket ก็คือเป็นที่เว็บไฟล์ทั่วไปนี้แหละ และมันสามารถใช้เป็น host ให้ static website ได้ด้วย
สร้าง S3 Bucket
- ต้อง login aws ก่อน
- ไปที่ S3
- กดที่ Create bucket
- ในหน้า Create bucket ให้ตั้งชื่อ Bucket name
- ในหน้า Create bucket เอา Block all public access ออก แล้วติ๊กเพื่อรับทราบด้านล่าง แล้วกด save
- ในหน้า Create bucket ให้ตั้งชื่อ Bucket name
- เมื่อสร้างเสร็จจะได้ bucket ตามชื่อที่เราตั้ง ให้คลิกเข้าไปเพื่อจะตั้งค่าเพิ่มเติม
- ในหน้า bucket ไปที่เมนู Properties > Static website hosting > Edit
- ในหน้า Edit ตั้งชื่อ Index document ว่า index.html มันคือชื่อไฟล์ home page ของเรา เสร็จแล้วอย่าลืมกด save
- ในหน้า Edit ตั้งชื่อ Index document ว่า index.html มันคือชื่อไฟล์ home page ของเรา เสร็จแล้วอย่าลืมกด save
- ในหน้า bucket ไปที่เมนู Permissions > Bucket policy > Edit
- กำหนด policy ตามนี้
- กำหนด policy ตามนี้
- ในหน้า bucket ไปที่เมนู Properties > Static website hosting > Edit
อย่าลืมเปลี่ยนตรง arn:aws:s3:::my-s3-example-name-2022 เป็นชื่อ bucket ที่เราตั้งไว้
ปิดท้ายใส่ /* ด้วย
{ "Version": "2012-10-17", "Statement": [ { "Sid": "PublicReadGetObject", "Effect": "Allow", "Principal": "*", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::my-s3-example-name-2022/*" } ]}
เราจะได้ url ที่ใช้เข้า website ของเราได้ในหน้า bucket ไปที่เมนู Properties > Static website hosting
พอถึงตรงนี้ S3 bucket พร้อมให้เอาไฟล์มาวางแล้ว
export static website
ก่อนอื่นต้องเพิ่มคำสั่งในไฟล์ package.json
"scripts": { // ... "export": "next export", // ... },
จากนั้นทำการ build และ export เพื่อให้ได้ static ไฟล์เพื่อเอาไป deploy ที่ S3 ได้เลย
npm run buildnpm run export
Next.js ใน version ใหม่จะเจอ error ประมาณว่า Error: Image Optimization using Next.js’ default loader is not compatible with
next export
เราต้องแก้โดยการเพิ่ม config images.unoptimized = true ที่ไฟล์ next.config.js
const nextConfig = {...experimental: {images: {unoptimized: true,},},...}module.exports = nextConfig
จะได้ directory ที่ชื่อว่า out ได้จากคำสั่ง next export เราสามารถเอาไฟล์ที่อยู่ใน out ไปใช้ deploy ได้เลย
นำขึ้น AWS S3 Bucket
การนำไฟล์ขึ้น S3 มีอยู่ 2 วิธีคือ
-
ใช้ aws cli หากใครใช้ aws cli อยู่แล้วสามารถใช้คำสั่ง sync ได้เลย จากคำสั่งนี้หมายความว่าเราจะนำไฟล์ทั้งหมดใน out ไปใส่ที่ s3 bucket ของเรา
Terminal window aws s3 sync out s3://<bucket-name>/ -
อัพโหลดตรงๆผ่านหน้าเว็บ aws
ปัญหาที่พบ
หลังจากลองใช้ประมาณ 1 เดือนกว่า ได้ลอง deploy หลายๆรอบก็เจอปัญหาเรื่อง routing ของ next สมมุติว่าเว็บเรามีอยู่ 2 หน้าคือ home, about แล้ว routes จะเป็น /, /about ปัญหาคือตอนเข้าตรงๆผ่าน url /about กับ refresh จะขึ้นประมาณว่า error page not found สาเหตุเกิดจาก AWS S3 ไม่รู้จักไฟล์ about.html วิธีแก้คือเปลี่ยน about.html เป็น about คือเอาสกุลไฟล์ออก
ทีนี้ถ้าเรามีหลายไฟล์มากๆ 20 - 30 ไฟล์ เราต้องมา rename ทุกไฟล์ที่เป็น .html เลยไหม คำตอบคือใช่ครับ แต่ก็มีวิธี rename อยู่ 2 วิธี
- rename ตรงๆผ่านหน้าเว็บ
- rename โดยใช้ aws cli จริงๆมันไม่มีคำสั่ง rename ตรงๆมีแค่คำสั่ง mv หรือย้ายไฟล์นั้นเอง
จากคำสั่งนี้สามารถ rename ได้ทีละไฟล์อยู่ดี แต่เราสามารถเอาคำสั่งนี้ไปเขียนโปรแกรมให้มัน run อัตโนมัติได้ด้วย library ที่ชื่อ child_process ในบทความนี้จะยังไม่เขียนอธิบายวิธีการทำ ว่ามันทำอย่างไร 😎
Terminal window aws s3 mv s3://<bucket-name>/about.html s3://<bucket-name>/about