Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FROM library/node:lts-bookworm

ARG DEBIAN_FRONTEND=noninteractive
RUN apt update \
&& apt install -y --no-install-recommends sudo \
&& apt autoremove -y \
&& rm -rf /var/lib/apt/lists/* \
&& echo "node ALL=(ALL) NOPASSWD: ALL" >/etc/sudoers.d/node \
&& chmod 0440 /etc/sudoers.d/node
20 changes: 20 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "SonicJS Dev",
"build": { "dockerfile": "Dockerfile" },
"forwardPorts": [9115],
"remoteUser": "node",
"mounts": [
"source=sonicjs-node_modules,target=/IdeaProjects/sonicjs/node_modules,type=volume",
"source=sonicjs-core-node_modules,target=/IdeaProjects/sonicjs/packages/core/node_modules,type=volume",
"source=sonicjs-create-app-node_modules,target=/IdeaProjects/sonicjs/packages/create-app/node_modules,type=volume",
"source=sonicjs-stats-node_modules,target=/IdeaProjects/sonicjs/packages/stats/node_modules,type=volume",
"source=sonicjs-www-node_modules,target=/IdeaProjects/sonicjs/www/node_modules,type=volume",
"source=sonicjs-my-app-node_modules,target=/IdeaProjects/sonicjs/my-sonicjs-app/node_modules,type=volume"
],
"postCreateCommand": "bash .devcontainer/setup.sh",
"customizations" : {
"jetbrains" : {
"backend" : "WebStorm"
}
}
}
56 changes: 56 additions & 0 deletions .devcontainer/setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#!/usr/bin/env bash
set -euo pipefail

# Devcontainer postCreate bootstrap.
#
# Bind-mounted workspaces inherit the host's file ownership. If the checkout
# was created by a root process, npm (running here as the `node` user) fails
# with `EPERM: operation not permitted, chmod` when it links workspace `bin`
# files (e.g. packages/core/bin/db-reset.js). This script normalises ownership
# so `npm install` works in the container without touching anything that
# Conductor or other CI flows rely on.

# Allow git to read the mount even if `.git` is owned by root.
git config --global --add safe.directory '*' || true

# Locate the repo root regardless of where the workspace is mounted.
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || echo "$PWD")"

# Make the whole workspace writable/ownable by the container user.
if ! sudo chown -R node:node "$REPO_ROOT"; then
echo "WARNING: could not chown '$REPO_ROOT' to node:node —" \
"npm install may fail with EPERM on bin files" >&2
fi

# Install dependencies so the workspace is immediately runnable.
#
# `node_modules` lives on Linux-native Docker volumes (see `mounts` in
# devcontainer.json) so npm never reifies against the host bind mount. On
# Docker Desktop + WSL2 (and some other bind mounts), `npm install` fails
# transiently with `EACCES: permission denied, rename node_modules/caniuse-lite`
# during npm's reify phase — npm renames directories while rebuilding the tree,
# and the 9p/drvfs mount intermittently rejects the rename, especially when a
# second install (e.g. one triggered by the IDE) is reifying the same tree
# concurrently. Ownership is fine; the failure is non-deterministic.
#
# Run unconditionally: install is idempotent and fast when the tree is already
# up to date, and re-running repairs any partially-installed state that the
# bind-mount failures left behind.
install_with_retry() {
local attempts=4
local attempt=1
while true; do
if npm --prefix "$REPO_ROOT" install; then
return 0
fi
if (( attempt >= attempts )); then
echo "npm install failed after $attempts attempts" >&2
return 1
fi
echo "npm install failed (attempt $attempt/$attempts) — retrying..." >&2
sleep 3
attempt=$((attempt + 1))
done
}

install_with_retry
33 changes: 33 additions & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,3 +1,36 @@
#!/usr/bin/env sh

# Resolve npm even when PATH is minimal or comes from a host-side git that
# knows nothing about the devcontainer (node_modules + npm live inside the
# container, on Docker volumes). The container installs node at /usr/local/bin;
# nvm/fnm/asdf users have shims under $HOME.
resolve_npm() {
command -v npm >/dev/null 2>&1 && return 0
for dir in /usr/local/bin "$HOME/.local/bin" "$HOME/.nvm" "$HOME/.fnm" "$HOME/.asdf"; do
[ -x "$dir/npm" ] && { PATH="$dir:$PATH"; export PATH; return 0; }
for v in "$dir"/versions/node/*/bin; do
[ -x "$v/npm" ] && { PATH="$v:$PATH"; export PATH; return 0; }
done
done
return 1
}

if ! resolve_npm; then
echo "WARNING: 'npm' not found on PATH."
echo "This repo's checks run inside the devcontainer (npm/node_modules live on"
echo "Docker volumes). Commits made from the host cannot run lint/type-check, so"
echo "they are skipped here — CI enforces them on every push."
exit 0
fi

# Even when an npm binary exists, node_modules may still be hidden behind the
# container's Docker volumes from the host's point of view.
if [ ! -f "$(dirname "$0")/../node_modules/.package-lock.json" ]; then
echo "WARNING: node_modules is not installed in this environment."
echo "Skipping lint/type-check for this commit — CI enforces them on every push."
exit 0
fi

echo "Running linting..."
npm run lint --workspace=@sonicjs-cms/core

Expand Down
21 changes: 12 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,25 +141,28 @@ Your app includes:

### For Package Developers (Contributing to SonicJS)

```bash
# Clone this repository
git clone https://github.com/lane711/sonicjs.git
cd sonicjs
> Optionally, you can use our preconfigured [Devcontainer](https://containers.dev/) so the environment is identical
> for every local machine — no manual Node/Cloudflare setup required. You just need
> Docker and VS Code (or a JetBrains IDE with remote development support).

This sets up a development environment with all dependencies installed and ready to go.
To see your changes live, go to http://localhost:9115

```bash
# Install dependencies
npm install

# Build the core package
npm run build:core

# Create a test app to validate changes
npx create-sonicjs@latest my-sonicjs-app
# Prep the demo database
npm run db:reset

# Run tests
npm test
# Run the demo app
npm run dev # open http://localhost:9115/
```

#### Setting Up a Fresh Database
### Setting Up a Fresh Database

```bash
# Create a fresh D1 database for your branch (run from project root)
Expand Down