Skip to content
Merged
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
26 changes: 16 additions & 10 deletions docker/app-dev.sh
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
#!/bin/sh
# Start the Vite dev server for the compose dev stack, with annotator, media and
# ui-core rebuilding as they are edited. No install: docker/app.Dockerfile already did it.
# Start the Vite dev server for the compose dev stack, with browser-inference, annotator,
# media and ui-core rebuilding as they are edited. No install: docker/app.Dockerfile already
# did it.
set -eu

# All three libraries are consumed through their `dist/`, so vite cannot resolve them
# All four libraries are consumed through their `dist/`, so vite cannot resolve them
# from source. A blocking build first, because a watcher's first pass is asynchronous and
# vite would race an empty `dist/`. Topological order matters here (unlike the watch
# below): ui-core imports @visionset/media, so media must build before ui-core does. The
# app itself is not built: nothing in dev reads it.
echo "app-dev: building @visionset/annotator, @visionset/media and @visionset/ui-core"
pnpm --filter @visionset/annotator --filter @visionset/media --filter @visionset/ui-core build
# browser-inference also has to build before Vite starts: its ORT artifact directory is
# served by frontend/app/vite.config.ts rather than being copied into this source tree.
echo "app-dev: building @visionset/browser-inference, @visionset/annotator, @visionset/media and @visionset/ui-core"
pnpm --filter @visionset/browser-inference --filter @visionset/annotator --filter @visionset/media --filter @visionset/ui-core build

# tsup's watcher is chokidar underneath, so it already honours CHOKIDAR_USEPOLLING from
# compose.yaml — no polling flags to pass here, unlike tsc before #839. `--watch` alone;
# tsup accepts no `--preserveWatchOutput`/`--watchFile`/`--watchDirectory` (those were
# tsc's) and rejects unknown flags outright.
echo "app-dev: starting watch builds for annotator + media + ui-core"
pnpm --filter @visionset/annotator --filter @visionset/media --filter @visionset/ui-core --parallel run build --watch &
# compose.yaml — no polling flags to pass here, unlike tsc before #839. Every package's
# regular build uses `clean: true`, which is correct for the blocking build above but
# wrong for a long-lived watcher: Vite may resolve a library between its clean and emit,
# or read browser-inference's ORT directory before its copy script restores it. Watch
# tsup directly with cleaning disabled. The blocking build provides a clean output and
# browser-inference's immutable ORT assets only change when its configuration is rebuilt.
echo "app-dev: starting watch builds for browser-inference + annotator + media + ui-core"
pnpm --filter @visionset/browser-inference --filter @visionset/annotator --filter @visionset/media --filter @visionset/ui-core --parallel exec tsup --watch --clean=false &
WATCH_PID=$!

# Backgrounded rather than `exec`, so this shell stays PID 1 and keeps the trap.
Expand Down
7 changes: 6 additions & 1 deletion docker/app.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ WORKDIR /workspace
# Manifests and lockfile only, so a source edit does not re-run the install.
COPY pnpm-workspace.yaml pnpm-lock.yaml package.json ./
COPY frontend/annotator/package.json ./frontend/annotator/
COPY frontend/browser-inference/package.json ./frontend/browser-inference/
COPY frontend/ui-core/package.json ./frontend/ui-core/
COPY frontend/media/package.json ./frontend/media/
COPY frontend/app/package.json ./frontend/app/
Expand All @@ -37,8 +38,12 @@ RUN --mount=type=cache,target=/pnpm-store \
# purpose (Playwright, which this image never runs). tsup.config.ts is required too:
# app-dev.sh builds these packages with tsup (#839), and it reads no CLI entry, so
# without the config file on disk it fails with "No input files". ui-core imports
# @visionset/media (#847), so it needs the same treatment.
# @visionset/media (#847), and app's Vite configuration reads the ORT assets that
# @visionset/browser-inference emits, so both need the same treatment.
COPY frontend/annotator/tsconfig*.json frontend/annotator/tsup.config.ts ./frontend/annotator/
COPY frontend/browser-inference/tsconfig*.json frontend/browser-inference/tsup.config.ts ./frontend/browser-inference/
COPY frontend/browser-inference/scripts ./frontend/browser-inference/scripts
COPY frontend/browser-inference/src ./frontend/browser-inference/src
COPY frontend/ui-core/tsconfig*.json frontend/ui-core/tsup.config.ts ./frontend/ui-core/
COPY frontend/media/tsconfig*.json frontend/media/tsup.config.ts ./frontend/media/
COPY frontend/app/tsconfig.json frontend/app/vite.config.ts frontend/app/index.html ./frontend/app/
Expand Down
1 change: 1 addition & 0 deletions docker/compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ services:
# image's node_modules. Manifests, tsconfigs, vite.config.ts and index.html are
# baked into the image, so editing one needs `build`.
- ../frontend/annotator/src:/workspace/frontend/annotator/src
- ../frontend/browser-inference/src:/workspace/frontend/browser-inference/src
- ../frontend/media/src:/workspace/frontend/media/src
- ../frontend/ui-core/src:/workspace/frontend/ui-core/src
- ../frontend/app/src:/workspace/frontend/app/src
Expand Down
56 changes: 56 additions & 0 deletions tests/scripts/compose_browser_inference.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Run with: pnpm test:scripts (also part of the root `pnpm test`)
//
// The Compose app image starts Vite, whose configuration serves the ORT assets emitted
// by @visionset/browser-inference. That package is consumed through `dist/`, so merely
// installing its dependencies is insufficient: the image needs its build inputs and
// app-dev.sh must build it before Vite reads the configuration.
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";
import { test } from "node:test";

const ROOT = join(dirname(fileURLToPath(import.meta.url)), "..", "..");
const read = (...parts) => readFileSync(join(ROOT, ...parts), "utf8");

test("the Compose app image builds browser-inference before Vite starts", () => {
const dockerfile = read("docker", "app.Dockerfile");
const devScript = read("docker", "app-dev.sh");
const compose = read("docker", "compose.yaml");

assert.match(
dockerfile,
/^COPY frontend\/browser-inference\/package\.json \.\/frontend\/browser-inference\/$/m,
"docker/app.Dockerfile must copy browser-inference's manifest before pnpm install",
);
assert.match(
dockerfile,
/^COPY frontend\/browser-inference\/src \.\/frontend\/browser-inference\/src$/m,
"docker/app.Dockerfile must bake browser-inference's build source into the app image",
);
assert.match(
dockerfile,
/^COPY frontend\/browser-inference\/scripts \.\/frontend\/browser-inference\/scripts$/m,
"docker/app.Dockerfile must bake browser-inference's ORT-copy build script into the app image",
);
assert.match(
dockerfile,
/^COPY frontend\/browser-inference\/tsconfig\*\.json frontend\/browser-inference\/tsup\.config\.ts \.\/frontend\/browser-inference\/$/m,
"docker/app.Dockerfile must bake browser-inference's tsup configuration into the app image",
);
assert.match(
devScript,
/pnpm --filter @visionset\/browser-inference(?:\s|$).* build/m,
"docker/app-dev.sh must build browser-inference before starting Vite",
);
assert.match(
devScript,
/pnpm --filter @visionset\/browser-inference --filter @visionset\/annotator --filter @visionset\/media --filter @visionset\/ui-core --parallel exec tsup --watch --clean=false/m,
"docker/app-dev.sh must watch every library without clearing its dist output",
);
assert.match(
compose,
/^\s*- \.\.\/frontend\/browser-inference\/src:\/workspace\/frontend\/browser-inference\/src$/m,
"docker/compose.yaml must mount browser-inference source for the watcher",
);
});
Loading