ส่วนหน้า: การใช้ Gatsby.js และ Node.js สำหรับการอัปเดตไซต์แบบคงที่
เผยแพร่แล้ว: 2022-03-11สำหรับข้อกำหนดของโปรเจ็กต์บางอย่าง การสร้างเพจสแตติกไม่เพียง เพียงพอ แต่ยัง มีประสิทธิภาพสูงสุด ในแง่ของความเร็วและความสามารถในการขยาย
ในช่วงครึ่งแรกของซีรีส์นี้ เราได้รวม Node.js, Express, MongoDB, cron และ Heroku เพื่อส่งแบ็กเอนด์ที่พร้อมใช้งาน CI ซึ่งใช้ API ของ GitHub ตามกำหนดการรายวัน ตอนนี้เราพร้อมที่จะเพิ่ม Gatsby ลงในมิกซ์เพื่อให้โครงการสร้างเพจคงที่ของเราเสร็จสมบูรณ์
การพัฒนาส่วนหน้า: ทำให้เป็นเว็บไซต์ของ Gatsby
เนื่องจากเว็บไซต์ Gatsby นั้นใช้ React จึงเป็นประโยชน์หากคุณคุ้นเคยกับวิธีสร้างเว็บไซต์ด้วย React อยู่แล้ว
สำหรับการจัดแต่งทรงผม ฉันชอบ Bootstrap, reactstrap และ react-markdown คุณอาจรู้ว่าบันทึกประจำรุ่นใน GitHub นั้นจัดเก็บไว้ในรูปแบบ Markdown ดังนั้นเราจึงจำเป็นต้องมีตัวแปลง
โครงสร้างโครงการเว็บไซต์แบบคงที่
โครงสร้างไฟล์/โฟลเดอร์ของเราจะเป็นดังนี้:
ไฟล์เหล่านี้มีไว้เพื่ออะไร? มาดูกัน:
-
env.development
และenv.production
เป็นไฟล์การกำหนดค่าตัวแปรสภาพแวดล้อม - เทมเพลต
all-repositories.js
จะใช้สำหรับหน้าแรกของเรา ซึ่งมีรายการที่เก็บ - เทมเพลต
repository.js
จะใช้เพื่อแสดงรายละเอียดของที่เก็บที่ระบุ -
gatsby-node.js
คือที่ที่เราใช้จุดสิ้นสุดส่วนหลังและเรียกใช้createPage
ของเรา -
package.json
มีการอ้างอิงและคุณสมบัติของโครงการเช่นเคย -
global.css
เป็นไฟล์สไตล์ชีตหลักของเรา
การติดตั้งเว็บไซต์ Gatsby
เช่นเดียวกับส่วนหลังของเรา ให้รัน npm install
(หรือ yarn
หากคุณติดตั้ง Yarn ไว้) หลังจากเพิ่มการพึ่งพาที่จำเป็นใน package.json
ของส่วนหน้า:
{ // ... "dependencies": { "axios": "^0.18.0", "bootstrap": "^4.3.1", "gatsby": "^2.0.0", "react": "^16.5.1", "react-dom": "^16.5.1", "react-markdown": "^4.0.6", "reactstrap": "^7.1.0" } // ... }
ไฟล์ env.development
และ env.production
มีเฉพาะ URL แบ็คเอนด์สำหรับสภาพแวดล้อมที่เกี่ยวข้องเท่านั้น อดีตมี:
API_URL=http://localhost:3000
…ในขณะที่การผลิตมี:
API_URL=https://[YOUR_UNIQUE_APP_NAME].herokuapp.com
gatsby-node.js
จะทำงานเพียงครั้งเดียวในขณะที่คุณสร้างโค้ด ดังนั้นเราจึงต้องรวบรวมข้อมูลที่จำเป็นทั้งหมดจากส่วนหลังของเราที่นี่ จากนั้น การตอบสนองจะใช้กับเทมเพลตของเราเพื่อสร้างเพจสแตติกที่เหมาะสม
ในกรณีของเรา all-repositories.js
ต้องการที่เก็บทั้งหมด และ repository.js
ต้องการที่เก็บที่สอดคล้องกันสำหรับการวนซ้ำแต่ละครั้ง สุดท้าย เราสามารถสร้างพาธของเพจแบบไดนามิก โดยส่งผ่าน owner
ที่เก็บและพารามิเตอร์ name
เป็นส่วนหนึ่งของฟิลด์ path
:
const axios = require('axios'); require("dotenv").config({ path: `.env.${process.env.NODE_ENV}` }); const getRepositoryData = async () => { console.log(process.env.API_URL); return axios.get(`${process.env.API_URL}/repositories`); }; exports.createPages = async ({ actions: { createPage } }) => { let repositories = await getRepositoryData(); repositories = repositories.data; // Create a page that lists all repositories. createPage({ path: `/`, component: require.resolve('./src/templates/all-repositories.js'), context: { repositories } }); // Create a page for each repository. repositories.forEach(repository => { createPage({ path: `/repository/${repository.owner}/${repository.name}`, component: require.resolve('./src/templates/repository.js'), context: { repository } }); }); };
สำหรับ all-repositories.js
และ repository.js
หากเราละเว้นสไตล์ เราก็แค่รวบรวมข้อมูลจาก pageContext
และใช้งานในขณะที่เราใช้พารามิเตอร์ใน React
ใน all-repositories.js
เราจะใช้ฟิลด์ repositories
ของ pageContext
ดังนี้:
export default ({pageContext: {repositories}}) => ( // ... <ListGroup> {/* Because the repositories parameter is a list, we are iterating over all items and using their fields */} {repositories.map(repository => (repository.tagName && <ListGroupItem className="repository-list-item"> // ... <Row> {`${repository.repositoryDescription}`} </Row> // ... </ListGroupItem> ))} </ListGroup> // ... );
สำหรับ repository.js
เราจะใช้ฟิลด์ที่ repository
ของ pageContext
แทน:
export default ({pageContext: {repository}}) => ( <div className="layout"> {repository.tagName && <ListGroupItem className="repository-list-item"> // ... <h1 className="release-notes">{`Release notes`}</h1> <hr/> {/* This the place where we will use Markdown-formatted release notes */} <ReactMarkdown source={`${repository.releaseDescription}`}/> </ListGroupItem> } // ... </div> );
ตอนนี้ ตรวจสอบให้แน่ใจว่าส่วนหลังของคุณพร้อมใช้งานแล้ว คุณจะจำได้ว่าสำหรับโปรเจ็กต์นี้เราตั้งเป็น http://localhost:3000
ต่อไป รัน gatsby develop
จากรูทของโปรเจ็กต์ front-end แล้วเปิด http://localhost:8000
หากคุณเพิ่มที่เก็บข้อมูล (เจ้าของ/ชื่อ) ในส่วนแบ็คเอนด์และเรียกใช้คุณสมบัติ update-via-GitHub-API อย่างน้อยหนึ่งครั้ง คุณควรเห็นสิ่งนี้:
และหลังจากคลิกหนึ่งในที่เก็บ คุณควรเห็นสิ่งนี้:
หลังจากการเปลี่ยนแปลงข้างต้น การใช้งานส่วนหน้าของเราเสร็จสิ้น
ยอดเยี่ยม! ตอนนี้เราแค่ต้องปรับใช้
การปรับใช้ส่วนหน้า
เราไม่จำเป็นต้องทำการเปลี่ยนแปลงใดๆ ในแอปพลิเคชันส่วนหน้าในส่วนนี้ เราจะปรับใช้กับ Netlify ได้ง่ายๆ โดยคุณจะต้องมีบัญชีอยู่ที่นั่น
แต่ก่อนอื่น เราต้องปรับใช้โค้ดของเรากับ GitHub, GitLab หรือ Bitbucket ในส่วนแบ็คเอนด์ ฉันปรับใช้โค้ดของฉันกับ GitHub
จากนั้นเข้าสู่ระบบ Netlify และคลิกปุ่ม "ไซต์ใหม่จาก Git" บนแดชบอร์ดของคุณ ทำตามขั้นตอนบนหน้าจอเพื่อเลือกผู้ให้บริการ Git และค้นหาที่เก็บของคุณ
สำหรับขั้นตอนสุดท้าย หากคุณจัดโครงสร้างโค้ดของคุณอย่างถูกต้อง Netlify จะตั้งค่าคำสั่ง build และเผยแพร่ไดเร็กทอรีอย่างถูกต้องโดยอัตโนมัติดังนี้:

จากนั้นคลิก "ปรับใช้ไซต์" มันจะปรับใช้ไซต์ของคุณกับโดเมนย่อย Netlify ที่สร้างแบบสุ่ม แต่คุณสามารถเปลี่ยนได้ตลอดเวลา—ฉันเปลี่ยนการทำให้ใช้งานได้เป็น https://sample-create-page-api-gatsby.netlify.com ซึ่งคุณจะพบการสาธิตสด ของแอปที่เสร็จสมบูรณ์
จนถึงตอนนี้ดีมาก แต่เนื่องจากเป็นแอปพลิเคชันเพจแบบสแตติก เราจึงต้องสร้างใหม่ทุกวันเพื่อให้อัปเดตอยู่เสมอ
อัพเดททุกวันโดยใช้ Build Hook
Build hooks ใน Netlify ทำงานเป็นตัวกระตุ้นบิลด์ ดังนั้นคุณจึงสามารถทริกเกอร์พวกมันจากส่วนหลังของคุณหลังจากที่งาน cron เสร็จสิ้น ขั้นแรกให้สร้าง build hook ใน Netlify
ในส่วน "สร้างและปรับใช้ → การปรับใช้อย่างต่อเนื่อง" คุณจะพบ "สร้าง hooks" คลิก "เพิ่มเบ็ดบิลด์"
ตั้งชื่อและบันทึก (ฉันเรียกว่า mine build-from-backend
) จากนั้นคัดลอกลิงก์ที่สร้างขึ้น
ตอนนี้ มาเปิดโปรเจ็กต์แบ็คเอนด์ของเราและเพิ่มสองสามบรรทัดเหล่านี้ในไฟล์ cron.controller.js
เราเพียงแค่ส่งคำขอ POST
ไปยัง build-hook URL ของ Netlify
const Axios = require('axios'); const Config = require('../config/env.config'); const NETLIFY_BUILD_HOOK_URI = Config.netlifyEndpoint; function updateGatsby() { if (NETLIFY_BUILD_HOOK_URI) { console.log('Gatsby build request will be send'); Axios.post(NETLIFY_BUILD_HOOK_URI).then(() => { console.log('Gatsby build request was successful'); }); } }
จากนั้นอัปเดตฟังก์ชัน updateDaily
ของเรา:
function updateDaily() { RepositoryController.updateRepositories().then(() => { updateGatsby(); }); }
สุดท้าย อัปเดตไฟล์ env.config.js
เพื่อตั้งค่าคุณสมบัติ netlifyEndpoint
ที่จะรวบรวมจากตัวแปรสภาพแวดล้อม:
"netlifyEndpoint": process.env.NETLIFY_BUILD_HOOK || ""
ตอนนี้ คุณจะต้องตั้งค่าตัวแปรสภาพแวดล้อม NETLIFY_BUILD_HOOK
ที่คุณคัดลอกมาจาก Netlify เมื่อสักครู่นี้ ใน Heroku คุณสามารถตั้งค่าตัวแปรสภาพแวดล้อมได้จากส่วน "การตั้งค่า" ของแอปพลิเคชันของคุณ
หลังจากส่งคำสั่งของคุณแล้ว แอปพลิเคชันส่วนหลังจะส่งคำขอสร้างไปยัง Netlify และหน้าของคุณจะได้รับการอัปเดตทุกวันเมื่อสิ้นสุดงาน cron นี่คือลักษณะของ repo หลังจากเพิ่มฟังก์ชัน build hook พร้อมกับเวอร์ชันสุดท้ายของ back-end repo และ front-end repo
เมื่อสิ้นสุดโครงการ เราจะแสดงวิธีใช้ฟังก์ชัน AWS Lambda ที่ทริกเกอร์โดย AWS CloudWatch ที่จะปลุกระบบแบ็คเอนด์ของคุณทันเวลาสำหรับการอัปเดตรายวันแต่ละครั้ง
คำขออย่างง่ายของ AWS Lambda และ AWS CloudWatch
AWS Lambda เป็นแพลตฟอร์มการประมวลผลแบบไร้เซิร์ฟเวอร์ เราต้องการแค่พื้นฐานพื้นฐานของแพลตฟอร์มนี้เพื่อจุดประสงค์ของเราที่นี่ คุณจะต้องมีบัญชี AWS
ขั้นแรก เข้าสู่ระบบ AWS ด้วยบัญชีของคุณและค้นหา Lambda Management Console ตัวอย่างเช่น สำหรับ us-east-2
สามารถพบได้ที่ https://us-east-2.console.aws.amazon.com/lambda/home
หากยังไม่ได้เลือก ให้ไปที่ส่วน "ฟังก์ชัน":
ที่นี่ เราจะสร้างฟังก์ชันตั้งแต่เริ่มต้นโดยคลิก "สร้างฟังก์ชัน" ให้มันเป็นชื่ออธิบาย เราจะใช้ Node.js เป็นภาษารันไทม์ จากนั้นคลิก "สร้างฟังก์ชัน" ถัดไปเพื่อสิ้นสุดการทำงาน
มันจะเปลี่ยนเส้นทางเราไปยังหน้าของฟังก์ชันใหม่ ซึ่งเราสามารถเขียนโค้ดของเราใน index.js
ลองใช้ฟังก์ชันแลมบ์ดาแรกของเรา เนื่องจากเราไม่มีการพึ่งพาบุคคลที่สาม เราจึงต้องใช้โมดูลหลักของ Node.js (หากคุณต้องการเปิดใช้งานการพึ่งพาบุคคลที่สามแทน โปรดทำตามคำแนะนำนี้จาก AWS)
ตรวจสอบให้แน่ใจว่าชื่อวิธีการส่งออก ( handler
ในกรณีนี้) ตรงกับพารามิเตอร์ “ตัวจัดการ” ในหน้า:
ส่วนที่เหลือเป็นคำขอ GET
ง่ายๆ สำหรับแบ็คเอนด์ของคุณ:
const https = require('https'); exports.handler = async (event) => { return new Promise((resolve, reject) => { https.get(process.env.HEROKU_APP_URL, (resp) => { let data = ''; resp.on('data', (chunk) => { data += chunk; }); resp.on('end', () => { resolve(JSON.parse(data)); }); }).on("error", (err) => { reject("Error: " + err.message); }); }); };
ตรวจสอบให้แน่ใจว่าคุณได้ตั้งค่าตัวแปรสภาพแวดล้อม HEROKU_APP_URL
ในเพจ และบันทึกการกำหนดค่าของคุณ:
ขั้นตอนสุดท้ายคือการเพิ่มกฎทริกเกอร์ CloudWatch เพื่อเรียกใช้ฟังก์ชันนี้สิบนาทีก่อนการอัปเดตรายวันแต่ละครั้ง ในซีรีส์บทความนี้ ซึ่งใช้งานได้จนถึง 23:50 น.:
ประเภทกฎทริกเกอร์ CloudWatch ของเราจะเป็น “นิพจน์กำหนดการ” และตามรูปแบบที่ยอมรับ นิพจน์ cron ของเราจะเป็น cron(50 23 * * ? *)
ตอนนี้เราได้กำหนดค่าฟังก์ชัน AWS Lambda ให้ทริกเกอร์โดยกฎ CloudWatch ของเราแล้ว
ขับเคลื่อนหน้าเว็บแบบสแตติกของเรา: Gatsby/React และ Netlify
ด้วยการเพิ่ม AWS Lambda/CloudWatch ลงใน Node.js/MongoDB/Heroku แบ็กเอนด์ และ Gatsby และ Netlify สร้างและโฮสต์ส่วนหน้า แอปของเราจึงสมบูรณ์!
ฉันแชร์ลิงก์การสาธิตสดก่อนหน้านี้ แต่อย่าลังเลที่จะตรวจสอบเวอร์ชันที่ได้รับการปรับปรุงของต้นแบบของฉัน ซึ่งมีการเปลี่ยนแปลงเพิ่มเติมบางอย่างที่ฉันรู้ว่าคุณจะชอบ
คุณสามารถใช้สิ่งนี้เป็นพิมพ์เขียวสำหรับโครงการที่คล้ายคลึงกัน ฉันหวังว่าบทความเหล่านี้จะช่วยให้คุณสร้างต้นแบบแอปของคุณได้อย่างรวดเร็วและคุ้มค่ายิ่งขึ้น ขอบคุณที่อ่าน!