news 2026/9/20 5:35:22

Cube 文档静态资源上传指南:upload-asset.sh 与 cube-dev-websites-shared S3 桶的完整使用规范

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Cube 文档静态资源上传指南:upload-asset.sh 与 cube-dev-websites-shared S3 桶的完整使用规范

Cube 文档静态资源上传指南:upload-asset.sh 与 cube-dev-websites-shared S3 桶的完整使用规范

【免费下载链接】cube📊 Cube Core is open-source semantic layer for AI, BI and embedded analytics项目地址: https://gitcode.com/gh_mirrors/cu/cube

本指南围绕 Cube 文档仓库(docs-mintlify/)中维护文档静态资源(图片、Logo、架构图等)的标准流程展开,核心工具是docs-mintlify/scripts/upload-asset.sh:它负责将本地静态资源上传到cube-dev-websites-sharedS3 桶,并输出可直接写入.mdx文档的https://static.cube.dev/<key>URL。读完本文,你将掌握该脚本的安装配置、调用方式、路径命名约定、不可变(immutable)对象存储策略,以及如何在 Mintlify 文档中正确引用这些资源。

背景:为什么文档图片不能直接提交到仓库

Cube 文档站点基于 Mintlify 构建(参见 docs-mintlify/package.json,依赖mintlify ^4),其本地开发与构建命令如下:

cd docs-mintlify yarn dev # 启动 Mintlify 开发服务器(端口 3002) yarn build # 构建文档站点

关于图片与二进制文件的处理,docs-mintlify/CLAUDE.md 明确了一条硬性规则:不要把图片或其他二进制文件提交到仓库。截屏、示意图、Logo、视频等编辑性媒体统一上传到cube-dev-websites-sharedS3 桶,由https://static.cube.dev/<key>提供访问,文档.mdx中只引用该 URL。仓库中的docs-mintlify/images/目录仅存放少数遗留旧资源,官方说明不再向其中新增内容。

这样的设计带来几个好处:

  • 仓库只包含文本内容(.mdx),体积小、diff 清晰、审查容易;
  • 同一资源可被多篇文档复用,URL 与文档页面解耦;
  • 对象携带长效缓存头(Cache-Control: public, max-age=31536000, immutable),CDN 层可以放心缓存,站点加载更快。

脚本概览:upload-asset.sh 的职责与调用方式

