From 189387dc3d987acfc72e015c8e874c088be5681e Mon Sep 17 00:00:00 2001 From: Abhishek Krishna Date: Tue, 26 May 2026 10:13:48 +0530 Subject: [PATCH] fix(deploy): write .next/static to standalone/.next/static, not standalone/web/.next/static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit server.js does `process.chdir(__dirname)` where __dirname is the standalone root, then resolves static assets from `./.next/static`. The previous script mirrored the source layout (web/.next/static), which silently broke every /_next/static/* request — homepage HTML rendered but with no CSS and no client JS. Verified on prod: with the corrected path, /_next/static/css/*.css returns 200 and the homepage renders fully styled. --- deploy/README.md | 4 ++-- deploy/deploy.sh | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/deploy/README.md b/deploy/README.md index e48b7276..ef2a5618 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -11,7 +11,7 @@ deploys are triggered by SSHing into the VPS and running this script. | `/opt/muzix/` | Git checkout of `kcolbchain/muzix` (the `main` branch is prod) | | `/opt/muzix/web/.next/standalone/` | Next.js standalone build (`server.js`) — what systemd runs | | `/opt/muzix/web/.next/standalone/public/` | **Hand-wired** — Next.js does not copy `public/` into standalone output | -| `/opt/muzix/web/.next/standalone/web/.next/static/` | **Hand-wired** — Next.js does not copy `.next/static` into standalone output | +| `/opt/muzix/web/.next/standalone/.next/static/` | **Hand-wired** — Next.js does not copy `.next/static` into standalone output. Note: this lives at `standalone/.next/static`, **not** `standalone/web/.next/static` — the source dir-layout is misleading. | | `/etc/systemd/system/muzix-web.service` | systemd unit — `node /opt/muzix/web/.next/standalone/server.js` on `127.0.0.1:3700` | | `/etc/caddy/conf.d/muzix.caddy` | Caddy reverse-proxy to `127.0.0.1:3700` | @@ -26,7 +26,7 @@ The script: 1. `git fetch && git reset --hard origin/main` in `/opt/muzix` 2. `npm install` + `npm run build` in `/opt/muzix/web` 3. Copies `web/public/` → `web/.next/standalone/public/` -4. Copies `web/.next/static/` → `web/.next/standalone/web/.next/static/` +4. Copies `web/.next/static/` → `web/.next/standalone/.next/static/` 5. `systemctl restart muzix-web` 6. Verifies the service is active; on failure prints the last 30 journal lines and exits non-zero diff --git a/deploy/deploy.sh b/deploy/deploy.sh index 1b2fc528..541fa4f7 100755 --- a/deploy/deploy.sh +++ b/deploy/deploy.sh @@ -34,14 +34,19 @@ npm run build > /dev/null # Next.js standalone output does NOT copy these by design — the docs # explicitly tell you to wire them in for production. See: # https://nextjs.org/docs/app/api-reference/config/next-config-js/output +# Both destinations are RELATIVE TO THE STANDALONE ROOT — NOT under web/. +# server.js does process.chdir(__dirname) where __dirname is the standalone +# root, then looks for `./.next/static` and `./public`. Writing them under +# `standalone/web/.next/static` (a mirror of the source layout) is wrong: +# the homepage will render but every /_next/static/* request will 404, +# silently breaking all styling. echo "==> wiring public/ and .next/static into standalone..." rm -rf "$STANDALONE/public" mkdir -p "$STANDALONE/public" cp -r "$REPO/web/public/." "$STANDALONE/public/" -rm -rf "$STANDALONE/web/.next/static" -mkdir -p "$STANDALONE/web/.next" -cp -r "$REPO/web/.next/static" "$STANDALONE/web/.next/static" +rm -rf "$STANDALONE/.next/static" +cp -r "$REPO/web/.next/static" "$STANDALONE/.next/static" echo "==> systemctl restart ${SERVICE}..." sudo systemctl restart "$SERVICE"