2026-10-23 15:07:10 +07:00
2026-10-17 10:13:42 +07:00
2026-10-16 14:10:10 +07:00
2026-10-23 15:07:10 +07:00
2026-10-23 15:07:10 +07:00
2026-10-23 15:07:10 +07:00
2026-10-17 10:13:42 +07:00
2026-10-16 15:29:31 +08:00
2026-10-17 10:13:42 +07:00
2026-10-23 15:07:10 +07:00
2026-10-17 10:13:42 +07:00

花魁短剧 · Next.js / TypeScript

从 jha-1045-hgdjnet-web 迁移的独立 Next.js 16 项目。运行时仅需要 Node.js,不依赖 Go、原项目目录或原 Go 服务。保留内容浏览页面、原 URL、游客会话和播放器(登录、账户与充值功能已移除,旧账户地址 301 到首页);PC/H5 界面按花魁短剧 Figma 设计更新。

启动

推荐 Node.js 22,最低 Node.js 20.9。

npm ci
npm run dev

默认开发地址为 http://localhost:25121,使用原项目开发 API。通过 PORT=其他端口 npm run dev 可以更换端口。开发及测试开发模式默认使用 Webpack 热更新;可用 NEXT_DEV_BUNDLER=turbopack npm run dev 选择 Turbopack。优化构建保持 Next 默认 Turbopack。

PWA 全屏

通过 HTTPS 访问站点并安装到主屏幕后,从桌面图标启动。Android 优先采用 fullscreen,不支持时回退 standalone;iOS 使用独立窗口与透明状态栏,系统状态栏的显示由 Safari/iOS 决定。普通浏览器标签页保持浏览器本身的显示模式。

src/app/manifest.ts 提供安装清单,共用设置位于 src/lib/pwa/config.ts,安装入口为 /,不添加影响渠道或 canonical 的 query。全局 viewport 使用 viewport-fit=cover;安装窗口的页头、底部导航、弹窗与播放器按安全区布局,支持横竖屏。缺少原生 Fullscreen API 的安装窗口使用 xgplayer CSS 全屏。

PwaProvider 只在安全上下文注册 /sw.js,不弹安装提示;localhost 可用于开发验证,手机通过普通局域网 HTTP 访问时无法注册 Service Worker。Worker 源码为 TypeScript,开发启动与构建时自动编译,不拦截或离线缓存页面、接口、签名媒体和密钥;/manifest.webmanifest 与 /sw.js 绕过游客会话和 SSR Proxy,Worker 禁止 HTTP 缓存。standalone 包包含清单路由、Worker 和安装图标。

安装图标由现有花魁 SVG favicon 等比例生成,另提供保留安全留白的 maskable 图标及 180px Apple 图标。更新源图后运行:

npm run assets:pwa
npm run assets:pwa:check
npm run test:pwa

test:pwa 验证实际 React 组件、Worker 注册、模拟安全区和播放器全屏进出;安装与系统状态栏还需在真实 Android/iOS 设备验证。已安装的旧桌面入口可能保留旧清单,更新后可移除旧入口再安装。

本地 Charles 抓包

从 hgdj-official-website 移植 dev:charles,在 Node 启动前设置原生环境代理和 Charles 根证书,让服务端上游 API 和媒体的原生 fetch 请求经过 Charles。沿用普通开发的配置优先级、React 热更新和默认端口 25121;sitemap 读取本地后端产物,不发起远程下载。

  1. 使用 Node 24.5+(或 22.21+);Node 22.17 不支持此代理开关。
  2. 打开 Charles,确认 HTTP Proxy 端口为 8888,在 Proxy → SSL Proxying Settings 中启用实际 UPSTREAM_API_URL 对应的域名及端口,例如 api.example.com:443。
  3. 在 Help → SSL Proxying → Save Charles Root Certificate 中导出 PEM,保存到 ~/.charles-ca.pem。Charles 重置根证书后需要重新导出。
nvm use 24
npm run dev:charles
# 可通过 PORT 或传递 Next 参数指定端口
npm run dev:charles -- --port 3001

默认代理为 http://127.0.0.1:8888,本机回环请求通过 NO_PROXY 排除,并保留既有排除项。自定义代理地址或证书:

CHARLES_PROXY_URL=http://127.0.0.1:8889 \
NODE_EXTRA_CA_CERTS="$HOME/certs/charles.pem" \
npm run dev:charles

