From 4cb2a12f171091f6e06cb880c1ed45deca2764a0 Mon Sep 17 00:00:00 2001 From: rhld16 <24809571+rhld16@users.noreply.github.com> Date: Thu, 5 Mar 2026 17:41:48 +0000 Subject: [PATCH] optimise(): reduce docker image size and opengraph images (#4885) --- .github/assets/nginx.conf | 5 +++-- Dockerfile | 17 ++++++----------- docs/.vitepress/hooks/meta.ts | 6 +++--- docs/.vitepress/hooks/opengraph.ts | 13 +++++++++---- package.json | 5 +++-- pnpm-lock.yaml | Bin 356580 -> 356438 bytes 6 files changed, 24 insertions(+), 22 deletions(-) diff --git a/.github/assets/nginx.conf b/.github/assets/nginx.conf index f9d8e412d..a163a4735 100644 --- a/.github/assets/nginx.conf +++ b/.github/assets/nginx.conf @@ -6,7 +6,8 @@ server { index index.html; location / { - try_files $uri $uri/ /index.html; + try_files $uri $uri.html $uri/ =404; + add_header X-Frame-Options "DENY"; add_header X-Content-Type-Options "nosniff"; add_header X-XSS-Protection "1; mode=block"; @@ -26,4 +27,4 @@ gzip on; gzip_types text/plain text/css application/javascript application/json image/svg+xml; gzip_min_length 1000; gzip_proxied any; -gzip_vary on; \ No newline at end of file +gzip_vary on; diff --git a/Dockerfile b/Dockerfile index 4feee9d47..0ca7b6423 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,22 +1,17 @@ -FROM node:25.7-slim AS base +FROM node:25.7-alpine AS base ENV PNPM_HOME="/pnpm" ENV PATH="$PNPM_HOME:$PATH" RUN npm install -g pnpm@10.30.3 WORKDIR /app COPY package.json pnpm-lock.yaml ./ -FROM base AS prod-deps -RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile --config.autoInstallPeers=false - FROM base AS build RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile --config.autoInstallPeers=false COPY . . RUN pnpm run docs:build -FROM base -ENV NODE_ENV=production -COPY --from=prod-deps /app/node_modules /app/node_modules -COPY --from=build /app/docs/.vitepress/dist /app/docs/.vitepress/dist - -EXPOSE 4173 -CMD ["pnpm", "docs:preview"] +FROM nginx:alpine-slim +COPY --from=build /app/docs/.vitepress/dist /usr/share/nginx/html +COPY .github/assets/nginx.conf /etc/nginx/conf.d/default.conf +EXPOSE 80 +CMD ["nginx", "-g", "daemon off;"] diff --git a/docs/.vitepress/hooks/meta.ts b/docs/.vitepress/hooks/meta.ts index be455b25c..92c672ca8 100644 --- a/docs/.vitepress/hooks/meta.ts +++ b/docs/.vitepress/hooks/meta.ts @@ -70,14 +70,14 @@ export function generateMeta(context: TransformContext, hostname: string) { ]) } else { const url = pageData.filePath.replace('index.md', '').replace('.md', '') - const imageUrl = `${url}/__og_image__/og.png` + const imageUrl = `${url}/__og_image__/og.webp` .replaceAll('//', '/') .replace(/^\//, '') head.push( ['meta', { property: 'og:image', content: `${hostname}/${imageUrl}` }], ['meta', { property: 'og:image:width', content: '1200' }], - ['meta', { property: 'og:image:height', content: '628' }], + ['meta', { property: 'og:image:height', content: '630' }], ['meta', { property: 'og:image:type', content: 'image/png' }], [ 'meta', @@ -85,7 +85,7 @@ export function generateMeta(context: TransformContext, hostname: string) { ], ['meta', { name: 'twitter:image', content: `${hostname}/${imageUrl}` }], ['meta', { name: 'twitter:image:width', content: '1200' }], - ['meta', { name: 'twitter:image:height', content: '628' }], + ['meta', { name: 'twitter:image:height', content: '630' }], [ 'meta', { name: 'twitter:image:alt', content: pageData.frontmatter.title } diff --git a/docs/.vitepress/hooks/opengraph.ts b/docs/.vitepress/hooks/opengraph.ts index 3bbd78417..e15330aa1 100644 --- a/docs/.vitepress/hooks/opengraph.ts +++ b/docs/.vitepress/hooks/opengraph.ts @@ -20,6 +20,7 @@ import { mkdir, readFile, writeFile } from 'node:fs/promises' import { dirname, resolve } from 'node:path' import { fileURLToPath } from 'node:url' import { renderAsync } from '@resvg/resvg-js' +import sharp from 'sharp' import consola from 'consola' import { createContentLoader } from 'vitepress' import { satoriVue } from 'x-satori/vue' @@ -102,8 +103,8 @@ async function generateImage({ // consola.info(url, title, description) const options: SatoriOptions = { - width: 1800, - height: 900, + width: 1200, + height: 630, fonts, props: { title, @@ -116,12 +117,16 @@ async function generateImage({ const render = await renderAsync(svg) + const compressed = await sharp(render.asPng()) + .webp({ quality: 75 }) + .toBuffer() + const outputFolder = resolve(outDir, url.slice(1), '__og_image__') - const outputFile = resolve(outputFolder, 'og.png') + const outputFile = resolve(outputFolder, 'og.webp') await mkdir(outputFolder, { recursive: true }) - await writeFile(outputFile, render.asPng()) + await writeFile(outputFile, compressed) } function getPage(page: string) { diff --git a/package.json b/package.json index 273cd9d09..0d266b88b 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "nprogress": "^0.2.0", "pathe": "^2.0.3", "reka-ui": "^2.9.0", + "sharp": "^0.34.5", "unocss": "66.6.4", "vitepress": "^1.6.4", "vue": "^3.5.29", @@ -43,7 +44,7 @@ "zod": "^4.3.6" }, "devDependencies": { - "@cloudflare/workers-types": "^4.20251202.0", + "@cloudflare/workers-types": "^4.20260305.1", "@ianvs/prettier-plugin-sort-imports": "^4.7.1", "@iconify-json/carbon": "^1.2.19", "@iconify-json/fluent": "^1.2.40", @@ -73,7 +74,7 @@ "vite-plugin-optimize-exclude": "^0.0.1", "vite-plugin-pwa": "^1.2.0", "vite-plugin-terminal": "^1.4.0", - "wrangler": "^4.52.1" + "wrangler": "^4.70.0" }, "pnpm": { "peerDependencyRules": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4a3498bbcd4134821e8e12acd4e2dba14641b550..c3bae25916197260624b3a03cd57d651985f50d0 100644 GIT binary patch delta 7415 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 MhkEd%mVVFw0r&XR#Q*>R delta 11005 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 LZp?@kzWx6Ld