diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..36a893d --- /dev/null +++ b/.dockerignore @@ -0,0 +1,26 @@ +# 依赖与构建产物,由镜像内的 pnpm install / pnpm build 重新生成 +node_modules +**/node_modules +.nuxt +**/.nuxt +.output +**/.output +dist +**/dist + +# 版本控制与 CI +.git +.gitignore +.github + +# 本地环境变量 +.env +.env.* +!.env.example + +# 编辑器与工具 +.idea +.vscode +*.log +.DS_Store +.trae-html-share-packages diff --git a/Dockerfile b/Dockerfile index 86aa38c..f8d4ca8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,17 +1,45 @@ +# ---------- 构建阶段 ---------- FROM node:24-alpine AS builder -RUN apk update +# pnpm 版本与 package.json 的 packageManager 字段保持一致 RUN npm install -g pnpm@11.21.0 WORKDIR /app + +# 构建期关闭遥上报,避免容器构建时产生外部请求 +ENV NUXT_TELEMETRY_DISABLED=1 + +# 先只复制依赖清单,让 pnpm install 这一层可以被缓存复用 +COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./ +COPY apps/web/package.json apps/web/package.json +COPY packages/cook/package.json packages/cook/package.json +COPY docs/package.json docs/package.json + +RUN pnpm install --frozen-lockfile + +# 再复制源码并构建 COPY . . -# Public analytics settings are compiled into the static site. +# 统计配置在构建期编译进静态产物 ARG NUXT_PUBLIC_CLARITY_PROJECT_ID=ks1ebw03i5 ARG NUXT_PUBLIC_CLARITY_DOMAINS=cook.yunyoujun.cn,cook.yunle.fun +ENV NUXT_PUBLIC_CLARITY_PROJECT_ID=${NUXT_PUBLIC_CLARITY_PROJECT_ID} +ENV NUXT_PUBLIC_CLARITY_DOMAINS=${NUXT_PUBLIC_CLARITY_DOMAINS} -RUN pnpm install --frozen-lockfile && pnpm run build +# 镜像里没有 .git,版本号组件拿不到 commit;传入该值即可显示版本信息 +ARG CF_PAGES_COMMIT_SHA= +ENV CF_PAGES_COMMIT_SHA=${CF_PAGES_COMMIT_SHA} +# 构建产物输出到仓库根目录的 dist/(见 scripts/copy-web-output.ts) +RUN pnpm run build + +# ---------- 运行阶段 ---------- FROM nginx:stable-alpine + +COPY docker/nginx.conf /etc/nginx/conf.d/default.conf COPY --from=builder /app/dist /usr/share/nginx/html -EXPOSE 80 + +EXPOSE 2229 + +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD wget -qO- http://127.0.0.1:2229/ >/dev/null || exit 1 diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..ca9a38c --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,23 @@ +services: + cook: + build: + context: . + dockerfile: Dockerfile + args: + # 统计配置在构建期编译进静态产物,未设置时使用项目默认值 + NUXT_PUBLIC_CLARITY_PROJECT_ID: ${NUXT_PUBLIC_CLARITY_PROJECT_ID:-ks1ebw03i5} + NUXT_PUBLIC_CLARITY_DOMAINS: ${NUXT_PUBLIC_CLARITY_DOMAINS:-cook.yunyoujun.cn,cook.yunle.fun} + # 可选:传入 git commit,页脚会显示版本号与提交 + CF_PAGES_COMMIT_SHA: ${CF_PAGES_COMMIT_SHA:-} + image: cook-web:latest + container_name: cook-web + restart: unless-stopped + ports: + # 容器内 nginx 监听 2229,对外同样暴露 2229 + - '2229:2229' + healthcheck: + test: [CMD, wget, -q, -O, /dev/null, http://127.0.0.1:2229/] + interval: 30s + timeout: 3s + start_period: 5s + retries: 3 diff --git a/docker/nginx.conf b/docker/nginx.conf new file mode 100644 index 0000000..04b2386 --- /dev/null +++ b/docker/nginx.conf @@ -0,0 +1,49 @@ +server { + listen 2229; + server_name _; + + root /usr/share/nginx/html; + index index.html; + + # 静态资源压缩 + # 注意:显式声明 gzip_types 会覆盖内置默认列表,但 text/html 始终会被压缩,无需重复声明 + #(重复写 text/html 只会触发 nginx 的 duplicate MIME type 警告) + gzip on; + gzip_vary on; + gzip_min_length 1024; + gzip_types + text/plain + text/css + text/xml + text/javascript + application/javascript + application/json + application/xml + image/svg+xml; + + # 带内容哈希的构建产物可以长期缓存 + location /_nuxt/ { + add_header Cache-Control "public, max-age=31536000, immutable"; + try_files $uri =404; + } + + # Service Worker 每次都要回源校验,否则老用户会被锁在旧版本 + location = /sw.js { + add_header Cache-Control "no-cache, no-store, must-revalidate"; + try_files $uri =404; + } + + # 无扩展名的关联域名文件需要正确的 Content-Type + location /.well-known/ { + default_type application/json; + add_header Cache-Control "public, max-age=3600"; + try_files $uri =404; + } + + # CSR 应用:未预渲染的路由交给前端路由处理 + location / { + try_files $uri $uri/ /index.html; + } + + error_page 404 /404.html; +}