代理变量只作用于本次抓包进程;普通开发仍使用 npm run dev。这些 Node 启动变量不能仅放进 Next 的 .env.local 或 config/development.local.env。浏览器直接发出的请求需要浏览器/系统 Charles 代理;缓存命中时不会产生新的上游请求。

Node 原生代理说明:Node.js HTTP 文档。

开发、测试、生产

环境 配置文件 开发启动 构建 运行构建 构建目录
开发 config/development.env npm run dev npm run build:dev npm run start:dev .next-dev
测试 config/test.env npm run dev:test npm run build:test npm run start:test .next-test
生产 config/production.env — npm run build npm start .next

配置优先级:进程环境变量 > config/<环境>.local.env > config/<环境>.env。本地覆盖文件不会提交。APP_ENV 选择业务环境;测试环境的优化构建仍使用 Next.js 要求的 NODE_ENV=production。

开发 UPSTREAM_API_URL 使用 http://127.0.0.1:20032;测试服务与 API 同机,使用 http://127.0.0.1:30331,测试应用端口为 30334。本地运行测试环境且 API 不在本机时,可在 config/test.local.env 覆盖上游地址。正式配置使用同机 API http://127.0.0.1:26931、服务端口 26935,可由部署环境或 config/production.local.env 覆盖。构建不访问上游,启动时检查地址。

UPSTREAM_API_URL=https://your-api.example
UPSTREAM_TIMEOUT_MS=20000
IMAGE_CDN_URL=
SITEMAP_DIR=../template/pages/sitemaps

这些变量仅供服务端使用。官方导航独立进程可以使用 NAVIGATION_ONLY=true PORT=26813 npm start,开放 /、/navigation/ 和静态资源,原 /nav/、/dh/ 一次 301 到 /navigation/。与原 Go DHInit 一致,导航模式不注册 robots、llms、sitemap、验证文件及业务接口,这些地址返回原站 404 页面。

图片 CDN 与 API 独立配置。上游 config/info.config.imgCdn、imgAppUsCdn 按顺序提供图片来源,IMAGE_CDN_URL 提供环境级备用来源。开发 API 返回 imgCdn/imgAppUsCdn;测试 API 30331 返回裸 v3/image/... 且 CDN 配置为空,因此两套环境均显式配置原站已验证可用的 CloudFront 图片线路作为备用;生产独立配置。修改环境配置后需重启服务。

公共图片组件统一解析相对路径,覆盖封面、横幅、背景和头像;相对路径不会随页面目录变化。图片保持原首 100 字节 XOR 协议,也兼容未加密的有效图片;校验文件头后才缓存,HTTP、证书、JSON 错误或超时会尝试配置的备用 CDN。完整外域 URL 保持原签名,只有属于已配置 CDN 的资源才允许切换相同对象路径;图片请求不向外域发送本站 Cookie/Authorization。

目录和渲染边界

目录 职责
src/app/ 原生 App Router TSX 页面、Metadata 与 BFF/媒体 Route Handlers
src/features/ 短剧目录、播放、账号与内容页面组件
src/components/ 页头、页尾、卡片、播放器、图片、弹窗、认证、支付共用组件
src/styles/ 基础、公共组件、页面和 PWA 覆盖样式,通过 TSX 导入并由 Next 编译
src/lib/ 类型化浏览器请求、Cookie、搜索/展示方法
src/proxy.ts、src/server/react/ SSR 数据、状态、响应 Cookie 和 React 数据交接
src/server/pages/ 原路由参数、分页、页面数据组合与播放/账号场景
src/server/services/ 上游 DTO、展示模型、公共配置和请求级复用
src/server/upstream.ts、auth.ts 上游请求、请求头/Cookie 透传、登录与游客恢复
src/server/seo/ 原 SEO 策略、TDK、canonical、JSON-LD 和抓取文件
public/static/ 本地 Figma 品牌/图标、分享图

所有业务页面由 TSX 组件服务端渲染,交互使用 React hooks 和 Client Components。App Router 的 generateMetadata 输出完整首屏 SEO;JSON-LD 使用安全序列化的独立脚本。没有 HTML 模板运行时或注入整页 HTML 的适配层。

54 份业务样式统一在 src/styles/{foundations,components,pages,overrides},由根 layout.tsx 顶层导入,播放器同时保留 npm xgplayer 样式。Next 输出带内容哈希的 CSS 文件,无需手工版本参数或 /static/css 链接。业务类名使用 hk- 命名空间和组件/业务名称;第三方播放器类名保留其包合同。页面样式通过零特异性的 html[data-hk-page-styles] 作用域隔离,基础和公共组件样式共享,PWA 安全区覆盖最后加载。PagePresentation 在客户端切页时同步作用域及页面 body class,同时保留 PWA、弹窗滚动锁等临时状态。

