1.4 最小可用:先跑一个 Hello World

前三节都在做决策,这节开始动手。目标极其克制:用三个步骤把一个静态页面挂到公网上,拿到一个带 HTTPS 的可访问网址。不学架构、不配 CI、不写框架代码——那些是后面几篇的事。这节的哲学是,花二十分钟建立起“我发的东西真的有人能打开”的手感,后面的所有学习都有反馈支撑。

我见过反着的做法:有人花两周读完部署文档、画了三版架构图、对比了五种方案,网站仍然只存在于本地 localhost。先跑通一个粗糙但闭环的流程,再逐环替换成精细方案;一上来就要全盘精细化,往往永远启动不了。这也解释了为什么全书把最小可用放在第一章:它是后面所有章节的锚点,后面每学一个新东西,你都能立刻回到线上验证它是否真的有用。

会用到腾讯云网站托管 CloudPages,但流程对其他静态托管平台也大致通用。假设你本地已经装好了 Node 20 以上版本,命令用 Windows 的 PowerShell 和 Mac 的终端都能跑。

1.4.1 第一步:写一个真正的页面

新建目录,写两个文件。先是一个最简单的页面 index.html:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>创业页最小版</title>
</head>
<body>
  <h1>你好,这是我们的创业页</h1>
  <p>先上线,再完美。</p>
</body>
</html>

再写一个 package.json,让这个目录成为一个正式的 Node 项目:

{
  "name": "hello-cloud",
  "version": "0.0.1",
  "private": true,
  "type": "module"
}

注意 private 防止误发布,type 为 module 让后面写构建脚本时 import 写法不分裂。两个文件搞定,这就是全部“源码”。全程不需要 Vue,不需要 Vite——最小可用的意义在于把变量降到零,然后一次只引入一个新东西。所以这一节你只验证一件事:从本地到公网的这条路通不通。路通了,后面加什么都是工程问题;路不通,学再多框架也是空中楼阁。

1.4.2 第二步:本地构建与目录约定

真实项目不会只有一个 html,但部署入口永远是“一个目录”。所以从第一天起就养成这个约定:源码与产物分离,部署只认产物目录。这个约定在 2.1 仓库搭建 会展开成完整的目录规范,这里先建雏形:

hello-cloud/
├─ src/            # 源码
│  └─ index.html
├─ dist/           # 构建产物(部署它)
└─ package.json

加一条最短的构建脚本,把 src 拷贝到 dist:

{
  "scripts": {
    "build": "node scripts/copy.js"
  }
}

scripts/copy.js 只有三行,用 Node 内置模块,不装任何依赖:

import { cpSync, rmSync } from "node:fs";

rmSync("dist", { recursive: true, force: true });
cpSync("src", "dist", { recursive: true });
console.log("构建完成,产物在 dist/");

npm run build 跑一下,dist 出现。这一步看似朴素,含义是:从现在起,部署内容由脚本生成,而不是手动复制。 后面所有自动化(CI、预览、回滚)都建立在这个约定上。

1.4.3 第三步:传到托管平台拿网址

在控制台开好环境后,记录下环境 ID,在项目根目录建一个部署脚本,用平台 CLI 一行完成上传:

# 安装平台 CLI(一次性)
npm install -g @cloudbase/cli

# 登录并部署
tcb login
tcb hosting deploy ./dist -e your-env-id

执行完,控制台会给你一个默认域名,形如 your-env-id.tcloudbaseapp.com 之类的平台域名,浏览器打开就能看到页面,自带 HTTPS。整个链路是:dist 里的文件→平台的存储(COS)→CDN 边缘节点→用户。

第一次看到自己的页面通过 https 打开,而且手机上也能访问,这个正反馈会推着你继续。此时如果想用自己的域名,解析与证书的完整步骤在 3.2 域名与解析 和 3.3 SSL 证书,本节先不做。

部署成功的判断别只靠控制台的提示,我们习惯再看一眼文件列表的大小是否符合预期:如果整个 dist 只有几百字节,多半传错了目录或构建脚本拷贝了个寂寞。

1.4.4 三个动作验证真的上线了

命令跑完≠上线成功,养成三个验证动作:

验证项 方法 期望现象
文件到位 平台控制台文件管理 dist 里的文件都在
HTTPS 生效 浏览器看地址栏小锁 无证书警告
缓存新鲜度 改标题重新部署再刷新 看到新标题(或看到旧的就是缓存)

第三个是新手最容易卡住的:改了内容重新上传,刷新页面还是旧的。这不是 bug,是 CDN 缓存。验证时可以打开浏览器开发者工具看 Network 里该资源的状态码,200 是命中缓存、缓存策略相关内容在 4.1 CDN 接入 会系统讲。这节只要知道:缓存是特性不是 bug,看见旧页面先查缓存再怀疑自己。

补充一个新手常问的问题:本地预览和线上长得不一样怎么办?九成原因是本地直接打开 file 协议的 html,路径解析与 http 服务不同。解决办法很朴素:本地起一个静态服务器再看,Node 一行就能起:

npx serve dist

或者干脆把 1.4.2 的脚本升级成本地 dev 服务器,凡是要对照线上效果,一律走 http 而不是 file。这个习惯能帮你把一类“玄学白屏”直接从调试流程里消灭。

1.4.5 我第一次跑这流程时出过的四个错

错一:直接部署 src 而不是 dist。那时还没有产物目录的概念,传了整个项目文件夹,结果平台把 .DS_Store 和编辑器配置都传了上去,线上多出一堆奇怪文件。明确“部署入口只有一个目录”后,这类问题自动消失。

错二:构建脚本用绝对路径。同事在他电脑上跑 build,脚本里写死了我的用户名路径,直接报错。所以上面的脚本里全用相对路径,团队任何人 clone 下来都能跑——这个细节在 2.2 构建脚本 会展开成可移植脚本清单。

错三:改完 html 不重新 build 就部署。dist 是脚本的输出,手动改 dist 里的文件,下次 build 又会被覆盖。把 dist 当成不可手工干预的产物,所有改动只发生在 src。

错四:环境 ID 写进代码又写进命令行。我有次部署随手在命令里敲了测试环境 ID,于是生产环境一上午没更新。后来环境 ID 统一走环境变量,命令脚本只读变量,杜绝手敲。这个习惯在 3.4 常见构建失败与排查 会归到“Config 外置”一类的纪律里。

1.4.6 现在该往哪走

跑通这三步之后,你已经有了一个可发布的最小闭环:写页面→跑构建→一条命令上线。接下来就是把这个闭环逐步加固:

每一步都不大,每个闭环都有可验证的结果,这就是我把最小可用放在第一章的原因:先让东西在线上,再谈优化。

小结

三步上线最小静态页:写两个文件、加一条拷贝脚本约定源码产物分离、一行 CLI 把 dist 推到平台。学会用三个验证动作确认真的上线,记住缓存是特性。跑完这一节,你已经从读文档的人变成上线过东西的人,第二篇我们开始把这个最小项目变成正规仓库。

延伸阅读