前端:使用 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 格式存储,因此我们需要一个转换器。

静态网站项目结构

我们的文件/文件夹结构如下:

一个标准的前端项目根目录,其中包含一个空的公共文件夹和一个用于存放 package.json 等文件的 src 文件夹。在 src 文件夹下面是 global.css 的 styles 子文件夹和 all-repositories.js 和 repository.js 的 templates 子文件夹。

这些文件是干什么用的? 让我们来看看:

  • env.developmentenv.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.developmentenv.production文件只有对应环境的后端 URL。 前者有:

 API_URL=http://localhost:3000

…而生产有:

 API_URL=https://[YOUR_UNIQUE_APP_NAME].herokuapp.com

gatsby-node.js只会在您构建代码时运行一次。 所以我们必须在这里从后端收集所有必要的信息。 然后,响应将与我们的模板一起使用以生成适当的静态页面。

在我们的例子中, all-repositories.js需要所有存储库, repository.js需要每次迭代对应的存储库。 最后,我们可以动态生成页面路径,将存储库ownername参数作为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.jsrepository.js ,如果我们省略样式,我们只是从pageContext收集数据并像在 React 中使用参数一样使用它。

all-repositories.js中,我们将使用pageContextrepositories字段,如下所示:

 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 ,我们将使用pageContextrepository字段:

 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 功能,您应该会看到如下内容:

我们应用程序的存储库列表主页,显示了 GitHub 存储库示例的基本信息

单击其中一个存储库后,您应该会看到如下内容:

示例存储库详细信息页面,显示有关 facebook/react GitHub 存储库的更多信息

经过上面的修改,我们的前端实现就完成了。

伟大的! 现在我们只需要部署。

部署前端

在这部分我们不需要对我们的前端应用程序进行任何更改。 我们将简单地将其部署到 Netlify — 您需要一个帐户。

但首先,我们必须将代码部署到 GitHub、GitLab 或 Bitbucket。 与后端一样,我将代码部署到 GitHub。

然后,登录 Netlify 并单击仪表板上的“从 Git 新建站点”按钮。 按照屏幕上的步骤选择您的 Git 提供程序并找到您的存储库。

最后一步,如果你的代码结构正确,Netlify 将自动正确设置构建命令和发布目录,如下所示:

Netlify构建选项的正确设置:部署master,使用“gatsby build”作为构建命令,发布到“public/”目录。

然后单击“部署站点”。 它会将您的站点部署到随机生成的 Netlify 子域,但您可以随时更改它——我将部署更改为 https://sample-create-page-api-gatsby.netlify.com,您可以在其中找到现场演示完成的应用程序。

到目前为止,一切都很好。 但是因为它是一个静态页面应用程序,所以我们必须每天重新构建它以使其保持最新状态。

使用 Build Hook 进行每日更新

Netlify 中的构建钩子用作构建触发器,因此您可以在 cron 作业完成后从后端触发它们。 为此,首先在 Netlify 中创建一个构建挂钩。

在“构建和部署→持续部署”部分下,您可以找到“构建挂钩”。 单击“添加构建挂钩”。

在哪里可以找到 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 找到它。

如果尚未选择,请转到“功能”部分:

AWS Lambda“函数”部分

在这里,我们将通过单击“创建函数”从头开始创建函数。 让我们给它一个解释性的名字。 我们将使用 Node.js 作为运行时语言。 然后单击下一个“创建函数”以完成它。

AWS Lambda 的“创建函数”页面,在创建 triggerMyBackendAtUTCMidnight 时使用 Node.js 运行时和具有基本 Lambda 权限的新角色填写

它会将我们重定向到新函数的页面,我们可以在index.js中编写代码。

让我们实现我们的第一个 lambda 函数。 因为我们没有任何第三方依赖,所以我们必须使用 Node.js 的核心模块。 (如果您想启用第三方依赖项,请遵循 AWS 的本指南。)

确保导出的方法名称(在本例中为handler )与页面中的“Handler”参数匹配:

以“index.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环境变量,并保存您的配置:

在 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 咨询合作伙伴。