页面代码目录和公开 URL 按用户最新确认统一使用语义路径。src/app 使用 dramas、drama、account 等目录,旧有效页面 GET/HEAD 一次 301 到新地址,规则由 src/lib/routes.ts 管理,保留 slug 编码、原始 query 和 hash。站内链接、canonical、分页、JSON-LD、llms 和默认 App 下载入口同步新地址;同产品后端的 sitemap、canonical 与 SEO 推送生成新路径,Next 继续原字节服务后端 XML。API、媒体签名、图片 CDN、支付和外链保持各自合同。

场景 当前页面路径 301 兼容旧路径
短剧浏览/播放 /dramas/、/drama/:slug/ /list/、/play/:slug/
剧集浏览/播放 /series/、/series/watch/:slug/ /series-play/:slug/
精选/最新/榜单 /featured/、/latest/、/rankings/ /popular-recommend/、/recently-added/、/rank/
专题列表/详情 /collections/、/collection/:slug/ /topic/、/topic-detail/:slug/
推荐栏目 /curated/dramas/:id/、/curated/series/:id/ /more-list/:id/、/more-series-list/:id/
移动搜索/导航/下载 /discover/search/、/navigation/、/app/download/ /search-mobile/、/nav/、/dh/、/download-app/

已移除的账户页面 /account/** 及旧地址 /login/、/register/、/profile/、/history/、/favorites/、/purchased/、/setting/、/settings/、/recharge/ 的 GET/HEAD 一律 301 到首页 /,规则为 src/lib/routes.ts 的 REMOVED_ACCOUNT_PATHS。

分页和筛选保留原参数结构;搜索结果、标签、关于、帮助和法律声明沿用原路径。业务页面组件使用 HomePage、BrowsePages、DiscoveryPages、DramaWatchPage、SeriesWatchPage、SiteNavigationPage,服务端播放模块为 src/server/pages/playback.ts。公共组件封装、源码 CSS 的 TSX 导入和类名保持。

src/app/ 页面目录按上表同名迁移,原动态参数目录保留;nav/dh 合并到同一个入口。其他代码文件的新旧对应如下:

所在目录 原文件 当前文件
src/features/catalog/ IndexPage.tsx HomePage.tsx
src/features/catalog/ ListingPages.tsx BrowsePages.tsx
src/features/catalog/ SearchPages.tsx DiscoveryPages.tsx
src/features/playback/ PlayPage.tsx DramaWatchPage.tsx
src/features/playback/ SeriesPlayPage.tsx SeriesWatchPage.tsx
src/features/content/ NavigationPage.tsx SiteNavigationPage.tsx
src/server/pages/ play.ts playback.ts

后台 hkdj-web-admin 的导航分类 URL 支持搜索、选择当前固定页面入口及直接输入具体路径或外链;历史自定义值保留,提交仍使用原 urlValue 字符串。完整清单源自实际路由注册,执行 npm run routes:export -- --admin ../hkdj-web-admin 同步本仓库 src/lib/page-route-catalog.json、下方对照和后台 src/constants/hkdj-web-routes.json;使用 npm run routes:check -- --admin ../hkdj-web-admin 验证一致性。动态详情、筛选和分页需要真实参数,因此只列入对照,不将未填写参数的模板作为后台可选链接。

本次路径更新涉及 Web、后台管理端和 Go 后端三个仓库。部署后端并由原 sitemap 任务重新生成 XML 后,文件内链接才会更新;已有 XML 仍按原字节返回,其中的旧页面地址通过 301 兼容。

以下清单由 npm run routes:export 从实际路由注册生成,包含全部页面、筛选和分页模式。含 :参数 的路径需要填写真实值;后台导航下拉只展示可直接访问的固定入口,详情页和外链可手动输入。

页面 原路径 当前路径
首页 / /
移动端搜索 /search-mobile/ /discover/search/
搜索结果 /search/ /search/
搜索结果 /search/:q/ /search/:q/
搜索结果 /search/:q/page/:page/ /search/:q/page/:page/
关于我们 /about/ /about/
帮助中心 /help/ /help/
服务条款 /terms/ /terms/
隐私政策 /privacy/ /privacy/
2257 声明 /2257/ /2257/
版权声明 /dmca/ /dmca/
下载 App /download-app/ /app/download/
回家的路 /home-road/ /return-home/
官方导航 /nav/、/dh/ /navigation/
短剧列表 /list/ /dramas/
短剧列表 /list/:theme/ /dramas/:theme/
短剧列表 /list/:theme/:updateStatus/:sortType/ /dramas/:theme/:updateStatus/:sortType/
短剧列表 /list/:theme/:updateStatus/:sortType/page/:page/ /dramas/:theme/:updateStatus/:sortType/page/:page/
短剧推荐栏目 /more-list/:configId/:timeRange/:theme/page/:page/ /curated/dramas/:configId/:timeRange/:theme/page/:page/
短剧推荐栏目 /more-list/:configId/:timeRange/:theme/ /curated/dramas/:configId/:timeRange/:theme/
短剧推荐栏目 /more-list/:configId/page/:page/ /curated/dramas/:configId/page/:page/
短剧推荐栏目 /more-list/:configId/ /curated/dramas/:configId/
剧集推荐栏目 /more-series-list/:configId/:timeRange/:theme/page/:page/ /curated/series/:configId/:timeRange/:theme/page/:page/
剧集推荐栏目 /more-series-list/:configId/:timeRange/:theme/ /curated/series/:configId/:timeRange/:theme/
剧集推荐栏目 /more-series-list/:configId/page/:page/ /curated/series/:configId/page/:page/
剧集推荐栏目 /more-series-list/:configId/ /curated/series/:configId/
剧集列表 /series/ /series/
剧集列表 /series/:media/:topic/:sortType/ /series/:media/:topic/:sortType/
剧集列表 /series/:media/:topic/:sortType/page/:page/ /series/:media/:topic/:sortType/page/:page/
专题列表 /topic/ /collections/
专题列表 /topic/page/:page/ /collections/page/:page/
专题列表 /topic/sort/:sortType/ /collections/sort/:sortType/
专题列表 /topic/sort/:sortType/page/:page/ /collections/sort/:sortType/page/:page/
专题详情 /topic-detail/:slug/sort/:sortType/page/:page/ /collection/:slug/sort/:sortType/page/:page/
专题详情 /topic-detail/:slug/sort/:sortType/ /collection/:slug/sort/:sortType/
专题详情 /topic-detail/:slug/page/:page/ /collection/:slug/page/:page/
专题详情 /topic-detail/:slug/ /collection/:slug/
排行榜 /rank/ /rankings/
排行榜 /rank/page/:page/ /rankings/page/:page/
排行榜 /rank/:sortOrder/ /rankings/:sortOrder/
排行榜 /rank/:sortOrder/page/:page/ /rankings/:sortOrder/page/:page/
标签详情 /tags/:slug/sort/:sortType/page/:page/ /tags/:slug/sort/:sortType/page/:page/
标签详情 /tags/:slug/sort/:sortType/ /tags/:slug/sort/:sortType/
标签详情 /tags/:slug/page/:page/ /tags/:slug/page/:page/
标签详情 /tags/:slug/ /tags/:slug/
最新更新 /recently-added/ /latest/
最新更新 /recently-added/page/:page/ /latest/page/:page/
热门推荐 /popular-recommend/ /featured/
热门推荐 /popular-recommend/page/:page/ /featured/page/:page/
热门推荐 /popular-recommend/:rankType/ /featured/:rankType/
热门推荐 /popular-recommend/:rankType/page/:page/ /featured/:rankType/page/:page/
短剧播放 /play/:slug/ /drama/:slug/
短剧播放 /play/:slug/:ep/ /drama/:slug/:ep/
短剧播放 /play/:slug/recommendations/page/:guessPage/ /drama/:slug/recommendations/page/:guessPage/
短剧播放 /play/:slug/:ep/recommendations/page/:guessPage/ /drama/:slug/:ep/recommendations/page/:guessPage/
剧集播放 /series-play/:slug/ /series/watch/:slug/
剧集播放 /series-play/:slug/recommendations/page/:guessPage/ /series/watch/:slug/recommendations/page/:guessPage/
意见反馈 /feedback/ /feedback/

SSR 在 Proxy 中完成上游数据、游客恢复和 Cookie 写回,再交给 React 渲染,避免首屏流式响应开始后丢失 Cookie。小数据使用压缩内部请求头,较大数据暂存于操作系统临时目录下的私有目录,绑定 URL/Cookie、权限 0700/0600、60 秒过期。适用于当前单 Node 实例或同一文件系统的 standalone 部署;若未来改为分布式 Proxy 与渲染节点,需要更换交接存储。

公共配置可短期复用;登录用户内容仅在单次请求内复用,页面响应使用 private, no-store。必要内容接口临时不可用返回 503、Retry-After 和 noindex;真实缺失的实体及越界分页仍返回 404。

播放器通过 package.json 管理 xgplayer、xgplayer-hls,按需加载官方模块和样式,支持 MP4/HLS、加密密钥、预告切换、章节播放、全屏、解锁及评论。原 DPlayer、全局 Hls 和浏览器业务 JS 已删除。加密图片、二维码分别封装为 TSX 组件,二维码使用 npm qrcode;占位图 Logo 透明度保持 0.2。

SEO 保留范围

  • 上游站点/导航/栏目/内容 SEO、筛选维度和分页独立 TDK。
  • 原收录白名单、私有页面与章节 noindex、无效实体和越界分页真实 404。
  • 永久域名优先,代理协议/Host 回退;slug canonical、尾斜杠、去查询参数。
  • OG/Twitter、Google/Yandex/Bing 验证、可配置百度验证和 IndexNow 文件。
  • Organization、WebSite、WebPage、Breadcrumb、ItemList、FAQ、TVSeries/TVEpisode、VideoObject 等原 JSON-LD 条件和真实元数据。
  • robots.txt、llms.txt、sitemap 索引/分片、纯渠道首页 302、下载地址 302。

上游 TDK、导航、公告和 JSON-LD 中的完整旧品牌词「黄果短剧」统一显示为「花魁短剧」。永久域名、canonical、真实联系地址、普通影片名称、验证值保留原值。

抓取文件遵循原 Go 路由。普通站点的 robots/llms 读取公共配置,保留 60 秒成功缓存;刷新失败沿用最近成功配置,首次失败使用空配置。地址使用原永久域名优先、代理协议/Host 回退规则。robots 按顺序读取 template/pages/robots.txt、templates/pages/robots.txt、app/template/pages/robots.txt、app/templates/pages/robots.txt,没有可用文件时使用原内嵌文本,再回退原内置默认文本。保留原爬虫规则、行处理、已有 Host 和大小写语义,按原算法写入 Sitemap 地址。

sitemap 由原后端生成,Next 只提供文件服务。 开发环境的 SITEMAP_DIR 默认 ./template/pages/sitemaps;测试和生产默认 ../template/pages/sitemaps,均相对 Node 工作目录解析。测试 Node 运行于 /server/hkdj_net/h5/next,后端持续写入 /server/hkdj_net/h5/template/pages/sitemaps;正式环境同样按 h5/next 与 h5/template/pages/sitemaps 的父子目录关系读取,目录不同可通过对应 .local.env 或进程变量覆盖。/sitemap.xml 先读取该目录的 sitemap.xml,再读取 ./template/pages/sitemap.xml;/sitemaps/:name 仅读取该目录中通过原文件名校验的分片。成功响应保留原 XML 字节、loc、priority、lastmod 和文件响应语义,不改域名、不重写新旧路径,也不从分片生成索引。缺失索引、非法或缺失分片均走原站完整 404 页面及其共享数据加载,不生成静态页面 sitemap、空 XML 或远程 API 兜底。

成功的抓取文件通过原生 Route Handler 输出,保留 text/xml; charset=utf-8、Last-Modified、Content-Length、Accept-Ranges、条件请求和单段/多段 Range;HEAD 不返回 body。Proxy 提前将缺失文件、非法分片和不支持的方法交给完整 TSX 404;导航模式按 Go DHInit 不开放这些路由。Next 应用压缩关闭以保持原 Go 文件字节长度与 Range 语义,公网代理可沿用原有传输压缩配置。

新旧服务应读取同一份持续更新的后端产物;文件来源目录不要放进前端发布时会清空的构建目录。也可通过 SITEMAP_DIR=/绝对路径/template/pages/sitemaps 指向后端目录,或使用保留该关系的目录挂载。公网代理仍需正确转发 Host、X-Forwarded-Host 与 X-Forwarded-Proto;不提供额外公网 origin 开关或 IP 限制来改变原站地址规则。

本地需要真实 XML 时,显式执行只读同步命令;页面请求、开发启动和构建不会连接 SSH:

npm run sitemap:sync

该命令始终按开发配置读取,优先级为进程变量 > config/development.local.env > config/development.env;已设置 APP_ENV=test/production 时拒绝执行,避免继承服务端目录。开发默认 SSH 来源为 root@172.104.181.99:22889 的 /server/hkdj_net/h5/template/pages/sitemaps,可覆盖 SITEMAP_SYNC_HOST、SITEMAP_SYNC_PORT、SITEMAP_SYNC_DIR 与本地 SITEMAP_DIR。需提前配置 SSH 密钥及可信 known_hosts;命令不交互输入密码,也不关闭主机校验。仅下载原索引与其引用的有效分片,校验 XML 和索引稳定性后保留原字节、域名、路径和修改时间落盘,最后替换索引;不生成 sitemap、不写远端、不删除未引用的本地文件。同步 XML 及旧本地 data/sitemaps 兼容文件均忽略提交;页面 trace 排除 XML,最终发布包还会定向清理 Proxy trace 带入的副本。

SEO_INDEXNOW_KEY 在三套环境配置中使用同一份重新生成的 Key,并与代码默认值一致;站点根路径 /{key}.txt 自动返回该 Key。后端推送进程的 HKDJNET_INDEXNOW_KEY 需使用相同值。百度可通过 SEO_BAIDU_SITE_VERIFICATION、SEO_BAIDU_HTML_FILE 配置,验证文件放入 config/seo/。搜索引擎实际收录取决于真实域名、后端内容和站长平台状态。

Figma 与界面资源

设计来源:花魁短剧 WEB / H5。页头、页尾、徽标、favicon 和匹配图标均通过 Figma REST API 导出;资源保存在本地,运行和构建不依赖 Figma。SVG 保存 REST 返回的完整原始字节与 Figma 原始尺寸,显示尺寸由 CSS 或 HTML 的宽高属性决定。导出节点、尺寸和校验信息见 public/static/brand/manifest.json 与 scripts/figma-icon-manifest.json。没有精确对应节点的原有功能图标保留,清单记录原因。

导航、登录及 SEO 使用 /static/brand/huakui-20261013/ 下的版本化品牌资源,路径统一在 src/lib/brand-assets.ts 管理,避免旧站同名静态资源和 CDN 缓存继续显示旧 logo。assets:sync 同步生成这些资源并写入校验清单;原路径保留兼容,PWA 图标也从新版品牌源图生成。

# 仅维护设计资源时需要本机 FIGMA_TOKEN;不将 token 写入仓库。
npm run assets:sync
# 离线检查资源完整性,不访问 Figma。
npm run assets:check

首页、列表、播放器和静态页面分别适配 1440px 桌面与 375px 手机设计。H5 底部导航按设计页面显示。影片、广告、余额、套餐、社交地址和二维码继续使用真实上游配置,不将设计示例数据当作业务内容。

设置页的头像、昵称、简介、隐私模式和密码使用现有上传与资料接口。通知偏好、邮箱修改及注销没有对应上游能力,保留设计位置并明确禁用,避免显示保存成功却未生效。

下载入口共用桌面下载弹窗与 H5 安装引导;iOS 支持 App Store、轻量版两个页签,Android 展示安装步骤。以下服务端变量可分别配置真实安装地址,三套环境默认均留空:

APP_IOS_STORE_URL=
APP_IOS_PROFILE_URL=
APP_ANDROID_APK_URL=
APP_DEEP_LINK_URL=

平台地址未配置时,按钮显示“前往下载页”,沿用上游 AppAddr 或 /app/download/ 跳转;未配置 App 深链时隐藏打开 App 入口。链接保留原始跳转地址,不生成设计示例中的安装包、描述文件或 App Store 地址。

谷歌统计(GA4)由 GOOGLE_ANALYTICS_ID 配置,三套环境默认 G-269F3ZFQFQ,在根布局通过 next/script 于页面可交互后加载;留空即关闭。Yandex.Metrika 由 YANDEX_METRIKA_ID 配置,三套环境默认 113657403,同样在根布局加载并带 noscript 像素;留空即关闭。

所有 Telegram 联系入口(页尾、官方导航、回家的路、播放页链接、2257/DMCA、意见反馈,以及 Telegram 形式的「联系我们」客服链接)统一使用 CONTACT_TELEGRAM_URL,三套环境默认 https://t.me/jbd125,覆盖上游 tgGroup、telegram、telegramAdd。值无效时回退为默认账号。

接口和媒体

保留原 BFF 路由、别名、参数校验、业务响应壳、上传和 CSV 导出。Cookie、cookie token 优先的 Authorization、客户端 IP、浏览器 UA、X-User-Agent 透传;过滤 hop-by-hop 和内部控制头。多个 Set-Cookie 独立回传。

公共配置隔离过期登录凭证;个人资料刷新与游客恢复写回当前请求,避免首屏重复建立会话。正式账号失效和内容允许降级游客的规则分别保留。

/h5/m3u8/*、/enkey、/newenkey 保留查询签名、密钥和媒体响应,媒体请求不强制携带登录凭证。/enkey 上游不可用时支持 M3U8_KEY_FILE 本地兜底;原本地密钥已复制到忽略提交的 config/secrets/m3u8.key。部署时提供同一文件或挂载其路径,文件不要放入 public。

验证

npm run check
npm run assets:check
npm run build:dev
npm run build:test
npm run build
npm run test:catalog
npm run test:popups
npm run test:playback
npm run test:ssr
SMOKE_URL=http://localhost:25131 npm run test:browser
SMOKE_URL=http://localhost:25131 npm run test:ui

浏览器检查默认使用 macOS Chrome,可通过 CHROME_PATH 指定。test:catalog、test:popups、test:playback 使用隔离上游与真实 React 组件,验证目录交互、弹层焦点/滚动、官方 xgplayer、加密 HLS 与评论,不改动真实账号。test:ssr 使用生产构建核验 SEO、HTTP 状态、Cookie、透传和并发隔离,不访问真实业务接口。

全站界面截图默认输出 /tmp/hkdj-figma/implementation,浏览器基础检查输出 /tmp/hkdj-browser-smoke。完整真实内容回归需要原上游剧集、专题与标签数据;空环境可设置 UI_ALLOW_EMPTY_CONTENT=1,缺失实体仍必须返回 404 与 noindex。

原 Go 输出夹具保留为 SEO、链接、卡片、预览/可播/锁定场景的迁移参照。签名时间、票据和后端实时热度属于动态值。Next.js 会先规范化连续斜杠和 .. 路径,此类异常 URL 与 Gin 可能存在差异,正常站内链接、canonical 和原筛选/分页规则保留。

独立部署

npm run build
npm run bundle
cd dist/production
UPSTREAM_API_URL=https://your-api.example node start.mjs

bundle 包含 standalone 服务、完整静态资源、对应环境公共配置,以及 robots 和站点验证文件,无需在部署机器安装依赖。后端生成的 sitemap XML(包括开发同步副本)不打入前端包;发布程序必须保留并挂载服务器持续更新的源目录。生产机可以通过进程变量或 config/production.local.env 提供配置;sitemap 和密钥可外部挂载。SITEMAP_DIR 指向的外部目录不会被构建或打包扫描、生成或覆盖。测试包使用 npm run bundle:test。不要在构建机器本地覆盖文件中放入需要打包的生产凭证。

Next 16.4 当前仍可能通过 Node Proxy 的 middleware.js.nft.json 将开发 XML 复制到原始 .next*/standalone,页面级 tracing 排除不能保证该目录无 XML。发布应使用 npm run bundle / bundle:test 生成的 dist:打包脚本只在复制后的独立目录清理 template/pages/sitemaps、data/sitemaps 内的合法 sitemap 文件及备用 template/pages/sitemap.xml。清理前逐层检查父目录,不接受符号链接或异常文件;只 unlink 已确认的文件,不递归删目录,也不跟随后端挂载。robots、密钥及未知文件保留。

