diff --git a/.gitignore b/.gitignore index 3c7320e..da12b9f 100644 --- a/.gitignore +++ b/.gitignore @@ -140,3 +140,6 @@ vite.config.ts.timestamp-* # Vite cache directory .vite + +# Vite logs directory +.logs diff --git a/.logs/api_dev.jsonl b/.logs/api_dev.jsonl index c953368..1adcb07 100644 --- a/.logs/api_dev.jsonl +++ b/.logs/api_dev.jsonl @@ -1 +1 @@ -{"level":"info","trace":1752758946.110915,"event":"server-start","at":1752758946.1434226} +{"level":"info","trace":1752839585.7461548,"event":"server-start","at":1752839585.7912903} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..532b96f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,30 @@ +# Stage 1: Builder +FROM denoland/deno:latest AS builder +WORKDIR /app + +# Copy project files +COPY ./api /app/api +COPY ./tasks/vite.js /app/tasks/vite.js +COPY ./deno.json /app/deno.json +COPY ./deno.lock /app/deno.lock +COPY ./.env.prod /app/.env.prod +COPY ./web /app/web + +# Cache dependencies +RUN deno cache --allow-scripts --lock=deno.lock api/server.ts tasks/vite.js + +# Build frontend (dist/web) and compile backend with static files +RUN deno task prod + +# Stage 2: Final image +FROM debian:bookworm-slim +WORKDIR /app + +# Copy compiled executable and Deno cache +COPY --from=builder /app/dist/api /app/server + +# Expose port from .env.prod (3021) +EXPOSE 3021 + +# Run the compiled executable +CMD ["/app/server", "--env=prod"] \ No newline at end of file diff --git a/api/server.ts b/api/server.ts index 9915810..7fb2d2f 100644 --- a/api/server.ts +++ b/api/server.ts @@ -10,13 +10,15 @@ import { join } from 'jsr:@std/path/join' import { serveDir } from 'jsr:@std/http/file-server' import { PORT } from './lib/env.ts' -const staticDir = join(Deno.cwd(), 'dist/web') +const isProd = Deno.args.includes('--env=prod') +const staticDir = isProd + ? join((import.meta.dirname || Deno.cwd()).split('/api')[0], 'dist/web') + : Deno.cwd() const indexHtml = await Deno.readFile(join(staticDir, 'index.html')) const htmlContent = { headers: { 'Content-Type': 'text/html' } } const serveDirOpts = { fsRoot: staticDir } const { ResponseError } = respond -const isProd = Deno.args.includes('--env=prod') const handleRequest = async (ctx: RequestContext) => { const logProps: Record = {} diff --git a/deno.json b/deno.json index ea53370..b628dca 100644 --- a/deno.json +++ b/deno.json @@ -3,12 +3,21 @@ "api:dev": "deno serve -A --env-file=.env.dev --port=3021 api/server.ts --env=dev", "vite:dev": "deno run -A --env-file=.env.dev tasks/vite.js --env=dev", "dev": { "dependencies": ["api:dev", "vite:dev"] }, - "api:prod": "deno compile -A --env-file=.env.prod --output dist/api api/server.ts --env=prod", - "vite:prod": "deno run -A --env-file=.env.prod tasks/vite.js --build --env=prod", - "prod": { "dependencies": ["api:prod", "vite:prod"] }, + "api:prod": "deno compile -A --env-file=.env.prod --no-check --output dist/api --target x86_64-unknown-linux-gnu --include dist/web api/server.ts --env=prod", + "vite:prod": "deno run -A tasks/vite.js --build --env=prod", + "prod": "deno task vite:prod && deno task api:prod", "start:prod": "dist/api --env=prod", "fmt": "deno fmt", - "lint": "deno lint" + "lint": "deno lint", + "docker:build": "docker build -t devtools .", + "docker:prod": "docker run --name devtools-app -p 8877:3021 --env-file .env.prod devtools", + "docker:stop": "docker stop devtools-app", + "docker:start": "docker start devtools-app", + "docker:restart": "docker restart devtools-app", + "docker:rm": "docker rm -f devtools-app", + "docker:logs": "docker logs -f devtools-app", + "docker:exec": "docker exec -it devtools-app /bin/sh", + "docker:clean": "docker rm -f devtools-app && docker rmi devtools" }, "imports": { "./": "./", @@ -20,8 +29,7 @@ "@tailwindcss/vite": "npm:@tailwindcss/vite@^4.1.11", "tailwindcss": "npm:tailwindcss@^4.1.11", "daisyui": "npm:daisyui@^5.0.46", - "lucide-preact": "npm:lucide-preact@^0.525.0", - "sonda": "npm:sonda@^0.7.1" + "lucide-preact": "npm:lucide-preact@^0.525.0" }, "fmt": { "useTabs": false, diff --git a/deno.lock b/deno.lock index 24de169..cc2ff85 100644 --- a/deno.lock +++ b/deno.lock @@ -21,7 +21,6 @@ "npm:daisyui@^5.0.46": "5.0.46", "npm:lucide-preact@0.525": "0.525.0_preact@10.26.9", "npm:preact@^10.26.9": "10.26.9", - "npm:sonda@~0.7.1": "0.7.1", "npm:tailwindcss@^4.1.11": "4.1.11", "npm:vite@*": "7.0.4_picomatch@4.0.2_@types+node@22.15.15", "npm:vite@^7.0.4": "7.0.4_picomatch@4.0.2_@types+node@22.15.15" @@ -709,12 +708,6 @@ ], "bin": true }, - "bundle-name@4.1.0": { - "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", - "dependencies": [ - "run-applescript" - ] - }, "caniuse-lite@1.0.30001727": { "integrity": "sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==" }, @@ -755,19 +748,6 @@ "ms" ] }, - "default-browser-id@5.0.0": { - "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==" - }, - "default-browser@5.2.1": { - "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", - "dependencies": [ - "bundle-name", - "default-browser-id" - ] - }, - "define-lazy-prop@3.0.0": { - "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==" - }, "detect-libc@2.0.4": { "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==" }, @@ -872,23 +852,6 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "bin": true }, - "is-docker@3.0.0": { - "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", - "bin": true - }, - "is-inside-container@1.0.0": { - "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", - "dependencies": [ - "is-docker" - ], - "bin": true - }, - "is-wsl@3.1.0": { - "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", - "dependencies": [ - "is-inside-container" - ] - }, "jiti@2.4.2": { "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", "bin": true @@ -1035,15 +998,6 @@ "boolbase" ] }, - "open@10.1.2": { - "integrity": "sha512-cxN6aIDPz6rm8hbebcP7vrQNhvRcveZoJU72Y7vskh4oIm+BZwBECnx5nTmrlres1Qapvx27Qo1Auukpf8PKXw==", - "dependencies": [ - "default-browser", - "define-lazy-prop", - "is-inside-container", - "is-wsl" - ] - }, "picocolors@1.1.1": { "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" }, @@ -1101,9 +1055,6 @@ ], "bin": true }, - "run-applescript@7.0.0": { - "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==" - }, "semver@6.3.1": { "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": true @@ -1117,15 +1068,6 @@ "sisteransi@1.0.5": { "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" }, - "sonda@0.7.1": { - "integrity": "sha512-PCdSdBvspoJXA0uY5GFeRzAolTHDP7gVnnMnr/O74IYIB8CiOFaEbTGNkEmShG6HBtmmFdQfPxdXbI+2vAgjYw==", - "dependencies": [ - "@ampproject/remapping", - "@jridgewell/sourcemap-codec", - "open" - ], - "bin": true - }, "source-map-js@1.2.1": { "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==" }, @@ -1235,7 +1177,6 @@ "npm:daisyui@^5.0.46", "npm:lucide-preact@0.525", "npm:preact@^10.26.9", - "npm:sonda@~0.7.1", "npm:tailwindcss@^4.1.11", "npm:vite@^7.0.4" ] diff --git a/tasks/vite.js b/tasks/vite.js index 9ceaa68..5e2e222 100644 --- a/tasks/vite.js +++ b/tasks/vite.js @@ -3,7 +3,6 @@ import { join } from 'node:path' import { build, createServer } from 'vite' import preact from '@preact/preset-vite' import tailwindcss from '@tailwindcss/vite' -import Sonda from 'sonda/vite' // import { PORT } from '../api/lib/env.ts'; const PORT = 3000 @@ -32,10 +31,6 @@ if (isBuild) { plugins: [ preact({ jsxImportSource: 'preact' }), tailwindcss(), - Sonda({ - enabled: true, - format: 'html', - }), ], server: { host: true,