PVQ-UI 部署方案(腾讯云 COS)
唯一真源:本文件。配置/脚本变更须先更新本文件再改代码。 关联:《PVQ-UI组件库开发方案.md》§3(产物 CDN 单一源)、《PVQ-UI组件库调用手册.md》。
1. 目标
组件库产物(CSS/JS)通过 coscli(腾讯云官方命令行)一键部署到腾讯云 COS;各插件经 pvq-ui-loader.php 以固定 URL 调用:
https://cdn-buke.pvq.ink/pvq-ui/v{ver}/pvq-ui.css
版本号隔离在路径中,旧版本保留不删,调用方显式锁版本(见《调用手册》§2)。
2. 前置条件
- 安装
coscli:https://cloud.tencent.com/document/product/436/63144- macOS:
brew install coscli - 其他平台:下载官方二进制并加入
PATH
- macOS:
- 腾讯云账号 + 已建存储桶(如
pvq-ui-125xxxxxxx) - 将自定义域名
cdn-buke.pvq.ink绑定到该桶的 CDN 加速域名(未绑定时见 §6 临时方案)
3. 配置文件
3.1 cos.config.example.json(入库模板)
真实文件 cos.config.json 不入库(.gitignore 已忽略),本地复制后填入。
{
"secretId": "YOUR_SECRET_ID",
"secretKey": "YOUR_SECRET_KEY",
"bucket": "pvq-ui-125xxxxxxx",
"region": "ap-guangzhou",
"customDomain": "https://cdn-buke.pvq.ink",
"localDir": "assets",
"remotePrefix": "pvq-ui",
"cacheControl": "max-age=31536000, immutable"
}
| 字段 | 说明 |
|---|---|
secretId / secretKey |
腾讯云 API 密钥(仅本地,绝不入库) |
bucket |
存储桶名(含 APPID,如 pvq-ui-125xxxxxxx) |
region |
地域,如 ap-guangzhou |
customDomain |
绑定的自定义域名,用于自检与 loader 默认 URL |
localDir |
本地产物目录,默认 assets |
remotePrefix |
COS 内前缀,默认 pvq-ui |
cacheControl |
上传时设置的 Cache-Control 响应头 |
3.2 coscli 认证(独立于仓库)
coscli 读 ~/.cos.yaml(由 coscli config 生成,含 secretId/secretKey/buckets/region)。deploy.sh 不传任何密钥,只调用 coscli,密钥安全由 coscli 本地配置承担,与仓库解耦。
4. 部署流程
cp cos.config.example.json cos.config.json # 填入真实 bucket / region / 密钥
coscli config # 按提示生成 ~/.cos.yaml
./scripts/deploy.sh # 自动读取 assets/css/pvq-ui.css 的 @version 部署
./scripts/deploy.sh 1.1.3 # 或显式指定版本号
脚本步骤:校验 coscli 与 cos.config.json → 读取版本号 →
coscli sync assets/ cos://{bucket}/{prefix}/v{ver}/ --meta "Cache-Control: {cacheControl}"
→ curl 自检自定义域名 URL 返回 200。
依赖:本地需有 php CLI(用于解析 JSON 与读取 @version)。
5. COS 存储结构 ↔ loader URL
cos://pvq-ui-125xxxxxxx/pvq-ui/v1.1.2/
├─ pvq-ui.css
├─ pvq-ui-admin.css
├─ pvq-ui-editor.css
├─ pvq-ui-frontend.css
├─ pvq-ui.js
└─ components.json # 组件清单机器可读唯一真源(§3.5),随库同版本发布
components.json与库 CSS/JS 同目录同版本,官网画廊(site/inc/gallery.php)线上运行时读它,库一升级发布,画廊自动跟随多组件、变稳定性标签(详见《组件库开发方案》§3.5)。 对应 loader 默认 URL(CDN_BASE = https://cdn-buke.pvq.ink/pvq-ui,按v{ver}/拼接):https://cdn-buke.pvq.ink/pvq-ui/v1.1.2/pvq-ui.css等。
6. 调用方式
require_once 'pvq-ui-loader.php';
PVQ_UI_Loader::enqueue( array( 'admin' ), '1.1.2' );
自定义域名尚未绑定到 COS 时,站点可用常量覆盖为 COS 默认访问域名:
define( 'PVQ_UI_URL', 'https://pvq-ui-125xxxxxxx.cos.ap-guangzhou.myqcloud.com/pvq-ui/v1.1.2/pvq-ui.css' );
define( 'PVQ_UI_ADMIN_URL', 'https://pvq-ui-125xxxxxxx.cos.ap-guangzhou.myqcloud.com/pvq-ui/v1.1.2/pvq-ui-admin.css' );
define( 'PVQ_UI_EDITOR_URL', 'https://pvq-ui-125xxxxxxx.cos.ap-guangzhou.myqcloud.com/pvq-ui/v1.1.2/pvq-ui-editor.css' );
define( 'PVQ_UI_FRONT_URL', 'https://pvq-ui-125xxxxxxx.cos.ap-guangzhou.myqcloud.com/pvq-ui/v1.1.2/pvq-ui-frontend.css' );
define( 'PVQ_UI_JS_URL', 'https://pvq-ui-125xxxxxxx.cos.ap-guangzhou.myqcloud.com/pvq-ui/v1.1.2/pvq-ui.js' );
7. 缓存策略
上传即设 Cache-Control: max-age=31536000, immutable。版本号已在路径中,更新即换路径,旧 URL 永久有效,长缓存零风险。
8. 安全
cos.config.json(真实密钥)与~/.cos.yaml均 不入库;仅cos.config.example.json入库。- 严禁将
SecretId/SecretKey提交到任何仓库或文档。 - 本仓库
.gitignore已忽略cos.config.json、.cos.yaml、本地临时文件。
9. 多版本共存与回滚
每次 deploy 上传到独立 v{ver}/ 目录,旧版本保留。回滚只需调用方把 enqueue 的版本号改回旧版,COS 上无需删除旧目录。
10. 本方案不 bump 库产物版本
本次新增的是部署工具链(配置 + 脚本 + 文档),CSS/JS 产物内容未变,不提升库版本号;仅在 readme.md 增加「部署」段、CHANGELOG.md 补一条部署工具记录。
11. 官网部署(FTP → pvq-ui.pvq.ink)
官网是库的对外门面:展示全部组件、说明与调用方法,位于仓库 site/。采用 PHP 动态渲染 doc/ 下的 Markdown(文档为单一真源,改一处网站自动同步),组件资源直接引用 COS CDN(cdn-buke.pvq.ink),不另存一份。
目标主机为 PHP 虚拟主机,部署走 FTP:
cp ftp.config.example.json ftp.config.json # 填入真实 FTP 信息(host/user/pass/remoteDir…)
php scripts/deploy-ftp.php # PHP 原生 ftp 扩展,镜像 site/ + doc/ 到 remoteDir
脚本行为:
- 读
ftp.config.json(真实文件,不入库)→ 连接(优先 FTPSftp_ssl_connect,失败回退普通 FTP)→ 被动模式。 - 递归上传
site/→remoteDir,并把doc/→remoteDir/doc(官网实时渲染用)。 site/lib/Parsedown.php(Markdown 解析器)随site/一并上传。
安全与耦合:
- 真实
ftp.config.json含 FTP 密码,不入库(.gitignore已忽略),仅ftp.config.example.json入库。 - 网站版本与库版本耦合:
site/inc/config.php的PVQ_UI_VERSION必须与当前库版本一致;升库版本时同步修改它,否则网站引用的 CDN 资源路径会失效。 - 域名
pvq-ui.pvq.ink的 web 根指向remoteDir,访问https://pvq-ui.pvq.ink/即官网首页。 - 组件清单 JSON 双轨(与《组件库开发方案》§3.5 一致):
components.json位于site/inc/,随site/由deploy-ftp.php上传到 web 根;同时deploy.sh把它同步到 COSpvq-ui/v{ver}/components.json。官网画廊gallery.php本地开发时读仓库内site/inc/components.json(改 JSON 刷新即见),线上运行时读 COS 同版本 JSON——新增组件只改components.json,画廊自动出现,无需改gallery.php。 doc/必须随部署进入 web 根内的doc/目录:线上deploy-ftp.php把doc/上传到remoteDir/doc,与铺在 web 根的site/程序同级;docs.php探测is_dir(__DIR__.'/doc')为真 → 走「同级 doc」分支,不越级访问。这是线上唯一正确形态,切勿让docs.php走到../doc分支。
11.1 本地预览与 open_basedir 约束
docs.php 的文档根探测(site/docs.php:8):
$docBase = is_dir(__DIR__ . '/doc') ? __DIR__ . '/doc' : __DIR__ . '/../doc';
- 线上(web 根 =
remoteDir,site/内容铺在 web 根,doc/在web根/doc):__DIR__.'/doc'存在 → 走前半段,安全。 - 本地直接把
site/当 web 根跑(宝塔建站 / 本地 nginx 根指向site/):若主机对站点设open_basedir锁到site/(+/tmp),则仓库根doc/(在site/之外)不会被纳入 →docs.php走到../doc分支 →is_file()被open_basedir拦截,报Warning: is_file(): open_basedir restriction in effect …并落到「文档未找到」。
方案 A(推荐,贴合线上架构):让 site/doc 存在即可,不动环境安全配置。
- 本地执行:
cp -r doc site/doc(真实复制,不可用软链——open_basedir会解析软链真实路径,仍判越界)。 - 把
site/doc/加入.gitignore:仓库根的doc/才是单一真源,site/doc仅本地预览派生产物,不得入库。 - 之后
docs.php探测is_dir(__DIR__.'/doc')为真,warning 消失、文档正常渲染。 - 改了仓库根
doc/后需重新cp -r doc site/doc才反映到本地预览(线上由deploy-ftp.php自动同步,无需手动)。 - 备选方案 B(不推荐):放宽
open_basedir把仓库根纳入。代价是削弱站点安全隔离,仅为迁就代码,非长久之计。