也提供 Dockerfile,构建参数 APP_ENV=production|test|development 选择环境,启动时传入 UPSTREAM_API_URL,容器默认端口 3000。

测试服上传

参考 naixin-web-nuxt 的直连测试发布流程,入口为仓库根目录 deploy_test.sh:

# 只核对流程和目标,不构建、不连接服务器
DEPLOY_DRY_RUN=1 npm run deploy:test

# 检查、构建、打包、上传并更新测试服
npm run deploy:test
# 等价于 ./deploy_test.sh

默认目标为 root@172.104.181.99,SSH 端口 22889,上传目录 /server/hkdj_net/h5/。可通过 DEPLOY_HOST、DEPLOY_SSH_PORT、DEPLOY_DIR 临时覆盖。发布后默认检查公网 https://hkdjneth5.remoces.com,可通过 DEPLOY_CHECK_URL 覆盖为另一个 HTTP(S) 站点根地址;dry-run 仅显示该地址,不访问域名。需要本机已安装依赖、zip/unzip、SSH/SCP,并提供忽略提交的 config/secrets/m3u8.key。

脚本依次执行 npm run check、build:test、bundle:test,生成 dist.zip 和 dist.zip.sha256,连同 deploy/up_next_h5.sh 上传。包保留配置、页面和静态资源,排除 node_modules 与本地环境覆盖文件;服务器在暂存目录按 lockfile 执行 npm ci --omit=dev --include=optional --ignore-scripts,为 Linux 安装对应架构的运行依赖。服务器需要 Node.js 20.9+(推荐 22)、npm、可访问 npm 包源,以及 Bash、unzip、sha256sum、curl 和 Supervisor。运行时 dotenv 属于正式依赖。

