ส่วนหน้า: การใช้ 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 ดังนั้นเราจึงจำเป็นต้องมีตัวแปลง

โครงสร้างโครงการเว็บไซต์แบบคงที่

โครงสร้างไฟล์/โฟลเดอร์ของเราจะเป็นดังนี้:

รูทโปรเจ็กต์ส่วนหน้ามาตรฐานที่มีโฟลเดอร์สาธารณะว่างและโฟลเดอร์ src สำหรับไฟล์ เช่น package.json ใต้โฟลเดอร์ src เป็นโฟลเดอร์ย่อยของสไตล์สำหรับ global.css และโฟลเดอร์ย่อยเทมเพลตสำหรับ all-repositories.js และ repository.js

ไฟล์เหล่านี้มีไว้เพื่ออะไร? มาดูกัน:

  • 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 อย่างน้อยหนึ่งครั้ง คุณควรเห็นสิ่งนี้:

ที่เก็บที่แสดงโฮมเพจของแอพของเรา แสดงข้อมูลพื้นฐานสำหรับตัวอย่างของ GitHub repos

และหลังจากคลิกหนึ่งในที่เก็บ คุณควรเห็นสิ่งนี้:

หน้ารายละเอียดที่เก็บตัวอย่าง แสดงข้อมูลเพิ่มเติมเกี่ยวกับ facebook/react GitHub repo

หลังจากการเปลี่ยนแปลงข้างต้น การใช้งานส่วนหน้าของเราเสร็จสิ้น

ยอดเยี่ยม! ตอนนี้เราแค่ต้องปรับใช้

การปรับใช้ส่วนหน้า

เราไม่จำเป็นต้องทำการเปลี่ยนแปลงใดๆ ในแอปพลิเคชันส่วนหน้าในส่วนนี้ เราจะปรับใช้กับ Netlify ได้ง่ายๆ โดยคุณจะต้องมีบัญชีอยู่ที่นั่น

แต่ก่อนอื่น เราต้องปรับใช้โค้ดของเรากับ GitHub, GitLab หรือ Bitbucket ในส่วนแบ็คเอนด์ ฉันปรับใช้โค้ดของฉันกับ GitHub

จากนั้นเข้าสู่ระบบ Netlify และคลิกปุ่ม "ไซต์ใหม่จาก Git" บนแดชบอร์ดของคุณ ทำตามขั้นตอนบนหน้าจอเพื่อเลือกผู้ให้บริการ Git และค้นหาที่เก็บของคุณ

สำหรับขั้นตอนสุดท้าย หากคุณจัดโครงสร้างโค้ดของคุณอย่างถูกต้อง Netlify จะตั้งค่าคำสั่ง build และเผยแพร่ไดเร็กทอรีอย่างถูกต้องโดยอัตโนมัติดังนี้:

การตั้งค่าที่ถูกต้องสำหรับตัวเลือกบิลด์ของ Netlify: ปรับใช้ต้นแบบ ใช้ "gatsby build" เป็นคำสั่งบิลด์ และเผยแพร่ไปยังไดเร็กทอรี "public/"

จากนั้นคลิก "ปรับใช้ไซต์" มันจะปรับใช้ไซต์ของคุณกับโดเมนย่อย Netlify ที่สร้างแบบสุ่ม แต่คุณสามารถเปลี่ยนได้ตลอดเวลา—ฉันเปลี่ยนการทำให้ใช้งานได้เป็น https://sample-create-page-api-gatsby.netlify.com ซึ่งคุณจะพบการสาธิตสด ของแอปที่เสร็จสมบูรณ์

จนถึงตอนนี้ดีมาก แต่เนื่องจากเป็นแอปพลิเคชันเพจแบบสแตติก เราจึงต้องสร้างใหม่ทุกวันเพื่อให้อัปเดตอยู่เสมอ

อัพเดททุกวันโดยใช้ Build Hook

Build hooks ใน Netlify ทำงานเป็นตัวกระตุ้นบิลด์ ดังนั้นคุณจึงสามารถทริกเกอร์พวกมันจากส่วนหลังของคุณหลังจากที่งาน cron เสร็จสิ้น ขั้นแรกให้สร้าง build hook ใน Netlify

ในส่วน "สร้างและปรับใช้ → การปรับใช้อย่างต่อเนื่อง" คุณจะพบ "สร้าง hooks" คลิก "เพิ่มเบ็ดบิลด์"

จะหา build hook ใน Netlify ได้ที่ไหน

