Quellcode durchsuchen

add check-next-symlinks.sh

Yuki Takei vor 1 Monat
Ursprung
Commit
1df2519832

+ 3 - 0
.github/workflows/reusable-app-prod.yml

@@ -60,6 +60,9 @@ jobs:
     - name: Assemble production artifacts
       run: bash apps/app/bin/assemble-prod.sh
 
+    - name: Check for broken symlinks in .next/node_modules
+      run: bash apps/app/bin/check-next-symlinks.sh
+
     - name: Archive production files
       id: archive-prod-files
       run: |

+ 9 - 31
apps/app/.claude/rules/package-dependencies.md

@@ -47,12 +47,9 @@ These were successfully removed from production artifact by eliminating their SS
 
 ## Verifying the Production Artifact
 
-Use the lightest check that fits the situation.
+### Level 1 — Externalisation check (30–60 s, local, incremental)
 
-### Level 1 — Externalisation check (30–60 s, incremental)
-
-Just want to know if a package gets externalised by Turbopack? Only a build is needed.
-`assemble-prod.sh` and server startup are not required.
+Just want to know if a package gets externalised by Turbopack?
 
 ```bash
 turbo run build --filter @growi/app
@@ -63,34 +60,15 @@ ls apps/app/.next/node_modules/ | grep <package-name>
 
 Turbopack build is incremental via cache, so subsequent runs after the first are fast.
 
-### Level 2 — Symlink integrity check (adds ~30 s)
-
-Want to confirm all `.next/node_modules/` symlinks resolve (no broken links)?
-
-```bash
-bash apps/app/bin/assemble-prod.sh
-
-cd apps/app && find .next/node_modules -maxdepth 2 -type l | while read link; do
-  linkdir=$(dirname "$link"); target=$(readlink "$link")
-  resolved=$(cd "$linkdir" 2>/dev/null && realpath -m "$target" 2>/dev/null || echo "UNRESOLVABLE")
-  { [ "$resolved" = "UNRESOLVABLE" ] || [ ! -e "$resolved" ]; } && echo "BROKEN: $link"
-done
-# Zero output (except fslightbox-react which is intentionally broken but harmless)
+### Level 2 — CI (`reusable-app-prod.yml`, authoritative)
 
-git show HEAD:apps/app/next.config.ts > apps/app/next.config.ts
-```
+Trigger via `workflow_dispatch` before merging. Runs two jobs:
 
-### Level 3 — Full server smoke test (adds ~60 s, for release gate only)
+1. **`build-prod`**: `turbo run build` → `assemble-prod.sh` → **`check-next-symlinks.sh`** → archives production tarball
+2. **`launch-prod`**: extracts the tarball into a clean isolated directory (no workspace-root `node_modules`), runs `pnpm run server:ci`
 
-```bash
-# assemble-prod.sh already run in Level 2; do NOT restore next.config.ts yet
-cd apps/app && pnpm run server > /tmp/server.log 2>&1 &
-timeout 90 bash -c 'until grep -q "Express server is listening" /tmp/server.log; do sleep 2; done'
+`check-next-symlinks.sh` scans every symlink in `.next/node_modules/` and fails the build if any are broken (except `fslightbox-react` which is intentionally broken but harmless). This catches classification errors regardless of which code paths are exercised at runtime.
 
-# Use / not /login — /login returns 200 even when SSR is broken
-curl -s -o /tmp/res.html -w "%{http_code}" http://localhost:3000/
-grep -c "ERR_MODULE_NOT_FOUND" /tmp/server.log  # must be 0
+`server:ci` = `node dist/server/app.js --ci`: the server starts fully (loading all modules), then immediately exits with code 0. If any module fails to load (`ERR_MODULE_NOT_FOUND`), the process exits with code 1, failing the CI job.
 
-kill $(lsof -ti:3000)
-git show HEAD:apps/app/next.config.ts > apps/app/next.config.ts
-```
+This exactly matches Docker production (no workspace fallback). A `build-prod` or `launch-prod` failure definitively means a missing `dependencies` entry.

+ 23 - 0
apps/app/bin/check-next-symlinks.sh

@@ -0,0 +1,23 @@
+#!/bin/bash
+# Check that all .next/node_modules/ symlinks resolve correctly after assemble-prod.sh.
+# fslightbox-react is intentionally broken (useEffect-only import, never accessed during SSR).
+# Usage: bash apps/app/bin/check-next-symlinks.sh (from monorepo root)
+set -euo pipefail
+
+NEXT_MODULES="apps/app/.next/node_modules"
+
+broken=$(find "$NEXT_MODULES" -maxdepth 2 -type l | while read -r link; do
+  linkdir=$(dirname "$link")
+  target=$(readlink "$link")
+  resolved=$(cd "$linkdir" 2>/dev/null && realpath -m "$target" 2>/dev/null || echo "UNRESOLVABLE")
+  { [ "$resolved" = "UNRESOLVABLE" ] || [ ! -e "$resolved" ]; } && echo "BROKEN: $link"
+done | grep -v 'fslightbox-react' || true)
+
+if [ -n "$broken" ]; then
+  echo "ERROR: Broken symlinks found in $NEXT_MODULES:"
+  echo "$broken"
+  echo "Move these packages from devDependencies to dependencies in apps/app/package.json."
+  exit 1
+fi
+
+echo "OK: All $NEXT_MODULES symlinks resolve correctly."