服务器脚本校验包后更新 /server/hkdj_net/h5/next/,上一版留在 next.prev/,通过独立 Supervisor 程序 hkdj_next_h5 运行 node start.mjs。保留服务器的 next/config/test.local.env、密钥和后端生成的 sitemap:运行目录内默认或自定义目录中的原 XML 优先于包内文件,第二索引 template/pages/sitemap.xml 和四个可选 robots 覆盖文件同样保留;新目录不存在时可迁入旧版本 data/sitemaps,已有空目录也视为权威,不恢复旧 XML。已配置的外置目录不复制、不清空、不覆盖,默认目录的符号链接及其运行目录内目标也保留。首次部署可读取原 Go 目录的 XML;后台持续写原目录时应配置外置 SITEMAP_DIR,避免只使用一次复制的快照。密钥首次可复用原目录 config/secrets/m3u8.key 或 conf/m3u8.key。后续私密配置放服务器的 next/config/test.local.env,不要放入上传包。启动与健康检查失败会返回非零状态,切换后的失败会尝试恢复上一版。本地包及失败时的服务器上传包留存供排查。

测试站 Nginx 必须代理到 127.0.0.1:30334(若服务器覆盖 PORT,使用实际端口),包括页面、/_next/、/static/、/api/ 和媒体路径;上传脚本不修改 Nginx 配置。此前 /etc/nginx/conf.d/hkdj_net-h5.conf 将该域名代理到 API 端口 30331,导致首页和 /healthz 都返回 {"code":1000,"msg":""},本机服务健康也无法证明域名已切流。

