From 41197fd2c23d1a50ec9687db2269ff2744ac4404 Mon Sep 17 00:00:00 2001 From: Asep Haryana Saputra <90584806+MythEclipse@users.noreply.github.com> Date: Thu, 21 May 2026 12:27:07 +0000 Subject: [PATCH] feat(build): optimize Dockerfile to build vendor packages during image build and streamline package.json scripts --- Dockerfile | 5 ++-- package.json | 11 +++------ src/media/screenShareController.ts | 10 +++++--- src/moderation/aiAnalyzer.ts | 25 ++++++++++++++++--- src/moderation/llmModerationClient.ts | 6 ++++- src/moderation/types.ts | 5 +++- src/streaming/transcoder.ts | 5 +++- vite.backend.config.ts | 35 +++++++++++++++++++++++++++ 8 files changed, 83 insertions(+), 19 deletions(-) create mode 100644 vite.backend.config.ts diff --git a/Dockerfile b/Dockerfile index 971ee0e..d6db2d0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -30,8 +30,9 @@ RUN pnpm install --no-frozen-lockfile # Copy the rest of the application COPY . . -# Build step if required (e.g. build:web) -RUN pnpm run build:web || true +# Build vendor packages and app bundles during image build +RUN pnpm run prepare:vendor +RUN pnpm run build # Set node environment ENV NODE_ENV=production diff --git a/package.json b/package.json index a6a603b..8e5468a 100644 --- a/package.json +++ b/package.json @@ -7,17 +7,14 @@ "packageManager": "pnpm@11.1.3", "scripts": { "prepare:vendor": "pnpm --filter './vendor/*' --filter '!discord.js-selfbot-v13' --if-present run build", - "predev": "pnpm run prepare:vendor", "dev": "tsx watch src/index.ts", - "predev:server": "pnpm run prepare:vendor", "dev:server": "tsx watch src/index.ts", "dev:web": "vite --host 0.0.0.0 frontend", - "prestart": "pnpm run prepare:vendor", - "start": "tsx src/index.ts", - "prebuild": "pnpm run prepare:vendor", - "build": "pnpm run build:web && tsc --outDir dist", + "start": "node dist/index.js", + "start:dev": "tsx src/index.ts", + "build": "pnpm run build:web && pnpm run build:server", "build:web": "vite build frontend --outDir ../public/app --emptyOutDir", - "pretypecheck": "pnpm run prepare:vendor", + "build:server": "vite build --config vite.backend.config.ts", "typecheck": "tsc --noEmit", "lint": "biome check --diagnostic-level=error .", "format": "biome format --write .", diff --git a/src/media/screenShareController.ts b/src/media/screenShareController.ts index 34127be..c399748 100644 --- a/src/media/screenShareController.ts +++ b/src/media/screenShareController.ts @@ -1,7 +1,11 @@ import { AppError } from "../errors.js"; import { createChildLogger } from "../logger.js"; import { discordPlayer } from "../player.js"; -import { playPreparedStream, Streamer } from "../streaming/index.js"; +import { + playPreparedStream, + playTranscodedPreparedStream, + Streamer, +} from "../streaming/index.js"; const logger = createChildLogger("screen-share"); @@ -105,8 +109,8 @@ export function createScreenShareController( let stopped = false; const playFn = dependencies.useTranscoder - ? (await import("../streaming/index.js")).playTranscodedPreparedStream - : (await import("../streaming/index.js")).playPreparedStream; + ? playTranscodedPreparedStream + : playPreparedStream; const done = playFn(directUrl, session, { fps: 30, diff --git a/src/moderation/aiAnalyzer.ts b/src/moderation/aiAnalyzer.ts index f409660..44bd476 100644 --- a/src/moderation/aiAnalyzer.ts +++ b/src/moderation/aiAnalyzer.ts @@ -1,3 +1,5 @@ +import { existsSync } from "node:fs"; +import { fileURLToPath } from "node:url"; import { Worker } from "node:worker_threads"; import { config } from "../config.js"; import { createChildLogger } from "../logger.js"; @@ -157,15 +159,30 @@ async function processBatch( } } +function getAnalysisWorkerUrl(): URL { + const candidates = [ + new URL("./aiAnalysisWorker.js", import.meta.url), + new URL("../aiAnalysisWorker.js", import.meta.url), + new URL("./aiAnalysisWorker.ts", import.meta.url), + ]; + + for (const candidate of candidates) { + if (existsSync(fileURLToPath(candidate))) { + return candidate; + } + } + + return candidates[2]; +} + async function runAnalysisInWorker( conversationKey: string, messages: MessageRecord[], ): Promise { return new Promise((resolve, reject) => { - const worker = new Worker( - new URL("./aiAnalysisWorker.js", import.meta.url), - { execArgv: process.execArgv }, - ); + const worker = new Worker(getAnalysisWorkerUrl(), { + execArgv: process.execArgv, + }); worker.once("message", (response: AnalysisWorkerResponse) => { worker.terminate().catch((error) => { diff --git a/src/moderation/llmModerationClient.ts b/src/moderation/llmModerationClient.ts index 7dae1c8..3ea3d8c 100644 --- a/src/moderation/llmModerationClient.ts +++ b/src/moderation/llmModerationClient.ts @@ -2,7 +2,11 @@ import OpenAI from "openai"; import { config } from "../config.js"; import { createChildLogger } from "../logger.js"; import { retryWithBackoff } from "../retry.js"; -import type { AnalysisResult, AttachmentRecord, MessageRecord } from "./types.js"; +import type { + AnalysisResult, + AttachmentRecord, + MessageRecord, +} from "./types.js"; const log = createChildLogger("llmModerationClient"); const openai = new OpenAI({ diff --git a/src/moderation/types.ts b/src/moderation/types.ts index bc70e0f..787db7d 100644 --- a/src/moderation/types.ts +++ b/src/moderation/types.ts @@ -1,4 +1,7 @@ -import type { BroadcasterClient, ModerationBroadcaster } from "./broadcaster.js"; +import type { + BroadcasterClient, + ModerationBroadcaster, +} from "./broadcaster.js"; export type AIStatus = "pending" | "clean" | "warn" | "flagged" | "error"; diff --git a/src/streaming/transcoder.ts b/src/streaming/transcoder.ts index 48d0067..fd277cf 100644 --- a/src/streaming/transcoder.ts +++ b/src/streaming/transcoder.ts @@ -2,7 +2,10 @@ import { ChildProcess, spawn } from "node:child_process"; import type { Readable } from "node:stream"; import { PassThrough } from "node:stream"; import { createChildLogger } from "../logger.js"; -import { transcoderRestartsCounter, transcoderRunningGauge } from "../metrics.js"; +import { + transcoderRestartsCounter, + transcoderRunningGauge, +} from "../metrics.js"; import { retryWithBackoff } from "../retry.js"; const logger = createChildLogger("transcoder"); diff --git a/vite.backend.config.ts b/vite.backend.config.ts new file mode 100644 index 0000000..85e4132 --- /dev/null +++ b/vite.backend.config.ts @@ -0,0 +1,35 @@ +import { builtinModules } from "node:module"; +import { resolve } from "node:path"; +import { defineConfig } from "vite"; +import pkg from "./package.json" with { type: "json" }; + +const external = [ + ...builtinModules, + ...builtinModules.map((name) => `node:${name}`), + ...Object.keys(pkg.dependencies ?? {}), + ...Object.keys(pkg.devDependencies ?? {}), +]; + +export default defineConfig({ + build: { + emptyOutDir: true, + outDir: "dist", + sourcemap: true, + ssr: true, + target: "node22", + rollupOptions: { + external, + input: { + index: resolve(__dirname, "src/index.ts"), + aiAnalysisWorker: resolve( + __dirname, + "src/moderation/aiAnalysisWorker.ts", + ), + }, + output: { + entryFileNames: "[name].js", + chunkFileNames: "chunks/[name]-[hash].js", + }, + }, + }, +});