mirror of https://github.com/OpenVidu/openvidu.git
openvidu-dashboard: ./dashboard.sh dev runs the backend and frontend against openvidu-local-deployment
dashboard-ce/tools/dev.sh checks the configuration and MongoDB, then starts both development servers, stopped together. The backend reads dashboard-ce/backend/dev.env (local deployment defaults), under a git-ignored .env and the environment; DASHBOARD_DEV_PORT and DASHBOARD_DEV_BACKEND_PORT move the servers. The demo shares the process helpers, now in dev-lib.sh, and runs every server by directory so Ctrl+C prints no pnpm errors.chore/update-openvidu-actions-1.0.25
parent
e4f1ef6e7f
commit
2390f8753b
|
|
@ -14,3 +14,7 @@ dashboard-ce/tools
|
|||
# Their manifests keep the workspace consistent with the lockfile.
|
||||
!dashboard-ce/tools/*/package.json
|
||||
PLAN.md
|
||||
# Development settings, personal ones included, never reach the image.
|
||||
**/.env
|
||||
**/.env.*
|
||||
**/dev.env
|
||||
|
|
|
|||
|
|
@ -49,7 +49,8 @@ sources through the `source` export condition, so type checking, linting and tes
|
|||
|
||||
Everything runs through `./dashboard.sh` (what CI calls; `help` lists every command, any accepts `--skip-install`):
|
||||
`check` (lint, format check, typecheck, spec validation, unit tests), `test-integration` (Docker), `e2e`,
|
||||
`contract-check <openvidu-livekit>`, `build-image ce`, `smoke-image ce`, and `demo ce`: a local demo on generated data
|
||||
`contract-check <openvidu-livekit>`, `build-image ce`, `smoke-image ce`, `dev` (backend and frontend development
|
||||
servers against openvidu-local-deployment; README "Development") and `demo ce`: a local demo on generated data
|
||||
(http://localhost:4200, `admin` / `admin`; MongoDB container `openvidu-dashboard-demo-mongo` on port 27018;
|
||||
`DASHBOARD_DEMO_KEEP_DATA=true` reuses the data of a running container).
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ All tasks run through `./dashboard.sh`:
|
|||
```bash
|
||||
./dashboard.sh install # install dependencies
|
||||
./dashboard.sh check # lint + format check + type check + spec validation + unit tests
|
||||
./dashboard.sh dev # frontend dev server, proxying /api to a backend on port 5000
|
||||
./dashboard.sh dev # backend and frontend dev servers against openvidu-local-deployment
|
||||
./dashboard.sh demo ce # local demo on generated data: http://localhost:4200, admin / admin
|
||||
./dashboard.sh test-integration # integration tests against MongoDB (Docker required)
|
||||
./dashboard.sh e2e # build the application and run the Playwright tests
|
||||
|
|
@ -46,6 +46,23 @@ All tasks run through `./dashboard.sh`:
|
|||
./dashboard.sh help # list every command
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
`./dashboard.sh dev` runs the backend and frontend development servers against the MongoDB of an
|
||||
[openvidu-local-deployment](https://github.com/OpenVidu/openvidu-local-deployment) running on this machine, both
|
||||
reloading on changes: http://localhost:4200, `admin` / `admin`. Ctrl+C stops both. Without a deployment,
|
||||
`./dashboard.sh demo ce` runs the same servers on generated data instead.
|
||||
|
||||
- Before starting, it checks the configuration and that MongoDB answers, and says what to do when it does not.
|
||||
- The backend reads `dashboard-ce/backend/dev.env`, the defaults for the local deployment. A git-ignored
|
||||
`dashboard-ce/backend/.env` overrides them, and the environment overrides both, for example
|
||||
`DATABASE_URL` for another MongoDB or `LOG_LEVEL=debug`. The deployment's replica set advertises its member
|
||||
as `mongo:27017`, which only Docker resolves, so a URL from the host needs `directConnection=true`.
|
||||
- `DASHBOARD_DEV_PORT` (default 4200) and `DASHBOARD_DEV_BACKEND_PORT` (default 5000) move the servers, for
|
||||
example off port 5000 where macOS runs AirPlay.
|
||||
- The deployment needs a 3.10 OpenVidu server: data appears once it writes the analytics database, and an
|
||||
older writer schema stops the check.
|
||||
|
||||
## Container image
|
||||
|
||||
`openvidu/openvidu-dashboard`, built from `dashboard-ce/docker/Dockerfile` on `node:24-trixie-slim`
|
||||
|
|
|
|||
|
|
@ -45,6 +45,10 @@ Behaviour is specified in `openspec/specs/*-api`, `api-conventions`, `auth`, `st
|
|||
`entityIdKind()` from typings.
|
||||
- Configuration variables are new `DASHBOARD_*`, or `DATABASE_*` for database connection settings; legacy names keep
|
||||
their 3.9 meaning (`src/config/variables.ts`, unit-tested). The README lists them all.
|
||||
- `scripts/dev.ts` (exported as `@openvidu-dashboard/backend/dev`) serves `./dashboard.sh dev`: `loadDevEnv()` (the
|
||||
environment, then `.env`, then `dev.env`; `scripts/dev-preload.ts` for `tsx watch --import`) and
|
||||
`checkDevConfig()` (`scripts/dev-check.ts`). `dev.env` holds the openvidu-local-deployment defaults; never give
|
||||
`src/` defaults for required variables, since a deployment must fail when they are missing.
|
||||
|
||||
## Rules
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
# Defaults of ./dashboard.sh dev, for openvidu-local-deployment running on this machine. Override any of them in
|
||||
# .env next to this file (git-ignored) or in the environment.
|
||||
ADMIN_USERNAME=admin
|
||||
ADMIN_PASSWORD=admin
|
||||
# The deployment's replica set advertises its member as mongo:27017, a name only Docker resolves.
|
||||
DATABASE_URL=mongodb://mongoadmin:mongoadmin@localhost:27017/?directConnection=true
|
||||
DASHBOARD_BASE_PATH=/
|
||||
|
|
@ -13,14 +13,15 @@
|
|||
"default": "./dist/index.js"
|
||||
},
|
||||
"./testing": "./test/support/index.ts",
|
||||
"./testing/global-mongo": "./test/support/global-mongo.ts"
|
||||
"./testing/global-mongo": "./test/support/global-mongo.ts",
|
||||
"./dev": "./scripts/dev.ts"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsc -p tsconfig.build.json",
|
||||
"dev": "tsx watch --conditions=source src/server.ts",
|
||||
"dev": "tsx watch --conditions=source --import ./scripts/dev-preload.ts src/server.ts",
|
||||
"typecheck": "tsc --noEmit -p tsconfig.json",
|
||||
"test": "vitest run --project unit",
|
||||
"test:integration": "vitest run --project integration --project integration-plans",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
/** Run by `./dashboard.sh dev` before it starts the development servers. */
|
||||
import { checkDevConfig } from './dev.js';
|
||||
|
||||
if (!(await checkDevConfig())) {
|
||||
process.exitCode = 1;
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
/** Preloaded by the backend development scripts: the environment, then `.env` (git-ignored), then `dev.env`. */
|
||||
import { DEV_ENV_FILE, loadDevEnv } from './dev.js';
|
||||
|
||||
loadDevEnv(['.env', DEV_ENV_FILE]);
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
/**
|
||||
* Configuration of `./dashboard.sh dev`, exported as `@openvidu-dashboard/backend/dev` for the development scripts of
|
||||
* extending workspaces: the variable files of the backend development server and the check that runs before it.
|
||||
*/
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
import { MongoClient } from 'mongodb';
|
||||
|
||||
import { WriterSchemaStatus } from '@openvidu-dashboard/typings';
|
||||
|
||||
import { applyEnvFile, loadConfigFile } from '../src/config/config-file.js';
|
||||
import { type DashboardConfig, parseConfig } from '../src/config/variables.js';
|
||||
import { mongoClientOptions, resolveMongoUrl } from '../src/mongo/mongo-client.js';
|
||||
import { olderSchemaMessage, readSchemaStatus } from '../src/schema/schema-status.js';
|
||||
|
||||
/** The defaults for openvidu-local-deployment running on this machine. */
|
||||
export const DEV_ENV_FILE = fileURLToPath(new URL('../dev.env', import.meta.url));
|
||||
|
||||
const MONGO_HINT =
|
||||
'Start openvidu-local-deployment, set DATABASE_URL in the .env of the backend, or run ./dashboard.sh demo for ' +
|
||||
'generated data.';
|
||||
|
||||
/**
|
||||
* Loads the files that exist, in order, into `env`: a variable keeps the first value it gets, so the environment wins
|
||||
* over every file and each file over the ones after it.
|
||||
*
|
||||
* @throws Error when a file cannot be read.
|
||||
*/
|
||||
export function loadDevEnv(files: readonly string[], env: NodeJS.ProcessEnv = process.env): void {
|
||||
for (const file of files) {
|
||||
const result = applyEnvFile(file, env);
|
||||
|
||||
if (result.kind === 'unreadable') {
|
||||
throw new Error(`Cannot read ${file}: ${result.reason}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the configuration in `env` and that its MongoDB answers with a schema this dashboard supports, printing the
|
||||
* problem or what the backend will use.
|
||||
*
|
||||
* @returns Whether the backend can start.
|
||||
*/
|
||||
export async function checkDevConfig(env: NodeJS.ProcessEnv = process.env): Promise<boolean> {
|
||||
const problem = await findProblem(env);
|
||||
|
||||
if (problem !== undefined) {
|
||||
process.stderr.write(`${problem}\n`);
|
||||
}
|
||||
|
||||
return problem === undefined;
|
||||
}
|
||||
|
||||
async function findProblem(env: NodeJS.ProcessEnv): Promise<string | undefined> {
|
||||
const file = loadConfigFile(env);
|
||||
|
||||
if (file.kind === 'unreadable') {
|
||||
return `Cannot read ${file.path} (DASHBOARD_CONFIG_PATH): ${file.reason}`;
|
||||
}
|
||||
|
||||
const parsed = parseConfig(env);
|
||||
|
||||
if (parsed.kind === 'mongo-disabled') {
|
||||
return 'MONGO_ENABLED is false: the dashboard stops at startup';
|
||||
}
|
||||
|
||||
if (parsed.kind === 'invalid') {
|
||||
return parsed.errors.map((error) => `Invalid configuration: ${error}`).join('\n');
|
||||
}
|
||||
|
||||
return findMongoProblem(parsed.config);
|
||||
}
|
||||
|
||||
async function findMongoProblem(config: DashboardConfig): Promise<string | undefined> {
|
||||
const url = resolveMongoUrl(config.database);
|
||||
|
||||
if (url.kind === 'missing') {
|
||||
return `Define DATABASE_URL, or ${url.variables.join(', ')}`;
|
||||
}
|
||||
|
||||
const redacted = url.url.replace(/\/\/([^:@/]+):[^@/]*@/, '//$1:***@');
|
||||
let client: MongoClient;
|
||||
|
||||
try {
|
||||
client = new MongoClient(url.url, { ...mongoClientOptions(config.database), serverSelectionTimeoutMS: 3_000 });
|
||||
} catch (error) {
|
||||
return `Cannot use the MongoDB settings: ${errorMessage(error)}`;
|
||||
}
|
||||
|
||||
try {
|
||||
const schema = await readSchemaStatus(client.db(config.database.name));
|
||||
|
||||
if (schema.status === WriterSchemaStatus.OLDER && schema.writer !== undefined) {
|
||||
return `${olderSchemaMessage(schema.writer)} (pull the latest images of the deployment)`;
|
||||
}
|
||||
} catch (error) {
|
||||
return `MongoDB does not answer at ${redacted}: ${errorMessage(error)}\n${MONGO_HINT}`;
|
||||
} finally {
|
||||
await client.close();
|
||||
}
|
||||
|
||||
process.stdout.write(`User ${config.admin.username}; MongoDB ${redacted}, database ${config.database.name}\n`);
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function errorMessage(error: unknown): string {
|
||||
return error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
|
|
@ -14,10 +14,11 @@ export type ConfigFileResult =
|
|||
export function loadConfigFile(env: NodeJS.ProcessEnv): ConfigFileResult {
|
||||
const path = env.DASHBOARD_CONFIG_PATH?.trim();
|
||||
|
||||
if (!path) {
|
||||
return { kind: 'none' };
|
||||
}
|
||||
return path ? applyEnvFile(path, env) : { kind: 'none' };
|
||||
}
|
||||
|
||||
/** Loads the `KEY=value` lines of `path` into `env`; variables already set in `env` keep their value. */
|
||||
export function applyEnvFile(path: string, env: NodeJS.ProcessEnv): Exclude<ConfigFileResult, { kind: 'none' }> {
|
||||
if (!existsSync(path)) {
|
||||
return { kind: 'missing', path };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
import { mkdtempSync, writeFileSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { parseConfig } from '../../src/config/variables.js';
|
||||
import { DEV_ENV_FILE, loadDevEnv } from '../../scripts/dev.js';
|
||||
|
||||
describe('development variables', () => {
|
||||
function file(content: string): string {
|
||||
const path = join(mkdtempSync(join(tmpdir(), 'dashboard-dev-')), '.env');
|
||||
writeFileSync(path, content);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
it('keeps the environment over the first file and that file over the next one', () => {
|
||||
const env: NodeJS.ProcessEnv = { ADMIN_PASSWORD: 'from-env' };
|
||||
|
||||
loadDevEnv(
|
||||
[file('ADMIN_PASSWORD=from-local\nLOG_LEVEL=debug\n'), file('LOG_LEVEL=warn\nSERVER_PORT=6000\n')],
|
||||
env
|
||||
);
|
||||
expect(env).toEqual({ ADMIN_PASSWORD: 'from-env', LOG_LEVEL: 'debug', SERVER_PORT: '6000' });
|
||||
});
|
||||
|
||||
it('skips a file that does not exist', () => {
|
||||
const env: NodeJS.ProcessEnv = {};
|
||||
|
||||
loadDevEnv(['/nonexistent/.env'], env);
|
||||
expect(env).toEqual({});
|
||||
});
|
||||
|
||||
it('defaults to a valid configuration for the local deployment', () => {
|
||||
const env: NodeJS.ProcessEnv = {};
|
||||
|
||||
loadDevEnv([DEV_ENV_FILE], env);
|
||||
|
||||
const parsed = parseConfig(env);
|
||||
|
||||
expect(parsed.kind).toBe('config');
|
||||
expect(parsed.kind === 'config' && parsed.config.admin.username).toBe('admin');
|
||||
expect(env.DATABASE_URL).toBe('mongodb://mongoadmin:mongoadmin@localhost:27017/?directConnection=true');
|
||||
});
|
||||
});
|
||||
|
|
@ -5,5 +5,5 @@
|
|||
"resolveJsonModule": true,
|
||||
"types": ["node"]
|
||||
},
|
||||
"include": ["src", "test", "vitest.config.ts"]
|
||||
"include": ["src", "test", "scripts", "vitest.config.ts"]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,60 +1,20 @@
|
|||
#!/usr/bin/env bash
|
||||
# Shared parts of the local demos, sourced by dashboard-ce/tools/demo.sh and by the demos of workspaces that extend
|
||||
# these packages: a MongoDB replica set (a container, or DASHBOARD_DEMO_MONGO_URI), 30 days of generated data kept live,
|
||||
# and the backend and frontend development servers. The caller sets DATABASE and STATS_MODE and runs from the root of
|
||||
# its workspace.
|
||||
# and the backend and frontend development servers of dev-lib.sh. The caller sets DATABASE and STATS_MODE and runs
|
||||
# from the root of its workspace.
|
||||
# DASHBOARD_DEMO_MONGO_URI MongoDB to use instead of the container
|
||||
# DASHBOARD_DEMO_MONGO_PORT host port of the container (default 27018)
|
||||
# DASHBOARD_DEMO_KEEP_DATA true reuses the demo database instead of generating it again
|
||||
|
||||
TOOLS_DIR="$(dirname "${BASH_SOURCE[0]}")"
|
||||
|
||||
# shellcheck source=dashboard-ce/tools/dev-lib.sh
|
||||
source "$TOOLS_DIR/dev-lib.sh"
|
||||
|
||||
MONGO_IMAGE="${DASHBOARD_TEST_MONGO_IMAGE:-openvidu/mongodb:8.0.29-r1}"
|
||||
MONGO_CONTAINER=openvidu-dashboard-demo-mongo
|
||||
MONGO_PORT="${DASHBOARD_DEMO_MONGO_PORT:-27018}"
|
||||
# The frontend development servers proxy /api to port 5000 (proxy.conf.json); another backend gets its own proxy file.
|
||||
DEFAULT_BACKEND_PORT=5000
|
||||
WORK_DIR="$(mktemp -d)"
|
||||
PIDS=()
|
||||
|
||||
kill_tree() {
|
||||
local child
|
||||
|
||||
for child in $(pgrep -P "$1" || true); do
|
||||
kill_tree "$child"
|
||||
done
|
||||
|
||||
kill "$1" 2>/dev/null || true
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
for pid in "${PIDS[@]}"; do
|
||||
kill_tree "$pid"
|
||||
done
|
||||
|
||||
rm -rf "$WORK_DIR"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
# require_free_ports <port>...: exits when one is in use.
|
||||
require_free_ports() {
|
||||
local port
|
||||
|
||||
for port in "$@"; do
|
||||
if (exec 3<>"/dev/tcp/127.0.0.1/$port") 2>/dev/null; then
|
||||
echo "Port $port is in use" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
wait_for() {
|
||||
for _ in $(seq 1 120); do
|
||||
curl -sf -o /dev/null "$1" && return 0
|
||||
sleep 1
|
||||
done
|
||||
|
||||
echo "$1 did not answer" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
start_mongo() {
|
||||
if [ "$(docker inspect -f '{{.State.Running}}' "$MONGO_CONTAINER" 2>/dev/null)" != true ]; then
|
||||
|
|
@ -92,34 +52,22 @@ prepare_data() {
|
|||
|
||||
if [ "${DASHBOARD_DEMO_KEEP_DATA:-false}" != true ]; then
|
||||
echo "Generating $DATABASE (scenario S, 30 days, $STATS_MODE stats)"
|
||||
pnpm --silent --filter @openvidu-dashboard/data-generator run generate --uri "$MONGO_URI" --db "$DATABASE" \
|
||||
pnpm --silent --dir "$TOOLS_DIR/data-generator" run generate --uri "$MONGO_URI" --db "$DATABASE" \
|
||||
--scenario S --days 30 --stats-mode "$STATS_MODE" --drop --five-minute-rollups --node-rollups --room-sums \
|
||||
--active-window 60 --min-active-rooms 10 | tail -2
|
||||
fi
|
||||
|
||||
pnpm --silent --filter @openvidu-dashboard/data-generator run keep-alive --uri "$MONGO_URI" --db "$DATABASE" &
|
||||
pnpm --silent --dir "$TOOLS_DIR/data-generator" run keep-alive --uri "$MONGO_URI" --db "$DATABASE" &
|
||||
PIDS+=("$!")
|
||||
}
|
||||
|
||||
# start_backend <package> <port> [VAR=value...]: the backend development server on the demo database, in the background.
|
||||
# start_backend <package directory> <port> [VAR=value...]: the backend development server on the demo database, in
|
||||
# the background.
|
||||
start_backend() {
|
||||
local package="$1"
|
||||
local directory="$1"
|
||||
local port="$2"
|
||||
|
||||
shift 2
|
||||
env SERVER_PORT="$port" DASHBOARD_BASE_PATH=/ ADMIN_USERNAME=admin ADMIN_PASSWORD=admin DATABASE_URL="$MONGO_URI" \
|
||||
DATABASE_NAME="$DATABASE" "$@" pnpm --silent --filter "$package" run dev &
|
||||
PIDS+=("$!")
|
||||
}
|
||||
|
||||
# start_frontend <package> <port> <backend port>: the frontend development server proxying /api to that backend.
|
||||
start_frontend() {
|
||||
local proxy=()
|
||||
|
||||
if [ "$3" != "$DEFAULT_BACKEND_PORT" ]; then
|
||||
printf '{ "/api": { "target": "http://localhost:%s", "secure": false } }\n' "$3" >"$WORK_DIR/proxy-$2.json"
|
||||
proxy=(--proxy-config "$WORK_DIR/proxy-$2.json")
|
||||
fi
|
||||
|
||||
pnpm --silent --filter "$1" run dev --port "$2" "${proxy[@]}"
|
||||
start_dev_backend "$directory" "$port" DASHBOARD_BASE_PATH=/ ADMIN_USERNAME=admin ADMIN_PASSWORD=admin \
|
||||
DATABASE_URL="$MONGO_URI" DATABASE_NAME="$DATABASE" "$@"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ source dashboard-ce/tools/demo-lib.sh
|
|||
|
||||
require_free_ports "$DEFAULT_BACKEND_PORT" "$FRONTEND_PORT"
|
||||
prepare_data
|
||||
start_backend @openvidu-dashboard/backend "$DEFAULT_BACKEND_PORT"
|
||||
start_backend dashboard-ce/backend "$DEFAULT_BACKEND_PORT"
|
||||
wait_for "http://127.0.0.1:$DEFAULT_BACKEND_PORT/api/healthcheck"
|
||||
echo "OpenVidu Dashboard ce demo: http://localhost:$FRONTEND_PORT (admin / admin)"
|
||||
start_frontend @openvidu-dashboard/frontend "$FRONTEND_PORT" "$DEFAULT_BACKEND_PORT"
|
||||
start_frontend dashboard-ce/frontend "$FRONTEND_PORT" "$DEFAULT_BACKEND_PORT"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
#!/usr/bin/env bash
|
||||
# Development servers of the local runs, sourced by dev.sh and demo-lib.sh here and by the scripts of workspaces that
|
||||
# extend these packages: the backend and frontend development servers in one session, stopped together. The caller
|
||||
# runs from the root of its workspace.
|
||||
|
||||
# The frontend development servers proxy /api to port 5000 (proxy.conf.json); another backend gets its own proxy file.
|
||||
DEFAULT_BACKEND_PORT=5000
|
||||
WORK_DIR="$(mktemp -d)"
|
||||
PIDS=()
|
||||
|
||||
kill_tree() {
|
||||
local child
|
||||
|
||||
for child in $(pgrep -P "$1" || true); do
|
||||
kill_tree "$child"
|
||||
done
|
||||
|
||||
kill "$1" 2>/dev/null || true
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
for pid in "${PIDS[@]}"; do
|
||||
kill_tree "$pid"
|
||||
done
|
||||
|
||||
rm -rf "$WORK_DIR"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
# require_free_ports <port>...: exits when one is in use.
|
||||
require_free_ports() {
|
||||
local port
|
||||
|
||||
for port in "$@"; do
|
||||
if (exec 3<>"/dev/tcp/127.0.0.1/$port") 2>/dev/null; then
|
||||
echo "Port $port is in use" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
wait_for() {
|
||||
for _ in $(seq 1 120); do
|
||||
curl -sf -o /dev/null "$1" && return 0
|
||||
sleep 1
|
||||
done
|
||||
|
||||
echo "$1 did not answer" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# check_dev_backend <package directory>: exits when the backend there cannot start, with its scripts/dev-check.ts
|
||||
# and the variables of its scripts/dev-preload.ts.
|
||||
check_dev_backend() {
|
||||
pnpm --silent --dir "$1" exec tsx --conditions=source --import ./scripts/dev-preload.ts scripts/dev-check.ts
|
||||
}
|
||||
|
||||
# start_dev_backend <package directory> <port> [VAR=value...]: the backend development server in the background. The
|
||||
# variables win over the files of its scripts/dev-preload.ts.
|
||||
start_dev_backend() {
|
||||
local directory="$1"
|
||||
local port="$2"
|
||||
|
||||
shift 2
|
||||
env SERVER_PORT="$port" "$@" pnpm --silent --dir "$directory" run dev &
|
||||
PIDS+=("$!")
|
||||
}
|
||||
|
||||
# start_frontend <package directory> <port> <backend port>: the frontend development server proxying /api to that
|
||||
# backend.
|
||||
start_frontend() {
|
||||
local proxy=()
|
||||
|
||||
if [ "$3" != "$DEFAULT_BACKEND_PORT" ]; then
|
||||
printf '{ "/api": { "target": "http://localhost:%s", "secure": false } }\n' "$3" >"$WORK_DIR/proxy-$2.json"
|
||||
proxy=(--proxy-config "$WORK_DIR/proxy-$2.json")
|
||||
fi
|
||||
|
||||
pnpm --silent --dir "$1" run dev --port "$2" "${proxy[@]}"
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
#!/usr/bin/env bash
|
||||
# Local development against openvidu-local-deployment (see dev-lib.sh): the backend and frontend development servers,
|
||||
# both reloading on changes. The backend reads dashboard-ce/backend/dev.env, overridden by dashboard-ce/backend/.env
|
||||
# (git-ignored) and by the environment.
|
||||
# Usage: dashboard-ce/tools/dev.sh
|
||||
# DASHBOARD_DEV_PORT port of the frontend development server (default 4200)
|
||||
# DASHBOARD_DEV_BACKEND_PORT port of the backend development server (default 5000)
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "${BASH_SOURCE[0]}")/../.."
|
||||
|
||||
FRONTEND_PORT="${DASHBOARD_DEV_PORT:-4200}"
|
||||
BACKEND_PORT="${DASHBOARD_DEV_BACKEND_PORT:-5000}"
|
||||
|
||||
# shellcheck source=dashboard-ce/tools/dev-lib.sh
|
||||
source dashboard-ce/tools/dev-lib.sh
|
||||
|
||||
require_free_ports "$BACKEND_PORT" "$FRONTEND_PORT"
|
||||
check_dev_backend dashboard-ce/backend
|
||||
start_dev_backend dashboard-ce/backend "$BACKEND_PORT"
|
||||
wait_for "http://127.0.0.1:$BACKEND_PORT/api/healthcheck"
|
||||
echo "OpenVidu Dashboard: http://localhost:$FRONTEND_PORT"
|
||||
start_frontend dashboard-ce/frontend "$FRONTEND_PORT" "$BACKEND_PORT"
|
||||
|
|
@ -35,7 +35,9 @@ Commands:
|
|||
format-check Prettier --check
|
||||
typecheck tsc --noEmit in every package that defines it
|
||||
build Build every package in dependency order
|
||||
dev Frontend dev server on http://localhost:4200, proxying /api to the backend on port 5000
|
||||
dev Backend and frontend dev servers against openvidu-local-deployment: http://localhost:4200, backend
|
||||
on port 5000 (DASHBOARD_DEV_PORT, DASHBOARD_DEV_BACKEND_PORT); defaults in
|
||||
dashboard-ce/backend/dev.env, overridden by dashboard-ce/backend/.env and the environment
|
||||
demo [ce] Local demo on generated data: MongoDB (a container, or DASHBOARD_DEMO_MONGO_URI), 30 days of data
|
||||
kept live, backend and frontend dev servers on http://localhost:4200 (admin / admin)
|
||||
test Unit tests (Vitest) of every package that defines them (same as test-unit)
|
||||
|
|
@ -141,7 +143,11 @@ case "$COMMAND" in
|
|||
format-check) run format:check ;;
|
||||
typecheck) run typecheck ;;
|
||||
build) run build ;;
|
||||
dev) run dev ;;
|
||||
dev)
|
||||
require_pnpm
|
||||
ensure_installed
|
||||
dashboard-ce/tools/dev.sh
|
||||
;;
|
||||
demo)
|
||||
require_ce
|
||||
require_pnpm
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
"format:check": "prettier --check .",
|
||||
"typecheck": "pnpm -r run typecheck",
|
||||
"build": "pnpm -r run build",
|
||||
"dev": "pnpm --filter @openvidu-dashboard/frontend run dev",
|
||||
"test:unit": "pnpm -r --if-present run test",
|
||||
"test:integration": "pnpm -r --if-present run test:integration",
|
||||
"e2e": "pnpm --filter \"@openvidu-dashboard/e2e^...\" run build && pnpm --filter @openvidu-dashboard/e2e run e2e",
|
||||
|
|
|
|||
Loading…
Reference in New Issue