服务器健康检查覆盖 /healthz、首页及 /enkey;随后本地脚本通过公网域名检查 /healthz 必须为 HTTP 200 且 JSON status=ok、environment=test,首页必须为 HTTP 200、text/html 并含 Next 静态资源标记。公网检查最多重试 3 次,每次请求超时 4 秒,失败会明确提示“服务器服务已更新,但域名检查失败”,返回非零状态;检查不通过不会误报完整发布成功,也不会自动回滚已经健康的新服务。完成后仍应通过测试站域名检查 PC/H5 页面和真实媒体链路。

正式服上传

正式服为 root@172.104.166.87,Supervisor 程序 web_huakui_h5 在 /web_huakui/h5/app 执行 node start.mjs(端口 26935,Nginx webhuakuih5.mfcg.me 代理到该端口,/enkey、/newenkey 直接走 Go 服务 20031)。

npm run deploy:prod -- --dry-run      # 只核对配置,不构建、不连接
npm run deploy:prod -- --package-only # 检查、构建、生成运行包与 MD5,不上传
npm run deploy:prod                  # 构建、上传、切换并重启

脚本执行 check → build → bundle → bundle:linux,生成根目录 web_huakui_h5.tar.gz 和 web_huakui_h5.md5。tar 根部直接包含 start.mjs、server.js、.next/、public/、config/production.env、媒体密钥和裁剪后的 node_modules/,服务器无需 npm install。本地缺少忽略提交的 config/secrets/m3u8.key 时,构建前从服务器当前版本复制一份。

上传到 /web_huakui/h5/ 后,服务器校验 MD5,解压到 app.new,沿用当前 app/ 中的 config/secrets/m3u8.key 和 config/*.local.env,再将 app 改名为 app.prev、app.new 改名为 app,执行 supervisorctl restart web_huakui_h5。随后检查本机 /healthz(status=ok)和首页;失败则把新版本移到 app.failed,恢复 app.prev 并重启。可用 DEPLOY_HOST、DEPLOY_SSH_PORT、DEPLOY_DIR、DEPLOY_PROGRAM、DEPLOY_TARGET_ARCH、DEPLOY_TARGET_LIBC 覆盖默认值。

本机最低 Node.js 20.9、npm 10.9.2,推荐 Node.js 22。默认目标 Linux x64/glibc,只在临时目录补装目标平台的 Sharp/libvips 原生包,版本与 integrity 取自 lockfile。

S
Description
No description provided
Readme
3.3 MiB
Languages
TypeScript 72.7%
CSS 25.3%
Shell 1.8%
XSLT 0.2%