这篇文章的目的是向您展示如何以每月 1 美元以下的价格创建自己的静态个人网站。我知道,您可能在想:“我刚才读对了吗?”。你做到了!当然,要达到该目标有一些注意事项,但在您的网站之旅的开始阶段,托管您自己的静态网站实际上每月只需花费 0.01 美元。这篇文章的目标受众是具有一定 JavaScript 经验并对 Web 开发有一般了解的任何人。如果您没有这样的背景,请不要担心!我将尽力解释这篇文章中的想法和概念,以便任何人都可以理解!
在开始之前,让我们先了解一些定义,以帮助我们理解创建第一个网站时将使用的不同术语。在我们将网站添加到 Google Cloud 的过程中,请随意参考这些定义:
本文假设读者具有一些网站开发和编程的基础知识。我假设每个读者都有以下几点:
我倾向于通过将目标分解为渐进的工作块来更好地思考。让我们在创建网站时以这种方式构建我们的任务:
如果您想创建自己的个人网站,则需要一个域名才能开始。尽管我们最初不会使用它,但现在值得这样做,以便我们可以在后面的文章中使用自定义域。对我来说,我的域名是afro-cloud.com ,但只要注册提供商拥有可用的域名,您就可以选择任何想到的域名。您可以使用许多域名注册提供商,我个人使用的是 GoDaddy,但以下是可用选项的子集(我不隶属于任何这些服务):
现在我们已经设置了域,接下来创建一个 Google Cloud 帐户并启用结算。
伟大的!现在启用结算功能后,我们就可以开始使用 Google Cloud 服务了。现在我们已经完成了此选项卡的设置,但我们将在本文后面回到此页面,因此请将其放在方便的地方。
如果您在执行本文中的步骤时遇到问题,请与我们联系,我将尽力帮助调试问题。好吧,弄清楚了之后我们就可以继续了。我们将使用 Next.js,而不是其他 React.js 框架(或只是 React),因为它们支持静态导出。有许多不同的部署选项可用于托管 React.js 应用程序,但由于 SEO 优势和成本节省,我选择分享 Google Cloud Storage 和 Next.js 方法。通过 Next.js 静态导出,当进行生产构建时,会为每个路由创建一个 HTML 文件,以及与不同块中的 HTML 文件相对应的静态资源(CSS 和 JS 文件)。这很重要,因为它可以避免为正在查看的页面加载不必要的 JavaScript 包,这意味着页面加载速度更快。运行“next build”生成的所有文件都将导出到“out”文件夹中。但稍后会详细介绍这一点。让我们创建应用程序。
首先,让我们在我们的机器上安装一个 Starter Next.js 项目。幸运的是,Next.js 有一个“create-next-app”实用程序,就像使用过 Create React App 的人一样。要启动工作流程,我们可以运行以下命令:
npx create-next-app@latest
该命令将引导我们完成项目的一些配置选项(随意选择您喜欢的任何选项;我们只需要代码生成)。我已将本文中使用的选项加粗:
很好,我们现在有了一些代码!您会注意到我们的 node_modules 文件夹已填充,因此我们安装了运行应用程序所需的所有依赖项。在用于创建项目的同一终端窗口中,让我们运行以下命令: npm run dev 。这将启动 Next.js 开发工作流程,以便我们可以在本地查看我们的应用程序。 Next.js 将提供一个 URL 以在您的计算机上查看该项目。在大多数情况下,这将是http://localhost:3000 ,但如果您有另一个 Web 应用程序正在运行,它可能会选择另一个端口,例如 3001。单击该链接后,您应该会看到类似以下内容的内容:
好的!我们已经启动并运行了一个入门应用程序!但是让我们摆脱起始页来执行更经典的“Hello World”示例。更新 src/app/page.tsx(或 page.jsx)文件以包含以下内容:
import styles from "./page.module.css"; export default function Home() { return ( <main className={styles.main}> <div className={styles.description}> <p>Hello world!</p> </div> </main> ); }
保存文件并返回到运行应用程序的浏览器选项卡并重新加载页面。您应该在屏幕上看到“Hello world”!现在让我们回到让静态导出发挥作用。我们需要配置 next.config 文件来启用该功能。将 nextConfig 声明更新为:
const nextConfig = { output: "export", };
这将指示 Next.js 在构建过程中创建与应用程序中的每个路由相对应的单独 HTML 文件。我们暂时只有一页,所以让我们添加另一页来说明静态导出的好处。在 app/ 目录中,创建一个名为“test”的新目录。在新创建的目录中添加 page.tsx(或 page.jsx)文件并添加以下代码:
export default function Test() { return ( <main> <p>Hello test!</p> </main> ); }
现在我们有了一个测试页面,让我们从主页添加一个指向它的链接。打开 src/app/page.tsx (或 page.jsx)并更新文件,使其看起来像:
import Link from "next/link"; import styles from "./page.module.css"; export default function Home() { return ( <main className={styles.main}> <div className={styles.description}> <p>Hello world!</p> <Link href="/test">Test Page!</Link> </div> </main> ); }
保存新更新的文件并返回到运行我们的应用程序的浏览器选项卡并重新加载页面。您应该会看到一个带有“测试页!”的新链接。单击该链接后,屏幕上的内容应更改为显示“Hello test!”。干得好,现在我们的应用程序中有两条路线。现在让我们检查一下我们一直在讨论的静态导出功能的输出。返回终端窗口运行“npm run build”。该命令将运行“下一个构建”命令,该命令将为我们的工作创建一个生产就绪的构建,并将结果存储在项目根目录中调用的目录中。如果我们检查 out 目录,我们应该看到如下内容:
干得好,伙计们。现在让我们将代码上传到 Google Cloud,以便我们可以实时查看该网站。
现在我们已经准备好了代码,我们需要将其上传到 Google Cloud Storage,以便 Google Cloud 可以在互联网上为我们的网站提供服务。让我们回到 Google Cloud 选项卡。
打开屏幕左侧的汉堡菜单,然后选择“云存储”。在屏幕顶部,您应该会看到一个“创建”按钮。我们将单击将启动创建工作流程的按钮。由于我们还不会使用自定义域,因此请将存储桶命名为您想要的任何名称,但请注意唯一性限制。对我来说,我将使用“somerandombucket123”。接下来,我们将在美国使用多区域选项(这就是我撰写这篇文章的地方),但请随意根据您的用例进行调整。然后,我们将选择应为您预先填充的标准默认类别选项。下一个选项与我们是否希望通过互联网公开访问我们的存储桶有关。在这种情况下,由于我们希望将这些文件提供给查看者,因此我们需要取消选中“在此存储桶上实施公共访问阻止”,以便所有文件都可以通过互联网访问。我们将选择“统一”访问控制,而不选择“数据保护”产品,以保持较低的成本。然后我们将点击“创建”按钮。
现在我们已经创建了存储桶,我们需要添加新权限,以便用户可以查看我们的存储桶文件。选择“权限”选项卡,然后单击“授予访问权限”按钮。在“新主体”中输入“allUsers”,然后选择“云存储”下的“环境和存储对象查看器”角色。
将打开一个对话框,询问我们是否要公开我们的存储桶(我们确实这么做了),因此选择“允许公共访问”。因此选择“允许公共访问”。现在,该存储桶的文件将可供公开访问。单击存储桶详细信息页面中的后退箭头,返回概述页面。您应该会看到新创建的存储桶以及我们使用的配置选项。接下来,我们需要指示我们网站的存储桶,我们可以通过单击新创建的存储桶行的三个点来完成此操作。选择“编辑网站配置”,您应该看到如下内容:
对于索引页面输入,输入“index.html”,对于错误页面输入,输入“404.html”。您会注意到这些文件与我们的 Next.js 应用程序的构建输出相匹配,这正是我们想要的并将很快使用的。单击“保存”完成更改。
现在我们需要将代码的 out 目录中包含的文件上传到此存储桶中,以便我们的网站可以上线!我们可以通过导航到存储桶的存储桶详细信息页面并单独选择每个文件或文件夹来手动执行此操作。但是,让我们以编程方式处理它并编写一些代码来执行此操作。返回 IDE 或任何要更新代码的位置,让我们在项目的根目录下创建一个名为 upload.sh 的新文件。添加以下内容:
#!/bin/bash # ADD YOUR BUCKETNAME HERE (no quotes necessary) # For example: # BUCKETNAME=somerandombucket123 BUCKETNAME=somerandombucket123 echo "Removing out folder..." sleep 1; rm -rf out echo "Creating production build..." sleep 1; npm run build echo "Uploading assets to the cloud..." sleep 1; gsutil cp out/404.html gs://$BUCKETNAME gsutil cp out/favicon.ico gs://$BUCKETNAME gsutil cp out/index.html gs://$BUCKETNAME gsutil cp out/index.txt gs://$BUCKETNAME gsutil cp out/test.html gs://$BUCKETNAME gsutil cp out/test.txt gs://$BUCKETNAME gsutil cp -r out/_next gs://$BUCKETNAME
请务必将“somerandombucket123”替换为您的存储桶名称。这里不用太担心代码的语义。本质上我们正在做的是:
在运行此脚本之前,我们必须下载 Google Cloud CLI。您可以按照此处的说明进行操作。安装后,您需要在终端中运行: gcloud auth login 。这将授权我们使用 Google Cloud CLI。更多说明和背景可以在他们的文档中找到。成功授权后,让我们将新的运行脚本添加到 package.json 中。在“scripts”对象中添加一个新的脚本条目来注册我们的上传脚本:
"upload": "sh upload.sh"
接下来我们来测试一下。再次打开终端并运行:“npm run upload”。这将执行我们的脚本,您应该会看到一些有关存储桶上传的输出。如果我们导航回 Google Cloud Storage 页面并打开您的存储桶,您应该会看到我们刚刚上传的文件。如果您导航至: https://storage.googleapis.com/YOUR_BUCKET_NAME/index.html (其中 YOUR_BUCKET_NAME 是您的存储桶的名称),您应该会看到该网站。但您会注意到默认的 Next.js 样式已消失,并且指向我们测试页面的链接已损坏。有什么想法吗?
如果您打开浏览器控制台,您应该会看到很多资源未找到错误。换句话说,浏览器无法找到指示为您的网站加载的文件。如果仔细观察,您会发现资源的 URL 不太正确,路径中缺少我们的存储桶名称。如果我们使用自定义域并正确配置 DNS,就不会遇到此问题。但出于本文的目的,我们添加一些额外的代码来修复路由。打开 src/app/page.tsx (或 page.jsx)并更新文件,使其看起来像:
import Link from "next/link"; import styles from "./page.module.css"; // Replace below with your bucketname. const BUCKET_NAME = "somerandombucket123"; const isProd = process.env.NODE_ENV === "production"; export default function Home() { return ( <main className={styles.main}> <div className={styles.description}> <p>Hello world!</p> <Link href={isProd ? '/BUCKET_NAME/test.html' : "/test"}> Test Page! </Link> </div> </main> ); }
请务必将“somerandombucket123”替换为您的存储桶名称。接下来更新 next.config 文件,如下所示:
// Replace below with your bucketname. const BUCKET_NAME = "somerandombucket123"; const isProd = process.env.NODE_ENV === "production"; /** @type {import('next').NextConfig} */ const nextConfig = { assetPrefix: isProd ? 'https://storage.googleapis.com/BUCKET_NAME/' : undefined, output: "export", }; export default nextConfig;
同样,请务必将“somerandombucket123”替换为您的存储桶名称。您会在上面的代码片段中注意到,当节点环境变量为生产环境(由 Next.js 设置)时,我们添加了额外的逻辑来说明存储桶名称。我们添加资产前缀来修复配置文件中的资源未找到错误,并通过在路由前加上我们的存储桶名称来解决主页中的路由错误。现在让我们上传代码并看看它是否有效。再次开始:npm run upload。跳回您的网站并重新加载页面。我们做得怎么样?该网站应该反映我们现在在本地拥有的内容。在流程开始时,如果我们要创建存储桶来匹配我们的域名,我们将会遇到资源错误,但仍然会遇到客户端路由问题。不幸的是,这种方法的一个缺点是需要额外的代码来将 .html 后缀添加到生产服务的路由中。
稍后,我将介绍向存储桶添加服务自定义域所需的 DNS 记录和配置更改,以及为我们的网站配置 SSL。希望您今天学到了一些东西,将来我将围绕以下内容讨论一些想法:
感谢您的阅读和欢呼!