2 files changed
+44
-8
.agents/skills/smbcloud-deploy-nextjs/SKILL.md
+16
-4
@@ -310,6 +310,13 @@ Fix:
310
311
### `Cannot find module 'styled-jsx'`, `@swc/helpers`, or other pnpm peer deps
312
313
+A common concrete failure looks like:
314
+
315
+- `code: 'MODULE_NOT_FOUND'`
316
+- `path: '/home/git/apps/web/<app>/node_modules/@swc/helpers'`
317
+
318
+That usually means the standalone upload succeeded, but the top-level hoisted symlink for a scoped package was not recreated on the server.
319
+
320
Cause:
321
322
- pnpm stores peer dependencies inside `node_modules/.pnpm/<pkg>@<version>/node_modules/<pkg>` with internal symlinks that Node's standard `require.resolve()` cannot follow
@@ -318,10 +325,15 @@ Cause:
325
326
Fix:
327
321
-- the CLI deploy script now auto-hoists: after uploading standalone output, it scans `node_modules/.pnpm/*/node_modules/*` and creates symlinks at `node_modules/<pkg>` for any packages not already present
322
-- this restores the resolution structure that pnpm normally provides via its `.pnpm/node_modules/` virtual directory
323
-- no manual intervention needed for new deploys
324
-- to fix a server manually: `find node_modules/.pnpm -mindepth 2 -maxdepth 2 -type d -name node_modules` and symlink each child into the root `node_modules/`
328
+- the CLI deploy script now auto-hoists in two passes:
329
+ - first mirror pnpm's virtual directory at `node_modules/.pnpm/node_modules/*`
330
+ - then fall back to scanning `node_modules/.pnpm/*/node_modules/*` for anything still missing
331
+- this preserves pnpm's exact resolved package choice and fixes scoped packages like `@swc/helpers` as well as unscoped ones like `styled-jsx`
332
+- no manual intervention needed for new deploys once the updated CLI is used
333
+- to fix a server manually, prefer pnpm's virtual directory as the source of truth:
334
+ - create `node_modules/@scope/` directories as needed
335
+ - symlink `node_modules/<pkg>` or `node_modules/@scope/<pkg>` to the corresponding entry under `node_modules/.pnpm/node_modules/`
336
+ - only if that directory is missing, scan individual `.pnpm/<store-entry>/node_modules/*` folders as a fallback
337
338
### Wrong port after deploy
339
crates/cli/src/deploy/process_deploy_nextjs_ssr.rs
+28
-4
@@ -456,9 +456,30 @@ ECOSYSTEM_EOF
456
457
# pnpm standalone output buries peer deps inside node_modules/.pnpm/
458
# without the top-level symlinks Node needs for require.resolve().
459
- # Scan the .pnpm store and create flat symlinks. For scoped packages,
460
- # always force-replace partial rsync copies with symlinks to the .pnpm
461
- # store entry that has the most content (not just package.json).
459
+ # First mirror pnpm's own virtual node_modules directory when it exists —
460
+ # this preserves the exact version selection pnpm already resolved, which is
461
+ # especially important for scoped packages like @swc/helpers.
462
+ # Then fall back to scanning individual .pnpm store entries for anything the
463
+ # virtual directory did not expose.
464
+ if [ -d "node_modules/.pnpm/node_modules" ]; then
465
+ for pkg_path in node_modules/.pnpm/node_modules/*; do
466
+ [ -e "$pkg_path" ] || continue
467
+ pkg_name=$(basename "$pkg_path")
468
+ if [ "${{pkg_name:0:1}}" = "@" ] && [ -d "$pkg_path" ]; then
469
+ mkdir -p "node_modules/$pkg_name"
470
+ for sub_path in "$pkg_path"/*; do
471
+ [ -e "$sub_path" ] || continue
472
+ sub_name=$(basename "$sub_path")
473
+ rm -rf "node_modules/$pkg_name/$sub_name"
474
+ ln -sfn "$APP_PATH/$sub_path" "node_modules/$pkg_name/$sub_name"
475
+ done
476
+ else
477
+ rm -rf "node_modules/$pkg_name"
478
+ ln -sfn "$APP_PATH/$pkg_path" "node_modules/$pkg_name"
479
+ fi
480
+ done
481
+ fi
482
+
483
if [ -d "node_modules/.pnpm" ]; then
484
find node_modules/.pnpm -mindepth 2 -maxdepth 2 -type d -name "node_modules" 2>/dev/null | while read pnpm_nm; do
485
for pkg_path in "$pnpm_nm"/*; do
@@ -484,7 +505,10 @@ ECOSYSTEM_EOF
505
fi
506
done
507
else
487
- [ -e "node_modules/$pkg_name" ] || ln -sfn "$APP_PATH/$pkg_path" "node_modules/$pkg_name"
508
+ if [ -e "node_modules/$pkg_name" ]; then
509
+ continue
510
+ fi
511
+ ln -sfn "$APP_PATH/$pkg_path" "node_modules/$pkg_name"
512
fi
513
done
514
done