feat(tos): point all static assets to volcano TOS bucket
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 5m0s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 5m0s
资源已上传到 https://cyberstar.tos-cn-shanghai.volces.com/cyber-star/ 代码改动: - 新增 src/lib/tos.ts 提供 tosUrl(path) 工具,读 NEXT_PUBLIC_TOS_DOMAIN - mock-data.ts: portrait/gallery 切到 .webp, videoUrl 走 TOS, 全部通过 tosUrl() - page.tsx Hero PV 走 tosUrl("videos/hero-pv.mp4") - next.config.ts 把火山 TOS 域名(沪/京)+ 火山 CDN 加进 images.remotePatterns 白名单 - .env.example 更新 NEXT_PUBLIC_TOS_DOMAIN 示例为实际桶域名 体积影响 (与之前打包给运维的 cyber-star-assets.tar.gz 一致): - 立绘 5MB png → 100-300KB webp (-95%) - 单人 solo 5-10MB mp4 → 1-3MB (-70%) - Hero PV 45MB → 12MB (-70%) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
c0bce80dd1
commit
8c88943a06
@ -19,7 +19,7 @@ TOS_REGION="cn-beijing"
|
||||
TOS_BUCKET="cyber-star"
|
||||
TOS_ACCESS_KEY="CHANGE_ME"
|
||||
TOS_SECRET_KEY="CHANGE_ME"
|
||||
NEXT_PUBLIC_TOS_DOMAIN="https://cyber-star.tos-cn-beijing.volces.com"
|
||||
NEXT_PUBLIC_TOS_DOMAIN="https://cyberstar.tos-cn-shanghai.volces.com/cyber-star"
|
||||
|
||||
# ── Auth.js 鉴权 ──
|
||||
# 用 `openssl rand -base64 32` 生成
|
||||
|
||||
@ -5,6 +5,14 @@ const nextConfig: NextConfig = {
|
||||
devIndicators: false,
|
||||
// 容器化部署:产出精简的 standalone 包(node server.js 启动)
|
||||
output: "standalone",
|
||||
// next/image 远程域名白名单:火山 TOS 桶 + 后续 CDN 域名
|
||||
images: {
|
||||
remotePatterns: [
|
||||
{ protocol: "https", hostname: "*.tos-cn-shanghai.volces.com" },
|
||||
{ protocol: "https", hostname: "*.tos-cn-beijing.volces.com" },
|
||||
{ protocol: "https", hostname: "*.volccdn.com" },
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
|
||||
@ -11,6 +11,7 @@ import { getActivityEndTime, sortArtists, type SortKey } from "@/lib/mock-data";
|
||||
import { useVoteStore } from "@/lib/store";
|
||||
import { useVoteAction } from "@/hooks/useVoteAction";
|
||||
import { cn } from "@/lib/cn";
|
||||
import { tosUrl } from "@/lib/tos";
|
||||
|
||||
export default function Home() {
|
||||
const artists = useVoteStore((s) => s.artists);
|
||||
@ -70,7 +71,7 @@ export default function Home() {
|
||||
scrollMarginTop: "80px",
|
||||
}}
|
||||
>
|
||||
<HeroBanner endTime={endTime} videoSrc="/videos/hero-pv.mp4" />
|
||||
<HeroBanner endTime={endTime} videoSrc={tosUrl("videos/hero-pv.mp4")} />
|
||||
</div>
|
||||
|
||||
{/* Top12 出道位 · 作为第二个 snap 点:滚动结束后自然落到这里,标题贴近顶部 */}
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
import type { Artist } from "@/types/artist";
|
||||
import { ARTIST_SEEDS } from "./artist-bios";
|
||||
import { tosUrl } from "./tos";
|
||||
|
||||
/**
|
||||
* 真实艺人数据装配层。
|
||||
* 所有人物字段(姓名 / 性别 / 年龄 / 身高 / 性格 / 技能 / 赛道 / 口头禅 /
|
||||
* 座右铭 / 长简介)来自《36 位虚拟艺人人物小传.docx》。
|
||||
* 立绘 / 三视图 / 氛围图 / solo 视频 来自 public/portraits/ 和 public/videos/artists/。
|
||||
* 立绘 / 三视图 / 氛围图 / solo 视频 走火山 TOS 桶(webp + mp4 已压缩到 1/10)。
|
||||
*
|
||||
* 票数 / 排名是运行时计算(store 投票后会更新)。除此之外不再有任何虚构数据。
|
||||
*/
|
||||
@ -18,9 +19,12 @@ const MISSING_ATMOSPHERE_3: ReadonlySet<string> = new Set(["036"]);
|
||||
|
||||
/** 画廊 = 三张氛围图(1/2/3)。不包含三视图,因为长宽比与卡片不一致。 */
|
||||
function buildGallery(no: string): string[] {
|
||||
const items = [`/portraits/${no}.png`, `/portraits/${no}-2.png`];
|
||||
const items = [
|
||||
tosUrl(`portraits/${no}.webp`),
|
||||
tosUrl(`portraits/${no}-2.webp`),
|
||||
];
|
||||
if (!MISSING_ATMOSPHERE_3.has(no)) {
|
||||
items.push(`/portraits/${no}-3.png`);
|
||||
items.push(tosUrl(`portraits/${no}-3.webp`));
|
||||
}
|
||||
return items;
|
||||
}
|
||||
@ -35,12 +39,12 @@ function buildArtists(): Artist[] {
|
||||
age: seed.age,
|
||||
gender: seed.gender,
|
||||
bio: seed.bio,
|
||||
portrait: `/portraits/${seed.no}.png`,
|
||||
portrait: tosUrl(`portraits/${seed.no}.webp`),
|
||||
avatar: "",
|
||||
gallery: buildGallery(seed.no),
|
||||
videoUrl: MISSING_VIDEO.has(seed.no)
|
||||
? undefined
|
||||
: `/videos/artists/${seed.no}.mp4`,
|
||||
: tosUrl(`videos/artists/${seed.no}.mp4`),
|
||||
// 不设置 poster,由播放器运行时 seek 到 0.001s 渲染首帧作为封面
|
||||
videoPoster: "",
|
||||
tags: seed.tags,
|
||||
|
||||
18
src/lib/tos.ts
Normal file
18
src/lib/tos.ts
Normal file
@ -0,0 +1,18 @@
|
||||
/**
|
||||
* TOS 资源 URL 拼接工具
|
||||
*
|
||||
* 用法:
|
||||
* tosUrl("portraits/001.webp")
|
||||
* → https://cyberstar.tos-cn-shanghai.volces.com/cyber-star/portraits/001.webp
|
||||
*
|
||||
* 环境变量 NEXT_PUBLIC_TOS_DOMAIN 配置:
|
||||
* .env.local / .env.production → 完整的桶 + 路径前缀 (含 scheme, 不含末尾 /)
|
||||
* 未设置时 fallback 到相对路径 (/path/...), 适合本地用 public/ 静态文件托管的场景。
|
||||
*/
|
||||
const TOS_BASE = (process.env.NEXT_PUBLIC_TOS_DOMAIN ?? "").replace(/\/+$/, "");
|
||||
|
||||
export function tosUrl(path: string): string {
|
||||
const clean = path.replace(/^\/+/, "");
|
||||
if (!TOS_BASE) return `/${clean}`;
|
||||
return `${TOS_BASE}/${clean}`;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user