upload-asset.sh 是一个约 116 行的 Bash 脚本(以#!/usr/bin/env bash开头,启用set -euo pipefail),核心流程是:

  1. 校验参数与本地文件是否存在;
  2. 校验目标 key 是否合法(必须是相对路径、不允许包含../开头);
  3. 根据文件扩展名推断Content-Type
  4. 若未传--force,先通过aws s3api head-object检查 key 是否已存在,已存在则拒绝覆盖;
  5. aws s3 cp上传,携带固定的content-typecache-control
  6. 打印最终 URL,并在 macOS 上通过pbcopy复制到剪贴板。

脚本的常量定义如下(可在脚本头部看到):

BUCKET="cube-dev-websites-shared" REGION="us-west-2" PUBLIC_BASE="https://static.cube.dev" PROFILE="${AWS_PROFILE:-cube-static}"

也就是说:桶名固定为cube-dev-websites-shared,区域为us-west-2,公网基址为https://static.cube.dev,AWS 凭证 profile 默认取cube-static(可用环境变量AWS_PROFILE覆盖)。脚本还内置了usage函数,会在参数不足时打印帮助信息后退出(退出码 1)。

基本调用

docs-mintlify/目录下执行:

./scripts/upload-asset.sh <local-file> <dest-key> [--force]

参数含义:

参数说明
<local-file>本地待上传文件的路径(相对docs-mintlify/),必须真实存在,否则脚本报error: source file not found
<dest-key>上传到桶内的目标 key(即 URL 的<key>部分),必须是相对路径,不允许以/开头或包含..,否则脚本报错拒绝
--force可选。跳过"key 已存在则拒绝"的检查,强制覆盖(详见下文"不可变性"一节)

官方示例:

./scripts/upload-asset.sh ./snowflake.svg icons/snowflake.svg ./scripts/upload-asset.sh ./architecture.png docs/getting-started/architecture.png ./scripts/upload-asset.sh ./flow.svg diagrams/pre-aggregations-flow.svg

成功上传后的输出形如:

→ bucket: s3://cube-dev-websites-shared/icons/snowflake.svg → region: us-west-2 → profile: cube-static → content-type: image/svg+xml → cache: public, max-age=31536000, immutable ✓ uploaded https://static.cube.dev/icons/snowflake.svg (copied to clipboard)

把输出的 URL 粘贴到对应的.mdx文件中并提交即可。

注意:docs-mintlify/CLAUDE.md 特别提醒,本仓库直接使用./scripts/upload-asset.sh,而不是pnpm upload-asset——后者是 landing 仓库的封装,不适用于此处。

一次性环境配置(One-time setup)

1. 安装 AWS CLI

brew install awscli

2. 配置本地 profile

建议将 profile 命名为cube-static,这样脚本会自动选中它(脚本的默认PROFILE="${AWS_PROFILE:-cube-static}"会优先读取AWS_PROFILE环境变量,其次回退到cube-static;如果你用了别的名字,运行时需先export AWS_PROFILE=<name>)。

aws configure --profile cube-static # AWS Access Key ID: <your key> # AWS Secret Access Key: <your secret> # Default region name: us-west-2 # Default output format: json

所需凭证必须具有对cube-dev-websites-shared桶执行s3:PutObjects3:HeadObject的权限——前者用于上传,后者用于不可变检查。如果没有凭证,应向 Cube 的 AWS 账号管理者申请,切勿自行猜测或捏造凭证(CLAUDE.md 中明确强调"ask — don't guess credentials")。

3. 验证配置

aws sts get-caller-identity --profile cube-static aws s3 ls s3://cube-dev-websites-shared/icons/ --profile cube-static | head

第一条命令返回当前身份信息,确认凭证有效;第二条列出桶内icons/前缀下的对象,确认对桶的读权限与路径可用。

路径约定:按内容域组织资源

为保证同一资源可跨页面复用,资源按内容域分组存放,且文件名统一使用 kebab-case(小写连字符)。完整的前缀表如下:

前缀用途
icons/<slug>.svgProvider / integration / vendor 的 Logo,用于<Card>组件
icons/<slug>-light.svgLogo 的浅色变体(用于深色背景)
icons/<slug>-dark.svgLogo 的深色变体(用于浅色背景)
docs/<section>/<slug>/<file>特定文档页面的截屏与配图
diagrams/<slug>.svg架构图 / 流程图
recipes/<slug>/<file>与 recipe 相关的截屏

文件格式建议:

  • Provider Logo 优先使用 SVG(矢量、可缩放、体积小);
  • UI 截屏优先使用 PNG,大图使用 WebP;
  • 上传前务必压缩——该桶被激进缓存(max-age=31536000),一旦 CDN 缓存后,体积过大的资源会持续拖慢页面。

这一约定与 docs-mintlify/CLAUDE.md 的 "Images and screenshots" 一节保持一致,后者给出了同样的四个前缀(docs/<section>/<slug>/<file>icons/<slug>.svgdiagrams/<slug>.svgrecipes/<slug>/<file>),并补充说明:截屏请用 Mintlify 的<Frame>组件包裹;暂时没有截屏时,先用 MDX 注释占位:{/* TODO: screenshot — ... */}

在仓库实际文档中,可以找到大量按此约定组织的引用示例,例如:

  • docs-mintlify/admin/connect-to-data/visualization-tools/index.mdx 中的<Card>图标,如https://static.cube.dev/icons/quicksight.svghttps://static.cube.dev/icons/hashboard.svghttps://static.cube.dev/icons/metabase.svg等,以及深色/浅色变体icons/klipfolio-light.svgicons/hashboard.svgicons/hightouch-dark.svg
  • docs-mintlify/admin/deployment/continuous-deployment.mdx 中的页面截屏,如https://static.cube.dev/docs/admin/deployment/continuous-deployment/build-deploy-tab.png
  • docs-mintlify/admin/deployment/dedicated/aws/private-api-connectivity.mdx 中的架构图,如https://static.cube.dev/diagrams/private-api-connectivity-aws-v2.png

这些真实用例印证了icons/docs/<section>/diagrams/三类前缀的实际落地形态。

不可变性约定:路径不可覆盖

对象路径按约定不可变。脚本默认拒绝覆盖已存在的 key:非--force模式下,它先调用

aws s3api head-object --bucket "$BUCKET" --key "$KEY" --region "$REGION" --profile "$PROFILE"

若对象已存在,脚本会打印错误并退出(错误信息同时提示:约定是不可变路径,请换一个新 key,例如加-v2后缀,或确有必要时传--force)。

如果资源需要更新,标准流程是:

  1. 上传带版本后缀的新 key,例如snowflake-v2.svg
  2. 同一个 PR中更新.mdx里的引用。

这样做有两层收益:

  • 保证Cache-Control: public, max-age=31536000, immutable的安全性——旧 URL 内容永不变化,CDN 缓存永远有效;
  • 回滚极其简单——只需还原 Markdown 里的 URL 引用即可,无需动 S3 上的对象。

什么时候可以用 --force

如果确实需要覆盖(例如同一会话中上传了损坏文件、且 CDN 尚未缓存),可以传--force

./scripts/upload-asset.sh ./fixed.svg icons/snowflake.svg --force

但请避免对任何已上线的资源使用--force。原因从脚本源码可见:上传时固定携带--cache-control "public, max-age=31536000, immutable",对象会在一整年内被视为不可变而被缓存。覆盖已上线的 key 意味着新内容可能要在缓存中滞留长达一年才能被用户看到——这正是"路径不可变"约定的出发点。

从脚本源码看底层实现细节

upload-asset.sh 中有几个值得关注的实现细节,有助于理解脚本行为:

Content-Type 推断(guess_content_type函数):脚本将文件名转小写后按扩展名映射 MIME 类型——.svg → image/svg+xml.png → image/png.jpg/.jpeg → image/jpeg.gif → image/gif.webp → image/webp.avif → image/avif.ico → image/x-icon.mp4 → video/mp4.webm → video/webm.pdf → application/pdf.json → application/json.txt/.md → text/plain; charset=utf-8;未知扩展名则回退到file --mime-type -b探测,探测失败时兜底为application/octet-stream。这意味着 SVG 与 PNG 之外的文件类型(如 WebP、PDF、视频)也能被正确处理。

上传命令:最终通过

aws s3 cp "$SRC" "s3://${BUCKET}/${KEY}" \ --region "$REGION" \ --profile "$PROFILE" \ --content-type "$CONTENT_TYPE" \ --cache-control "$CACHE_CONTROL"

完成上传,content-typecache-control均显式指定,保证 CDN 与浏览器按预期解析资源。

macOS 剪贴板:上传成功后若检测到pbcopy(macOS 自带),会将 URL 写入剪贴板,方便直接粘贴到文档中。

上传后的验证与质量把关

docs-mintlify/CLAUDE.md 强烈建议:在编辑任何.mdx之前,先验证每次上传。验证命令:

curl -sI https://static.cube.dev/<key>

期望响应:

  • HTTP 状态码200
  • content-type正确;
  • content-length与本地文件一致。

这样可以在重写大量文档之前就发现坏上传,成本远低于事后排查。另外,static.cube.dev是原样透传(pass-through)的——博客的图片优化器只会重写 Uploadcare 的 URL,不会对static.cube.dev上的资源做任何缩放或压缩,因此上传前必须自行压缩:高分辨率截屏(例如 CleanShot 直出的 Retina 图)常常超过 3000px、数 MB 大小,需要先缩放;UI 截屏优先 PNG,大图用 WebP,Logo 用 SVG。

与其它文档脚本的分工

docs-mintlify/scripts/目录下还有若干配套脚本(完整清单见 docs-mintlify/scripts),与upload-asset.sh分工不同:

  • check_links.py:校验 Mintlify 文档中所有内部链接是否指向真实文件(支持行内链接text、引用式链接[ref]: /pathhref/url属性),可传入文档根目录运行,--verbose输出详情;
  • extract-api.mjs、extract-changelog.mjs、extract-chat.js、extract-core-data.js:从上游(API 定义、变更日志等)提取内容生成文档;
  • rewrite_links.py、transform_components.py、update_frontmatter.py:批量改写链接、转换组件、更新 frontmatter。

其中extract-api.mjsextract-changelog.mjs已接入 docs-mintlify/package.json 的脚本命令(api:extractapi:changelogapi:syncapi:check)。upload-asset.sh是其中唯一负责媒体资源上传与发布的核心脚本。

小结:标准工作流

将以上内容串成一条完整的日常工作流:

  1. docs-mintlify/下准备好本地资源文件(Logo 用 SVG,截屏用 PNG/WebP,先压缩);
  2. 按路径约定确定目标 key(icons/docs/<section>/<slug>/diagrams/recipes/,kebab-case 命名);
  3. 执行./scripts/upload-asset.sh <local-file> <dest-key>,脚本输出 URL 并(macOS 上)复制到剪贴板;
  4. curl -sI https://static.cube.dev/<key>验证200content-typecontent-length
  5. 将 URL 粘贴进对应的.mdx(截屏用<Frame>包裹),同一个 PR 内提交引用变更;
  6. 资源需要更新时,上传带版本后缀的新 key(如-v2)并更新引用,避免对已上线资源使用--force

这套流程保证了 Cube 文档仓库保持轻量、资源 URL 稳定、CDN 缓存高效且可随时回滚,是维护 docs-mintlify 文档站点内容时的标准做法。

【免费下载链接】cube📊 Cube Core is open-source semantic layer for AI, BI and embedded analytics项目地址: https://gitcode.com/gh_mirrors/cu/cube

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/20 5:34:41

OpenCode 跑六个开源 Skill 短篇流水线,Base URL 填 TaoToken 的 API 地址

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/20 5:33:07

龙珠Z第164集:特兰克斯VS沙鲁战斗解析与英语学习

1. 龙珠Z第164集剧情深度解析《龙珠Z》第164集展现了特兰克斯与沙鲁的巅峰对决&#xff0c;这一集不仅是力量的对决&#xff0c;更是两个不同时空命运的交汇点。当贝吉塔战败、悟空仍在修炼时&#xff0c;特兰克斯成为了地球最后的希望。1.1 战斗场景的戏剧张力特兰克斯面对完全…

作者头像 李华
网站建设 2026/9/20 5:28:23

修复Typora双击弹窗:Windows文件关联底层配置指南

1. 这个弹窗不是Typora在“提醒你”&#xff0c;而是在“拒绝服务”双击一个.md文件&#xff0c;本该直接在已打开的 Typora 窗口中新建标签页或打开新文档——结果却弹出一个刺眼的对话框&#xff1a;“Typora 已激活”。这行字背后没有温情提示&#xff0c;只有一条被系统拦截…

作者头像 李华
网站建设 2026/9/20 5:27:43

Citra 3DS模拟器完全指南:从下载安装到画质与手柄调校

身边几个朋友最近都在问同一个问题&#xff1a;手头堆了一堆3DS卡带&#xff0c;但主机电池早就不行了&#xff0c;屏幕也小&#xff0c;能不能直接在PC上接着玩&#xff1f;答案就是Citra。作为目前最成熟的任天堂3DS模拟器&#xff0c;Citra能让你在Windows、macOS甚至Linux上…

作者头像 李华
网站建设 2026/9/20 5:27:41

TC78B043FNG+STM32无感BLDC驱动方案:从硬件到调试的完整实战指南

算起来&#xff0c;这几年我在工业设备相关的项目里&#xff0c;用过不少方式去驱动三相 BLDC 电机。早期是纯 MCU 产生六步换相 PWM&#xff0c;那时候对霍尔传感器的依赖特别重&#xff1b;后来为了追求效率&#xff0c;又折腾过基于反电动势过零检测的无感方案。说实话&…

作者头像 李华