diff --git a/frontend/.dockerignore b/frontend/.dockerignore new file mode 100644 index 0000000..e8af01d --- /dev/null +++ b/frontend/.dockerignore @@ -0,0 +1,25 @@ +node_modules +dist +dist-ssr +coverage +playwright-report +test-results + +e2e +.eslintcache +*.tsbuildinfo +__screenshots__ +.vite + +.vscode +.idea +*.suo +*.sw? + +*.local +.DS_Store + +.git +.gitignore + +README.md diff --git a/frontend/Dockerfile b/frontend/Dockerfile new file mode 100644 index 0000000..94956c2 --- /dev/null +++ b/frontend/Dockerfile @@ -0,0 +1,41 @@ +# ============================================================ +# Stage 1: builder +# ============================================================ +FROM docker.io/library/node:22-alpine AS builder + +WORKDIR /app + +COPY package.json package-lock.json ./ +RUN npm ci --no-audit --no-fund + +COPY . . + +ARG VITE_API_BASE_URL +ENV VITE_API_BASE_URL=${VITE_API_BASE_URL} + +RUN npm run build + +# ============================================================ +# Stage 2: runtime +# ============================================================ +FROM docker.io/library/nginx:1.27-alpine + +LABEL org.opencontainers.image.title="datahub-frontend" \ + org.opencontainers.image.vendor="WPIC" \ + org.opencontainers.image.licenses="MIT" \ + org.opencontainers.image.source="https://192.168.30.181:3000/wpic-dev/datahub" + +ARG TIMEZONE=Asia/Shanghai +ENV TIMEZONE=${TIMEZONE} + +RUN apk add --no-cache tzdata && \ + ln -sf /usr/share/zoneinfo/${TIMEZONE} /etc/localtime && \ + echo "${TIMEZONE}" > /etc/timezone + +COPY --from=builder /app/dist /usr/share/nginx/html +COPY nginx.conf /etc/nginx/conf.d/default.conf + +EXPOSE 80 + +HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \ + CMD wget -qO- http://127.0.0.1/ -O /dev/null || exit 1 diff --git a/frontend/e2e/smoke.spec.ts b/frontend/e2e/smoke.spec.ts new file mode 100644 index 0000000..a73a41a --- /dev/null +++ b/frontend/e2e/smoke.spec.ts @@ -0,0 +1,15 @@ +import { test, expect } from '@playwright/test' + +test('homepage loads and SPA bootstraps', async ({ page }) => { + const response = await page.goto('/') + expect(response, 'page.goto should return a response').not.toBeNull() + expect(response!.status(), 'response status < 500').toBeLessThan(500) + + await page.waitForLoadState('domcontentloaded') + + const title = await page.title() + expect(title.length, 'page title is non-empty').toBeGreaterThan(0) + + const appRoot = page.locator('#app') + await expect(appRoot, '#app root mounts').toBeAttached() +}) diff --git a/frontend/e2e/vue.spec.ts b/frontend/e2e/vue.spec.ts deleted file mode 100644 index fc116a9..0000000 --- a/frontend/e2e/vue.spec.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { test, expect } from '@playwright/test'; - -// See here how to get started: -// https://playwright.dev/docs/intro -test('visits the app root url', async ({ page }) => { - await page.goto('/'); - await expect(page.locator('h1')).toHaveText('You did it!'); -}) diff --git a/frontend/nginx.conf b/frontend/nginx.conf new file mode 100644 index 0000000..cf129af --- /dev/null +++ b/frontend/nginx.conf @@ -0,0 +1,36 @@ +server { + listen 80; + server_name _; + + root /usr/share/nginx/html; + index index.html; + + gzip on; + gzip_types text/plain text/css application/json application/javascript + text/xml application/xml application/xml+rss text/javascript + image/svg+xml; + gzip_min_length 1024; + + # API 反代到 backend Swoole HTTP server + # 依赖 datahub.network + ContainerName=datahub-backend (Round 06 quadlet 落实) + location /api/ { + proxy_pass http://datahub-backend:9501; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 60s; + proxy_connect_timeout 10s; + } + + location ~* \.(?:css|js|woff2?|ttf|eot|svg|png|jpg|jpeg|gif|ico|webp)$ { + expires 7d; + add_header Cache-Control "public, immutable"; + try_files $uri =404; + } + + location / { + try_files $uri $uri/ /index.html; + } +} diff --git a/frontend/package.json b/frontend/package.json index 97f32fd..40bd699 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -28,7 +28,7 @@ "vue-router": "^4.6.3" }, "devDependencies": { - "@playwright/test": "^1.56.1", + "@playwright/test": "~1.50.0", "@tsconfig/node22": "^22.0.2", "@types/jsdom": "^27.0.0", "@types/node": "^22.18.11",