ตั้งชื่อและบันทึก (ฉันเรียกว่า 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

หากยังไม่ได้เลือก ให้ไปที่ส่วน "ฟังก์ชัน":

ส่วน "ฟังก์ชัน" ของ AWS Lambda

ที่นี่ เราจะสร้างฟังก์ชันตั้งแต่เริ่มต้นโดยคลิก "สร้างฟังก์ชัน" ให้มันเป็นชื่ออธิบาย เราจะใช้ Node.js เป็นภาษารันไทม์ จากนั้นคลิก "สร้างฟังก์ชัน" ถัดไปเพื่อสิ้นสุดการทำงาน

หน้า "สร้างฟังก์ชัน" ของ AWS Lambda กรอกที่ create triggerMyBackendAtUTCMidnight พร้อมรันไทม์ Node.js และบทบาทใหม่พร้อมสิทธิ์พื้นฐานของ Lambda

มันจะเปลี่ยนเส้นทางเราไปยังหน้าของฟังก์ชันใหม่ ซึ่งเราสามารถเขียนโค้ดของเราใน index.js

ลองใช้ฟังก์ชันแลมบ์ดาแรกของเรา เนื่องจากเราไม่มีการพึ่งพาบุคคลที่สาม เราจึงต้องใช้โมดูลหลักของ Node.js (หากคุณต้องการเปิดใช้งานการพึ่งพาบุคคลที่สามแทน โปรดทำตามคำแนะนำนี้จาก AWS)

ตรวจสอบให้แน่ใจว่าชื่อวิธีการส่งออก ( handler ในกรณีนี้) ตรงกับพารามิเตอร์ “ตัวจัดการ” ในหน้า:

พารามิเตอร์ตัวจัดการที่มี "index.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 ในเพจ และบันทึกการกำหนดค่าของคุณ:

การตั้งค่าตัวแปรสภาพแวดล้อมที่จำเป็นใน AWS Lambda ค่าที่แสดงคือ https://sample-github-api-consumer-nod.herokuapp.com/repositories

ขั้นตอนสุดท้ายคือการเพิ่มกฎทริกเกอร์ CloudWatch เพื่อเรียกใช้ฟังก์ชันนี้สิบนาทีก่อนการอัปเดตรายวันแต่ละครั้ง ในซีรีส์บทความนี้ ซึ่งใช้งานได้จนถึง 23:50 น.:

การกำหนดค่า CloudWatch Events เพื่อเพิ่มกฎทริกเกอร์

ประเภทกฎทริกเกอร์ CloudWatch ของเราจะเป็น “นิพจน์กำหนดการ” และตามรูปแบบที่ยอมรับ นิพจน์ cron ของเราจะเป็น cron(50 23 * * ? *)

หน้า "กำหนดค่าทริกเกอร์" ของ AWS CloudWatch ตั้งค่าให้สร้างกฎใหม่ที่เรียกว่า cronDailyUpdate ด้วยนิพจน์ที่ระบุด้านบนและเปิดใช้งานทริกเกอร์

ตอนนี้เราได้กำหนดค่าฟังก์ชัน AWS Lambda ให้ทริกเกอร์โดยกฎ CloudWatch ของเราแล้ว

ขับเคลื่อนหน้าเว็บแบบสแตติกของเรา: Gatsby/React และ Netlify

ด้วยการเพิ่ม AWS Lambda/CloudWatch ลงใน Node.js/MongoDB/Heroku แบ็กเอนด์ และ Gatsby และ Netlify สร้างและโฮสต์ส่วนหน้า แอปของเราจึงสมบูรณ์!

ฉันแชร์ลิงก์การสาธิตสดก่อนหน้านี้ แต่อย่าลังเลที่จะตรวจสอบเวอร์ชันที่ได้รับการปรับปรุงของต้นแบบของฉัน ซึ่งมีการเปลี่ยนแปลงเพิ่มเติมบางอย่างที่ฉันรู้ว่าคุณจะชอบ

คุณสามารถใช้สิ่งนี้เป็นพิมพ์เขียวสำหรับโครงการที่คล้ายคลึงกัน ฉันหวังว่าบทความเหล่านี้จะช่วยให้คุณสร้างต้นแบบแอปของคุณได้อย่างรวดเร็วและคุ้มค่ายิ่งขึ้น ขอบคุณที่อ่าน!

Toptal เป็นคู่ค้าที่ปรึกษาของ AWS ขั้นสูง