From 9104faf806fbc490f61c8223ab91de06781ae281 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Wed, 10 Jun 2026 09:28:25 -0400 Subject: [PATCH] fix frontend dev scripts (#1625) --- frontend/README.md | 125 +++++++++++++++------ frontend/package-lock.json | 39 +------ script/artcraft/unix_frontend_dev.sh | 5 +- script/common/frontend_preflight.sh | 86 ++++++++++++++ script/website/unix_frontend_dev.sh | 5 +- script/website/unix_frontend_webapp_dev.sh | 5 +- 6 files changed, 189 insertions(+), 76 deletions(-) create mode 100755 script/common/frontend_preflight.sh diff --git a/frontend/README.md b/frontend/README.md index 6b80709653..cd38d0d3cb 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -2,7 +2,21 @@ This is an `nx` monorepo that can contain multiple apps and shared libraries. -All commands to run these projects are performed from _this_ directory. +All commands to run these projects are performed from _this_ directory +(except the repo-root launcher scripts noted below). + +## Requirements + +- **Node.js 20+** (Nx 21 / Vite 6 requirement). Install via [nvm](https://github.com/nvm-sh/nvm), + [nodejs.org](https://nodejs.org), or `brew install node`. +- **npm** (ships with Node). + +> **We use npm, not pnpm.** pnpm was briefly adopted ("add pnpm to solve build +> issues") and later removed ("fix(frontend): consume video-editor libs via nx +> path aliases, drop pnpm"). If you have leftovers from that era — a +> `pnpm-lock.yaml`, `pnpm-workspace.yaml`, or a `node_modules/.pnpm` directory — +> npm installs will fail (typically with `ENOTEMPTY` rename errors). See +> Troubleshooting below. ## Install dependencies @@ -10,58 +24,95 @@ All commands to run these projects are performed from _this_ directory. npm install ``` -## Editor2d +## Running the apps in dev mode -Run dev server: +From the **repository root**, the launcher scripts (these preflight your +environment, install dependencies, and free the dev port first): ```bash +./script/website/unix_frontend_dev.sh # artcraft-website (marketing site), port 4200 +./script/website/unix_frontend_webapp_dev.sh # artcraft-webapp (user dashboard), port 4201 +./script/artcraft/unix_frontend_dev.sh # artcraft (Tauri app frontend), port 5173 +``` + +Or directly from this directory: + +```bash +nx dev artcraft-website +nx dev artcraft-webapp +nx dev artcraft # NB: the Tauri app also needs the Rust dev server running nx dev editor2d ``` -## artcraft - -Run dev server: +## Building ```bash -nx dev artcraft -``` - -``` -call when starting on main or a new branch: -./clean_modules - -The names for @frontend and @storyteller come from the package.json file in the libs folder. -import { Login } from "@frontend/login"; -import { api } from "@storyteller/api"; - -For shared UI components, import from @storyteller/ui-[componentname]. -import { Button } from "@storyteller/ui-button"; -import { Modal } from "@storyteller/ui-modal"; - -building: +npx nx build artcraft-website +npx nx build artcraft-webapp npx nx build artcraft npx nx build editor2d +``` -dev: -npx nx dev artcraft -npx nx dev editor2d +Netlify deploys run `apps//script/netlify_build.sh` (see each app's +`netlify.toml`). +## Troubleshooting +### `npm install` fails with `ENOTEMPTY: directory not empty, rename ...` -# component build -1. +Your `node_modules` tree is corrupted — usually an interrupted install, or a +tree written by pnpm back when the repo briefly used it. Fix: + +```bash +./clean_modules.sh +npm install +``` + +Or the manual minimum: + +```bash +rm -rf node_modules .nx pnpm-lock.yaml pnpm-workspace.yaml +npm install +``` + +### Stale build state after switching branches + +Call this when starting on main or a new branch: + +```bash +./clean_modules.sh +``` + +It removes all `dist/` outputs, resets the nx cache, and removes +`node_modules`. + +## Import aliases + +The names for `@frontend` and `@storyteller` come from the `package.json` file +in the libs folder: + +```ts +import { Login } from "@frontend/login"; +import { api } from "@storyteller/api"; +``` + +For shared UI components, import from `@storyteller/ui-[componentname]`: + +```ts +import { Button } from "@storyteller/ui-button"; +import { Modal } from "@storyteller/ui-modal"; +``` + +## Generating a new component library + +```bash +# 1. Generate the library npx nx g @nx/react:library libs/components/toaster --import-path=@storyteller/ui-toaster --bundler=vite npm install -2.import it first in code -3.nx sync -4.nx build -or +# 2. Import it somewhere in code -# frontend build -in frontend folder - -% nx build -project type -% nx build artcraft -% nx dev artcraft +# 3. Sync and build +nx sync +nx build ``` diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 67e41fc641..8444f2db3e 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -3066,6 +3066,7 @@ "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.0.tgz", "integrity": "sha512-l9Oo58x0HOP5znGzVhYW9U3e5wVuA4LAZU2AGezTmkhO1CgQRFDhDg4nneHsu/t3WniXg9QrG2nIXL/ZS8ln8Q==", "license": "MIT", + "peer": true, "dependencies": { "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" @@ -3076,6 +3077,7 @@ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.0.tgz", "integrity": "sha512-55coeOFKHv1ywEcUXJtWU5f+Jr/W5tZDvZig8DLKSwUN1JpROQ4rk/SNOQiFWmaR/VKF4zuFyW1B8JduOSv6Pg==", "license": "MIT", + "peer": true, "dependencies": { "tslib": "^2.4.0" } @@ -13370,42 +13372,6 @@ "node": ">=14.0.0" } }, - "node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@emnapi/core": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", - "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.1", - "tslib": "^2.4.0" - } - }, - "node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@emnapi/runtime": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", - "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@emnapi/wasi-threads": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", - "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", @@ -27290,6 +27256,7 @@ "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "whatwg-url": "^5.0.0" }, diff --git a/script/artcraft/unix_frontend_dev.sh b/script/artcraft/unix_frontend_dev.sh index 7bd0cd6e82..e7df48ceca 100755 --- a/script/artcraft/unix_frontend_dev.sh +++ b/script/artcraft/unix_frontend_dev.sh @@ -4,6 +4,9 @@ root_dir=$(pwd) frontend_path="${root_dir}/frontend" +source "${root_dir}/script/common/frontend_preflight.sh" +frontend_preflight "${frontend_path}" + echo "Running Artcraft Frontend in Dev Mode..." echo "" @@ -20,7 +23,7 @@ fi pushd "${frontend_path}" || exit -npm install --verbose +frontend_npm_install export VITE_ENVIRONMENT_TYPE="production" diff --git a/script/common/frontend_preflight.sh b/script/common/frontend_preflight.sh new file mode 100755 index 0000000000..a260e5940b --- /dev/null +++ b/script/common/frontend_preflight.sh @@ -0,0 +1,86 @@ +#!/usr/bin/env bash +# Shared preflight checks for the frontend dev/build scripts. +# +# Usage (from a script that has set ${frontend_path}): +# +# source "${root_dir}/script/common/frontend_preflight.sh" +# frontend_preflight "${frontend_path}" +# ... +# pushd "${frontend_path}" +# frontend_npm_install +# + +# Node 20+ is required by Nx 21 and comfortably covers Vite 6. +FRONTEND_MINIMUM_NODE_MAJOR=20 + +frontend_preflight() { + local frontend_path="$1" + + if [ ! -d "${frontend_path}" ]; then + echo "ERROR: frontend directory not found at: ${frontend_path}" + echo "Run this script from the repository root." + exit 1 + fi + + # --- Node and npm must be installed --- + if ! command -v node &>/dev/null; then + echo "ERROR: node is not installed (or not on PATH)." + echo "Install Node.js ${FRONTEND_MINIMUM_NODE_MAJOR}+ via nvm (https://github.com/nvm-sh/nvm)," + echo "https://nodejs.org, or:" + echo " brew install node" + exit 1 + fi + + if ! command -v npm &>/dev/null; then + echo "ERROR: npm is not installed (or not on PATH). It normally ships with Node.js." + echo "Reinstall Node.js to get it back." + exit 1 + fi + + # --- Node must be recent enough for Nx 21 / Vite 6 --- + local node_major + node_major=$(node --version | sed -E 's/^v([0-9]+).*/\1/') + if [ "${node_major}" -lt "${FRONTEND_MINIMUM_NODE_MAJOR}" ]; then + echo "ERROR: Node.js ${FRONTEND_MINIMUM_NODE_MAJOR}+ is required (found $(node --version))." + echo "Upgrade via nvm ('nvm install --lts') or https://nodejs.org." + exit 1 + fi + + # --- The frontend uses npm; stale pnpm state breaks installs --- + # pnpm was briefly adopted ("add pnpm to solve build issues") and then dropped + # ("fix(frontend): consume video-editor libs via nx path aliases, drop pnpm"). + # A node_modules tree written by pnpm makes npm fail with ENOTEMPTY errors. + if [ -e "${frontend_path}/pnpm-lock.yaml" ] \ + || [ -e "${frontend_path}/pnpm-workspace.yaml" ] \ + || [ -d "${frontend_path}/node_modules/.pnpm" ]; then + echo "ERROR: Stale pnpm artifacts detected in ${frontend_path}." + echo "The frontend uses npm (pnpm was dropped; see frontend/README.md)." + echo "Clean up with:" + echo " cd ${frontend_path} && rm -rf node_modules pnpm-lock.yaml pnpm-workspace.yaml && npm install" + exit 1 + fi +} + +# Run `npm install` in the current directory. If it fails (typically from a +# corrupted node_modules tree, eg. an interrupted install or a leftover pnpm +# layout causing ENOTEMPTY rename errors), wipe node_modules and the nx cache +# and retry once before giving up. +frontend_npm_install() { + if npm install; then + return 0 + fi + + echo "" + echo "WARNING: npm install failed. node_modules may be corrupted (eg. an" + echo "interrupted install or a mixed npm/pnpm tree). Wiping and retrying..." + echo "" + + rm -rf node_modules .nx + + if ! npm install; then + echo "" + echo "ERROR: npm install failed again. See the npm output above and the" + echo "troubleshooting section in frontend/README.md." + exit 1 + fi +} diff --git a/script/website/unix_frontend_dev.sh b/script/website/unix_frontend_dev.sh index 93796f2833..c3e15d468e 100755 --- a/script/website/unix_frontend_dev.sh +++ b/script/website/unix_frontend_dev.sh @@ -4,6 +4,9 @@ root_dir=$(pwd) frontend_path="${root_dir}/frontend" +source "${root_dir}/script/common/frontend_preflight.sh" +frontend_preflight "${frontend_path}" + echo "Running Artcraft Website in Dev Mode..." echo "" @@ -17,7 +20,7 @@ fi pushd "${frontend_path}" || exit -npm install --verbose +frontend_npm_install export VITE_ENVIRONMENT_TYPE="production" diff --git a/script/website/unix_frontend_webapp_dev.sh b/script/website/unix_frontend_webapp_dev.sh index 8b44b5d25d..911814c8aa 100755 --- a/script/website/unix_frontend_webapp_dev.sh +++ b/script/website/unix_frontend_webapp_dev.sh @@ -4,6 +4,9 @@ root_dir=$(pwd) frontend_path="${root_dir}/frontend" +source "${root_dir}/script/common/frontend_preflight.sh" +frontend_preflight "${frontend_path}" + echo "Running Artcraft Webapp in Dev Mode..." echo "" @@ -17,7 +20,7 @@ fi pushd "${frontend_path}" || exit -npm install --verbose +frontend_npm_install export VITE_ENVIRONMENT_TYPE="production"