尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

AngularJS code.angularjs.org 的 Firebase 部署架构:Cloud Functions 与 GCS 文件分发实战解析

发布时间:2026/9/18 23:18:03

资讯中心
01
ARTICLE

AngularJS code.angularjs.org 的 Firebase 部署架构:Cloud Functions 与 GCS 文件分发实战解析

AngularJS code.angularjs.org 的 Firebase 部署架构:Cloud Functions 与 GCS 文件分发实战解析
AngularJS code.angularjs.org 的 Firebase 部署架构Cloud Functions 与 GCS 文件分发实战解析【免费下载链接】angular.jsAngularJS - HTML enhanced for web apps!项目地址: https://gitcode.com/gh_mirrors/an/angular.js本文以 AngularJS 官方发布站点code.angularjs.org的 Firebase 部署方案为主题基于仓库 scripts/code.angularjs.org-firebase 目录下的配置与云函数源码深入讲解如何用 Firebase Hosting 重写规则、Cloud Functions 与 Google Cloud StorageGCS组合构建一个版本化、可自动索引目录的文件分发服务。读完本文你将掌握 firebase.json 重写规则的精确定义、sendStoredFile云函数的完整请求处理链路、snapshot 构建包自动清理触发器以及 CI 中整套自动部署的流水线设计。一、背景code.angularjs.org 承担什么职责code.angularjs.org是 AngularJS 官方发布文件的下载分发站点。社区用户通过类似https://code.angularjs.org/1.8.3/angular.min.js、https://code.angularjs.org/snapshot/angular.js这样的 URL 直接引用指定版本的框架文件、文档页面等资源。为了让这种“按版本号组织目录、按需直接下载文件”的站点可维护、可自动更新AngularJS 团队选择了 Firebase 生态作为承载平台Firebase Hosting承担域名入口与请求分发Cloud Functionsfunctions/index.js承担“把 GCS 存储桶中的文件流式送回浏览器”的核心逻辑GCS 存储桶project.appspot.com作为文件的真实存储介质支持按目录组织版本文件。整个目录在仓库中的结构如下firebase.json — Firebase Hosting 与 Storage 的配置重写规则、重定向、存储规则引用functions/index.js — 提供文件分发与目录索引的云函数以及快照 zip 清理触发器functions/package.json — 云函数运行时的 Node 版本与依赖声明storage.rules — GCS 桶的访问安全规则public/ — Firebase Hosting 的静态站点目录favicon、robots.txt、Google 站点验证文件。原文档 readme.firebase.code.md 提纲挈领地说明了这套结构的两个关键点一是firebase.json的重写规则把所有子目录请求都路由到functions/index.js中负责分发存储桶文件的云函数二是云函数中还内置了“新 zip 上传后删除 snapshot 目录中旧 zip”的清理规则。下文逐一展开。二、firebase.json重写规则如何把请求交给云函数firebase.json 是整套 Firebase 部署的“总开关”全文如下{ hosting: { public: public, trailingSlash: false, redirects: [ { source: /:version/docs, destination: /:version/docs/index.html, type: 301 } ], rewrites: [ { source: /**, function: sendStoredFile } ] }, storage: { rules: storage.rules } }各配置项的作用可以拆解如下配置项取值作用hosting.publicpublic指定 Firebase Hosting 的静态资源根目录即仓库内的 public/ 目录其中放置favicon.ico、robots.txt与 Google 站点验证文件googleb96cceae5888d79f.htmlhosting.trailingSlashfalse禁止 Hosting 层自动补充 URL 末尾斜杠保证原始请求路径原样进入重写逻辑便于云函数精确解析路径段hosting.redirects/:version/docs → /:version/docs/index.html301把形如/1.8.3/docs的文档目录请求永久重定向到/1.8.3/docs/index.html让文档入口 URL 始终指向可渲染的 HTML 文件hosting.rewrites/** → sendStoredFile核心重写规则除public中真实存在的静态文件外其余所有请求包括每一层子目录全部交给名为sendStoredFile的云函数处理storage.rulesstorage.rules声明 GCS 存储桶使用同目录下 storage.rules 作为访问安全规则值得注意的是重写规则使用/**而不是/这正是“每个子目录请求都会被路由”的原因——code.angularjs.org下的1.8.3/、snapshot/、snapshot-stable/等所有路径最终都会进入同一个云函数由函数内部自行区分文件与目录语义。这也印证了原文档中“route every subdirectory request to the cloud function”的描述。三、storage.rules存储桶的访问边界storage.rules 内容非常简短service firebase.storage { match /b/{bucket}/o { match /{allPaths**} { allow read, write: if request.auth!null; } } }其语义是对该项目默认 GCS 桶内所有对象{allPaths**}覆盖任意层级路径读写操作均要求请求方已通过 Firebase Authentication 认证request.auth ! null。也就是说公网用户并不能直接绕过 Hosting 直读桶对象正常的文件下载必须经由 Cloud Functions 校验路径后转发从而保证版本目录的路径规范与索引页逻辑始终在服务端掌控之中。四、sendStoredFile一次请求的完整处理链路云函数入口在 functions/index.js末尾通过exports.sendStoredFile functions.https.onRequest(sendStoredFile)L235注册为 HTTP 触发的 Cloud Function。它接收 Firebase Hosting 转发过来的全部请求按以下顺序处理。4.1 常量与存储桶定位const storage new Storage(); const gcsBucketId ${process.env.GCLOUD_PROJECT}.appspot.com; const BROWSER_CACHE_DURATION 60 * 10; const CDN_CACHE_DURATION 60 * 60 * 12;存储桶 ID 直接取当前 GCP 项目的默认桶命名规则GCLOUD_PROJECT.appspot.comL6-L7。这与.circleci/config.yml中gsutil -m rsync -r ... gs://code-angularjs-org-338b8.appspot.com的目标桶保持一致。两个缓存时长常量L9-L10随后用于拼接Cache-Control响应头浏览器端缓存 10 分钟CDN 层缓存 12 小时。4.2 URL 解码与路径分段const requestPath decodeURI(request.path || /); let filePathSegments requestPath.split(/).filter((segment) { return segment ! ; });源码注释L13-L16明确指出Hosting 转发进来的路径是URI 编码的必须先用decodeURI还原否则会与存储桶中的真实文件名失配、导致 404 并错误地回退到index.html。注释给出的例子是.../input%5Btext%5D.html需要还原成.../input[text].html。随后按/切分并过滤空段得到各层级路径段。4.3 版本目录与 docs 语义识别const version filePathSegments[0]; const isDocsPath filePathSegments[1] docs; const lastSegment filePathSegments[filePathSegments.length - 1];这里的解析约定与站点的目录组织方式强相关第一段filePathSegments[0]即版本号如1.8.3、snapshot第二段为docs时判定为文档请求最后一段即目标文件名。在此基础上云函数先处理一个特例——纯文档目录请求回退到 index.htmlL31-L36if (isDocsPath filePathSegments.length 2) { fileName index.html; filePathSegments [version, docs, fileName]; }也就是说/1.8.3/docs会被转换为/1.8.3/docs/index.html从桶中读取该文件返回。4.4 根目录动态生成目录索引if (!fileName) { // Root return getDirectoryListing(/).catch(sendErrorResponse); }当请求落在根路径没有文件名段时云函数调用getDirectoryListing(/)实时列出 GCS 桶的顶层目录即各个版本号目录并生成一个 HTML 索引页返回L103-L192。这是 code.angularjs.org 首页“版本列表”的实现基础。getDirectoryListing的实现要点使用delimiter: /与autoPaginate: false调用bucket.getFiles只取当前层级不递归L106-L109通过 GCS API 返回的prefixes收集子目录名、files收集文件名分别渲染为带链接的 HTML 条目L124-L132根路径时对目录列表做reverse()“让最新版本排在最前面”L119-L122这一行为依赖 GCS 返回的字典序通过反转实现降序展示生成 HTML 时以base href${base}固定基准路径L144并保证即使 URL 末尾没有斜杠也能通过补斜杠得到正确的相对链接L134-L136若某层既无文件也无目录含分页结果为空则拒绝并抛出 404L167-L175若结果被分页nextQuery存在会递归拉取下一页合并L183-L186。4.5 文件下载与缓存头function downloadAndSend(downloadSource) { const file bucket.file(downloadSource); return file.getMetadata().then(data { return new Promise((resolve, reject) { const readStream file.createReadStream() .on(error, reject) .on(finish, resolve); response .status(200) .set({ Content-Type: data[0].contentType, Cache-Control: public, max-age${BROWSER_CACHE_DURATION}, s-maxage${CDN_CACHE_DURATION} }); readStream.pipe(response); }); }); }核心逻辑L61-L83以完整路径如1.8.3/angular.min.js定位桶内对象先从file.getMetadata()取得该对象的contentTypeMIME 类型保证响应 Content-Type 与文件真实类型一致通过createReadStream()以流式方式将文件内容管道到 HTTP 响应避免大文件全部载入内存显式设置Cache-Control: public, max-age600, s-maxage43200——浏览器缓存 10 分钟、CDN 缓存 12 小时兼顾“新版本发布后及时可见”与“下载带宽优化”。4.6 404 回退链与错误响应下载失败时L45-L59遵循一条清晰的回退链若当前是 docs 路径且错误码为 404则回退尝试docs/index.html——保证文档目录内任意缺省路径都能落到应用入口若仍然 404则把原始路径当作“目录”再尝试一次getDirectoryListing(request.path.slice(1))实现目录浏览最终仍失败则由sendErrorResponse兜底404 返回File or directory not found其他错误返回 500 与通用错误提示L85-L101。这套“文件 → docs 入口 → 目录列表 → 错误页”的四级回退正是原文档所说“serves the docs from the Firebase Google Cloud Storage bucket”的完整实现——它让文件下载、文档访问、目录浏览三种场景共用一个函数、一份配置。五、deleteOldSnapshotZip自动清理旧快照构建包除 HTTP 分发函数外functions/index.js 还注册了一个存储触发型函数L236exports.deleteOldSnapshotZip functions.storage.object().onFinalize(deleteOldSnapshotZip);它会在 GCS 桶中任何对象最终写入完成onFinalize时被触发其目的正如源码注释L197-L200所述build 目录中每个构建对应一个唯一的 zip 文件当snapshot或snapshot-stable目录上传了新的 zip 时把旧的 zip 删除避免快照目录无限堆积历史构建包。处理逻辑L202-L233要点用正则/^snapshot(-stable)?\//匹配对象路径只处理snapshot/与snapshot-stable/两个前缀目录L195仅当新对象的contentType application/zip时才继续其余文件如 angular.js、angular.min.js 等一律忽略列出同前缀下所有对象过滤出“非当前文件且同样是 zip”的旧文件逐个调用file.delete()删除并打印found N old zip files to delete日志。这保证了snapshot/snapshot-stable目录在任意时刻最多保留一个 zip 构建包——与 scripts/code.angularjs.org/publish.sh 中“快照构建直接整体刷新 snapshot 目录”的发布模型形成闭环。六、CI 流水线Firebase 与 GCS 的自动部署原文档明确指出“代码通过 CI 自动部署到 Firebase Hosting、Functions 以及 GCS 存储桶”具体实现位于 .circleci/config.yml。其中两个 job 与本文主题直接相关6.1 deploy-code-files同步文件到 GCS该 jobconfig.yml L366-L383的执行条件是非 fork 仓库、非 PR、且构建对象是 tag / master / stable 分支。它完成用gcloud auth activate-service-account激活 CI 服务账号并设置项目执行gsutil -m rsync -r scripts/code.angularjs.org-firebase/deploy gs://code-angularjs-org-338b8.appspot.com把构建产物目录递归同步到 GCS 桶。可以推断scripts/code.angularjs.org-firebase/deploy是 CI 工作流中由上游构建 job 通过 workspace 持久化下来的发布文件目录config 中custom_attach_workspace与ls scripts/code.angularjs.org-firebase/deploy即为此做准备其内容对应不同版本号子目录。文件上传到桶后上一节提到的deleteOldSnapshotZip触发器会随之自动执行清理。6.2 deploy-code-firebase部署 Firebase 配置与函数该 jobconfig.yml L390-L411只在 master 分支触发负责把函数代码与 Hosting 配置发布到 Firebasecd scripts/code.angularjs.org-firebase/functions yarn install --frozen-lockfile --ignore-engines --non-interactive cd ../scripts/code.angularjs.org-firebase firebase$(yarn bin)/firebase $firebase use $firebase deploy --message Commit:\ $CI_COMMIT --non-interactive --token $FIREBASE_TOKEN实现细节中还有两点值得注意部署前先安装 functions 依赖是为了避免部署解析函数代码时因缺少依赖报错config 注释引用了 PR #16453 的背景刻意不通过yarn firebase而是直接取yarn bin下的 firebase 可执行文件因为前者会让 Firebase CLI 在仓库根目录查找firebase.json即使当前工作目录已在scripts/code.angularjs.org-firebase/内——这正是 config 注释中明确的坑位提示。结合 functions/package.json函数运行环境为Node 14engines: { node: 14 }依赖google-cloud/storage ^5.8.5、firebase-admin ^9.9.0、firebase-functions ^3.14.1均与index.js中的require一一对应。七、发布流程与 Firebase 的关系版本文件的“上游”发布由 scripts/code.angularjs.org/publish.sh 驱动它会从当前构建生成版本目录正式版或刷新snapshot目录包含sha的构建提交到独立的code.angularjs.org仓库而部署到 Firebase 与 GCS 的步骤由 CI 完成脚本注释明确写着 “the deployment to Firebase happens via CI”。同理scripts/code.angularjs.org/unpublish.sh 用于从版本仓库移除指定版本目录。由此可以梳理出完整的数据流本地构建 → publish.sh 提交版本目录到 code.angularjs.org 仓库 → CIdeploy-code-filesgsutil 同步到 GCS 桶 → CIdeploy-code-firebase部署 Hosting 配置与 Cloud Functions → 用户请求 code.angularjs.org → sendStoredFile 从桶中流式返回 → 快照 zip 上传触发 deleteOldSnapshotZip 清理旧包八、本地查看与调试建议仓库是只读的无法直接修改部署但基于源码可以给出合理的本地验证思路静态阅读配置对照 firebase.json 与 functions/index.js 逐行梳理请求路径解析逻辑重点关注decodeURI、docs 回退、根目录列表三处分支。本地启动函数在 functions/ 目录执行yarn install后可使用 Firebase CLI 的本地模拟器firebase emulators:start运行sendStoredFile需要本地存在可访问的 GCS 桶或模拟存储。验证缓存行为响应头中Cache-Control: public, max-age600, s-maxage43200可直接用curl -I检查目录索引页可访问站点根路径或任意目录路径触发。理解回退链分别请求存在的文件、/version/docs、不存在的目录观察 200 / 301 重定向 / 404 三种结果即可完整覆盖 L45-L59 的分支逻辑。九、总结code.angularjs.org的 Firebase 部署方案是一个非常典型的“Hosting 做入口、Cloud Functions 做分发逻辑、GCS 做存储”的架构范例firebase.json用一条/**重写规则把所有子目录请求收拢进sendStoredFile后者通过解码路径、识别版本/docs 语义、四级 404 回退和流式下载用一个函数同时支撑了文件下载、文档访问与目录浏览deleteOldSnapshotZip存储触发器则以极低成本保证了 snapshot 目录不堆积历史构建包CI 中deploy-code-files与deploy-code-firebase两个 job 分别完成 GCS 同步与 Firebase 部署让整个站点从发布到生效全程自动化。相关姊妹部署docs.angularjs.org可参考 scripts/docs.angularjs.org-firebase/readme.firebase.docs.md其目录结构与本文所述方案一脉相承。【免费下载链接】angular.jsAngularJS - HTML enhanced for web apps!项目地址: https://gitcode.com/gh_mirrors/an/angular.js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。