mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-19 13:21:46 +00:00
chore: fix monorepo build pipeline and migrate shared to built package (#1056)
* chore: fix monorepo build pipeline and migrate shared to built package
- Root package.json: add workspace scripts (dev, build, test, test:cov, test:e2e)
that delegate to actual scripts in shared/server/client workspaces
- shared: add tsup build step (CJS + ESM dual output, .d.ts); consumers now import
from the built dist instead of raw TS source via path aliases
- server: replace tsc-alias with tsconfig-paths (tsc-alias mangled node_modules
paths); fix MCP SDK path aliases to point to root node_modules (../node_modules)
- server/scripts/dev.mjs: delay node --watch until tsc -w signals first-pass done,
eliminating the spurious restart on every dev startup
- client/vite.config.js + vitest.config.ts: remove @trek/shared path alias (no longer
needed now that shared is a proper package)
- Consolidate package-lock.json at the workspace root; drop per-workspace lock files
* chore: fix test script to reflect root package.json
* chore: add missing lint and prettier script in root package.json
* fix(ci): build shared before tests; fix vitest MCP SDK alias paths
vitest.config.ts aliases pointed at ./node_modules/ (server-local) but
packages are hoisted to the root node_modules/ in the npm workspace —
changed to ../node_modules/.
CI jobs now install and build shared before running server/client tests
so that @trek/shared's dist/ exists when vitest resolves the package.
* fix(docker): update Dockerfile and CI for monorepo workspace structure
Dockerfile:
- Add shared-builder stage that produces @trek/shared dist before
client and server stages need it
- Each build stage carries root package.json + package-lock.json so npm
can resolve @trek/shared as a workspace dependency
- Production stage installs via workspace context (npm ci --workspace=server
--omit=dev) so node_modules/@trek/shared symlinks to shared/dist correctly
- Copy server/tsconfig.json into the image so tsconfig-paths/register can
find the MCP SDK path aliases at runtime
- CMD cds into /app/server before starting node so tsconfig-paths baseUrl
resolves and ../node_modules points to /app/node_modules
- Remove mkdir for /app/server (now a real dir); keep symlinks for uploads/data
docker.yml version-bump:
- Replace manual per-workspace cd+npm-version calls with single:
npm version --workspaces --include-workspace-root --no-git-tag-version
(mirrors the version:* scripts in root package.json)
- git add now references root package-lock.json; adds shared/package.json
.dockerignore: add shared/dist
package.json: fix version:prerelease preid (alpha → pre)
* fix(tests): use in-memory SQLite per worker in test mode
vitest pool:forks spawns parallel worker processes that all called
initDb() on the same data/travel.db, causing SQLite "database is locked"
and "duplicate column name" races.
When NODE_ENV=test each fork now gets an isolated :memory: DB so migrations
run independently with no file contention.
* chore(ci): add ACT guards to skip DockerHub steps in local act runs
act sets ACT=true automatically. Guards added:
- docker login: if: ${{ !env.ACT }}
- build outputs: type=docker (local load) when ACT, push-by-digest when CI
- digest export/upload: if: ${{ !env.ACT }}
- merge job: if: ${{ !env.ACT }}
- release-helm job (docker.yml): if: ${{ !env.ACT }}
- version-bump git push (docker.yml): wrapped in [ -z "$ACT" ] shell guard
Run locally with:
./bin/act -j build -W .github/workflows/docker.yml \
-P ubuntu-latest=catthehacker/ubuntu:act-latest
* fix(ci): move ACT guards to step level; add guards to security.yml
env context is invalid in job-level if conditions — moved all ACT
guards down to individual steps. Also guards docker login + scout
in security.yml so act can run the build-only part of that workflow.
* fix(ci): skip git fetch and tag logic in act (no remote access in local containers)
* Revert "fix(ci): skip git fetch and tag logic in act (no remote access in local containers)"
This reverts commit 67cf290cda.
* Revert "fix(ci): move ACT guards to step level; add guards to security.yml"
This reverts commit f92b95e054.
* Revert "chore(ci): add ACT guards to skip DockerHub steps in local act runs"
This reverts commit 797183de08.
* fix(docker): add musl optional deps so alpine builds find native rollup/sharp binaries
npm prunes libc-constrained optional deps to the host libc (glibc) when
generating the lockfile, leaving no musl entry for Alpine containers.
Declaring the x64/arm64 musl variants as explicit root optionalDependencies
forces them into the lockfile so npm ci on Alpine can install them.
Covers shared-builder (tsup/rollup) and client-builder (vite/rollup + sharp
icon generation) for both linux/amd64 and linux/arm64 CI targets.
* fix(docker): copy client dist into server/public so the server resolves static files correctly
The server runs from /app/server and serves static files relative to that
directory, so the client build output must land at /app/server/public, not /app/public.
This commit is contained in:
+46
-26
@@ -1,41 +1,60 @@
|
||||
# Stage 1: Build React client
|
||||
FROM node:24-alpine AS client-builder
|
||||
WORKDIR /app/client
|
||||
COPY client/package*.json ./
|
||||
RUN npm ci
|
||||
COPY client/ ./
|
||||
RUN npm run build
|
||||
# ── Stage 1: shared ──────────────────────────────────────────────────────────
|
||||
FROM node:24-alpine AS shared-builder
|
||||
WORKDIR /app
|
||||
COPY package.json package-lock.json ./
|
||||
COPY shared/package.json ./shared/
|
||||
RUN npm ci --workspace=shared
|
||||
COPY shared/ ./shared/
|
||||
RUN npm run build --workspace=shared
|
||||
|
||||
# Stage 2: Build server (TypeScript -> dist via tsc + tsc-alias)
|
||||
# --ignore-scripts: tsc only transpiles, so we skip native builds (better-sqlite3)
|
||||
# here; the production stage builds the native module.
|
||||
# ── Stage 2: client ──────────────────────────────────────────────────────────
|
||||
FROM node:24-alpine AS client-builder
|
||||
WORKDIR /app
|
||||
COPY package.json package-lock.json ./
|
||||
COPY shared/package.json ./shared/
|
||||
COPY client/package.json ./client/
|
||||
RUN npm ci --workspace=client
|
||||
COPY --from=shared-builder /app/shared/dist ./shared/dist
|
||||
COPY client/ ./client/
|
||||
RUN npm run build --workspace=client
|
||||
|
||||
# ── Stage 3: server ──────────────────────────────────────────────────────────
|
||||
# --ignore-scripts skips native builds (better-sqlite3); they happen in the production stage.
|
||||
FROM node:24-alpine AS server-builder
|
||||
WORKDIR /app
|
||||
COPY server/package*.json ./
|
||||
RUN npm ci --ignore-scripts
|
||||
COPY server/ ./
|
||||
RUN npm run build
|
||||
COPY package.json package-lock.json ./
|
||||
COPY shared/package.json ./shared/
|
||||
COPY server/package.json ./server/
|
||||
RUN npm ci --workspace=server --ignore-scripts
|
||||
COPY --from=shared-builder /app/shared/dist ./shared/dist
|
||||
COPY server/ ./server/
|
||||
RUN npm run build --workspace=server
|
||||
|
||||
# Stage 3: Production server (runs the compiled JS — NestJS DI needs the
|
||||
# decorator metadata that tsc emits; the old tsx runtime did not).
|
||||
# ── Stage 4: production runtime ──────────────────────────────────────────────
|
||||
FROM node:24-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Timezone support + native deps (better-sqlite3 needs build tools)
|
||||
COPY server/package*.json ./
|
||||
# Workspace manifests only — source never enters this stage.
|
||||
COPY package.json package-lock.json ./
|
||||
COPY shared/package.json ./shared/
|
||||
COPY server/package.json ./server/
|
||||
|
||||
# better-sqlite3 native addon requires build tools; purged after install.
|
||||
RUN apk add --no-cache tzdata dumb-init su-exec python3 make g++ && \
|
||||
npm ci --production && \
|
||||
rm package-lock.json && \
|
||||
npm ci --workspace=server --omit=dev && \
|
||||
apk del python3 make g++ && \
|
||||
rm -rf /usr/local/lib/node_modules/npm /usr/local/bin/npm /usr/local/bin/npx
|
||||
|
||||
COPY --from=server-builder /app/dist ./dist
|
||||
COPY --from=client-builder /app/client/dist ./public
|
||||
COPY --from=client-builder /app/client/public/fonts ./public/fonts
|
||||
COPY --from=server-builder /app/server/dist ./server/dist
|
||||
# tsconfig-paths/register reads this at runtime to resolve MCP SDK paths.
|
||||
COPY server/tsconfig.json ./server/
|
||||
COPY --from=shared-builder /app/shared/dist ./shared/dist
|
||||
COPY --from=client-builder /app/client/dist ./server/public
|
||||
COPY --from=client-builder /app/client/public/fonts ./server/public/fonts
|
||||
|
||||
RUN mkdir -p /app/data/logs /app/uploads/files /app/uploads/covers /app/uploads/avatars /app/uploads/photos && \
|
||||
mkdir -p /app/server && ln -s /app/uploads /app/server/uploads && ln -s /app/data /app/server/data && \
|
||||
ln -s /app/uploads /app/server/uploads && \
|
||||
ln -s /app/data /app/server/data && \
|
||||
chown -R node:node /app
|
||||
|
||||
ENV NODE_ENV=production
|
||||
@@ -49,4 +68,5 @@ HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
|
||||
CMD wget -qO- http://localhost:3000/api/health || exit 1
|
||||
|
||||
ENTRYPOINT ["dumb-init", "--"]
|
||||
CMD ["sh", "-c", "chown -R node:node /app/data /app/uploads 2>/dev/null || true; exec su-exec node node dist/index.js"]
|
||||
# cd into server/ so tsconfig-paths/register finds tsconfig.json and ../node_modules resolves correctly.
|
||||
CMD ["sh", "-c", "chown -R node:node /app/data /app/uploads 2>/dev/null || true; cd /app/server && exec su-exec node node --require tsconfig-paths/register dist/index.js"]
|
||||
|
||||
Reference in New Issue
Block a user