前端:使用 Gatsby.js 和 Node.js 進行靜態站點更新
已發表: 2022-03-11對於某些項目需求,靜態頁面生成不僅足夠,而且在速度和可擴展性方面也是最有效的。
在本系列的前半部分,我們結合了 Node.js、Express、MongoDB、cron 和 Heroku,以提供一個 CI 就緒的後端,該後端根據每日計劃使用 GitHub 的 API。 現在我們準備好將 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
是我們的主要樣式表文件。
蓋茨比網站實施
與我們的後端一樣,在將所需的依賴項添加到前端的package.json
後,運行npm install
(或yarn
,如果您安裝了 Yarn):
{ // ... "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
中,我們將使用pageContext
的repositories
字段,如下所示:
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
,我們將使用pageContext
的repository
字段:
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
並打開 http://localhost:8000。
如果您確實向後端添加了一些存儲庫(所有者/名稱)並至少運行一次 update-via-GitHub-API 功能,您應該會看到如下內容:
單擊其中一個存儲庫後,您應該會看到如下內容:
經過上面的修改,我們的前端實現就完成了。
偉大的! 現在我們只需要部署。
部署前端
在這部分我們不需要對我們的前端應用程序進行任何更改。 我們將簡單地將其部署到 Netlify — 您需要一個帳戶。

但首先,我們必須將代碼部署到 GitHub、GitLab 或 Bitbucket。 與後端一樣,我將代碼部署到 GitHub。
然後,登錄 Netlify 並單擊儀表板上的“從 Git 新建站點”按鈕。 按照屏幕上的步驟選擇您的 Git 提供程序並找到您的存儲庫。
最後一步,如果你的代碼結構正確,Netlify 將自動正確設置構建命令和發布目錄,如下所示:
然後單擊“部署站點”。 它會將您的站點部署到隨機生成的 Netlify 子域,但您可以隨時更改它——我將部署更改為 https://sample-create-page-api-gatsby.netlify.com,您可以在其中找到現場演示完成的應用程序。
到目前為止,一切都很好。 但是因為它是一個靜態頁面應用程序,所以我們必須每天重新構建它以使其保持最新狀態。
使用 Build Hook 進行每日更新
Netlify 中的構建鉤子用作構建觸發器,因此您可以在 cron 作業完成後從後端觸發它們。 為此,首先在 Netlify 中創建一個構建掛鉤。
在“構建和部署→持續部署”部分下,您可以找到“構建掛鉤”。 單擊“添加構建掛鉤”。
給它一個名字並保存它。 (我叫我build-from-backend
。)然後復制它生成的鏈接。
現在讓我們打開我們的後端項目並將這幾行添加到cron.controller.js
文件中。 我們只是向 Netlify 的 build-hook URL 發送一個POST
請求。
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 複製的NETLIFY_BUILD_HOOK
環境變量。 在 Heroku 中,您可以從應用程序的“設置”部分設置環境變量。
推送您的提交後,後端應用程序將向 Netlify 發送構建請求,並且您的頁面將在您的 cron 作業結束時每天更新。 這是添加構建鉤子功能後存儲庫的外觀,以及後端存儲庫和前端存儲庫的最終版本。
作為該項目的最後潤色,我們將展示如何使用由 AWS CloudWatch 觸發的 AWS Lambda 函數,該函數將在每次每日更新時及時喚醒您的後端。
AWS Lambda 和 AWS CloudWatch 簡單請求
AWS Lambda 是一個無服務器計算平台。 為了我們的目的,我們只需要這個平台的基礎知識。 您需要一個 AWS 賬戶。
首先,使用您的賬戶登錄 AWS 並找到 Lambda 管理控制台。 例如,對於us-east-2
,可以在 https://us-east-2.console.aws.amazon.com/lambda/home 找到它。
如果尚未選擇,請轉到“功能”部分:
在這裡,我們將通過單擊“創建函數”從頭開始創建函數。 讓我們給它一個解釋性的名字。 我們將使用 Node.js 作為運行時語言。 然後單擊下一個“創建函數”以完成它。
它會將我們重定向到新函數的頁面,我們可以在index.js
中編寫代碼。
讓我們實現我們的第一個 lambda 函數。 因為我們沒有任何第三方依賴,所以我們必須使用 Node.js 的核心模塊。 (如果您想啟用第三方依賴項,請遵循 AWS 的本指南。)
確保導出的方法名稱(在本例中為handler
)與頁面中的“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 生成並託管我們的前端,我們的應用程序就完成了!
我之前分享了一個現場演示鏈接,但也可以隨意查看我的原型的增強版本——它有一些額外的變化,我知道你會喜歡的。
您可以將其用作類似項目的藍圖——我希望這些文章能幫助您以更快、更具成本效益的方式構建您的應用程序原型。 謝謝閱讀!