feat(build): optimize Dockerfile to build vendor packages during image build and streamline package.json scripts

This commit is contained in:
Asep Haryana Saputra
2026-05-21 12:27:07 +00:00
parent 0530bf9a60
commit 41197fd2c2
8 changed files with 83 additions and 19 deletions
+3 -2
View File
@@ -30,8 +30,9 @@ RUN pnpm install --no-frozen-lockfile
# Copy the rest of the application # Copy the rest of the application
COPY . . COPY . .
# Build step if required (e.g. build:web) # Build vendor packages and app bundles during image build
RUN pnpm run build:web || true RUN pnpm run prepare:vendor
RUN pnpm run build
# Set node environment # Set node environment
ENV NODE_ENV=production ENV NODE_ENV=production
+4 -7
View File
@@ -7,17 +7,14 @@
"packageManager": "pnpm@11.1.3", "packageManager": "pnpm@11.1.3",
"scripts": { "scripts": {
"prepare:vendor": "pnpm --filter './vendor/*' --filter '!discord.js-selfbot-v13' --if-present run build", "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", "dev": "tsx watch src/index.ts",
"predev:server": "pnpm run prepare:vendor",
"dev:server": "tsx watch src/index.ts", "dev:server": "tsx watch src/index.ts",
"dev:web": "vite --host 0.0.0.0 frontend", "dev:web": "vite --host 0.0.0.0 frontend",
"prestart": "pnpm run prepare:vendor", "start": "node dist/index.js",
"start": "tsx src/index.ts", "start:dev": "tsx src/index.ts",
"prebuild": "pnpm run prepare:vendor", "build": "pnpm run build:web && pnpm run build:server",
"build": "pnpm run build:web && tsc --outDir dist",
"build:web": "vite build frontend --outDir ../public/app --emptyOutDir", "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", "typecheck": "tsc --noEmit",
"lint": "biome check --diagnostic-level=error .", "lint": "biome check --diagnostic-level=error .",
"format": "biome format --write .", "format": "biome format --write .",
+7 -3
View File
@@ -1,7 +1,11 @@
import { AppError } from "../errors.js"; import { AppError } from "../errors.js";
import { createChildLogger } from "../logger.js"; import { createChildLogger } from "../logger.js";
import { discordPlayer } from "../player.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"); const logger = createChildLogger("screen-share");
@@ -105,8 +109,8 @@ export function createScreenShareController(
let stopped = false; let stopped = false;
const playFn = dependencies.useTranscoder const playFn = dependencies.useTranscoder
? (await import("../streaming/index.js")).playTranscodedPreparedStream ? playTranscodedPreparedStream
: (await import("../streaming/index.js")).playPreparedStream; : playPreparedStream;
const done = playFn(directUrl, session, { const done = playFn(directUrl, session, {
fps: 30, fps: 30,
+21 -4
View File
@@ -1,3 +1,5 @@
import { existsSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { Worker } from "node:worker_threads"; import { Worker } from "node:worker_threads";
import { config } from "../config.js"; import { config } from "../config.js";
import { createChildLogger } from "../logger.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( async function runAnalysisInWorker(
conversationKey: string, conversationKey: string,
messages: MessageRecord[], messages: MessageRecord[],
): Promise<AnalysisWorkerResponse> { ): Promise<AnalysisWorkerResponse> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const worker = new Worker( const worker = new Worker(getAnalysisWorkerUrl(), {
new URL("./aiAnalysisWorker.js", import.meta.url), execArgv: process.execArgv,
{ execArgv: process.execArgv }, });
);
worker.once("message", (response: AnalysisWorkerResponse) => { worker.once("message", (response: AnalysisWorkerResponse) => {
worker.terminate().catch((error) => { worker.terminate().catch((error) => {
+5 -1
View File
@@ -2,7 +2,11 @@ import OpenAI from "openai";
import { config } from "../config.js"; import { config } from "../config.js";
import { createChildLogger } from "../logger.js"; import { createChildLogger } from "../logger.js";
import { retryWithBackoff } from "../retry.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 log = createChildLogger("llmModerationClient");
const openai = new OpenAI({ const openai = new OpenAI({
+4 -1
View File
@@ -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"; export type AIStatus = "pending" | "clean" | "warn" | "flagged" | "error";
+4 -1
View File
@@ -2,7 +2,10 @@ import { ChildProcess, spawn } from "node:child_process";
import type { Readable } from "node:stream"; import type { Readable } from "node:stream";
import { PassThrough } from "node:stream"; import { PassThrough } from "node:stream";
import { createChildLogger } from "../logger.js"; import { createChildLogger } from "../logger.js";
import { transcoderRestartsCounter, transcoderRunningGauge } from "../metrics.js"; import {
transcoderRestartsCounter,
transcoderRunningGauge,
} from "../metrics.js";
import { retryWithBackoff } from "../retry.js"; import { retryWithBackoff } from "../retry.js";
const logger = createChildLogger("transcoder"); const logger = createChildLogger("transcoder");
+35
View File
@@ -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",
},
},
},
});