Skip to content

Commit 582ebd1

Browse files
Add desktop Docker and Electron build configuration
1 parent 1774529 commit 582ebd1

6 files changed

Lines changed: 328 additions & 0 deletions

File tree

apps/desktop/Dockerfile

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# ---- build stage ----
2+
FROM node:22-bookworm-slim AS build
3+
WORKDIR /app
4+
5+
# Install build dependencies for native modules (fs-xattr, etc.)
6+
RUN apt-get update && apt-get install -y --no-install-recommends \
7+
python3 \
8+
make \
9+
g++ \
10+
&& rm -rf /var/lib/apt/lists/*
11+
12+
# CI-friendly env
13+
ENV HUSKY=0
14+
ENV CI=true
15+
16+
# Use pnpm
17+
RUN corepack enable && corepack prepare pnpm@9.15.9 --activate
18+
19+
# Accept (optional) build-time public URL for Remix/Vite (Coolify can pass it)
20+
ARG VITE_PUBLIC_APP_URL
21+
ENV VITE_PUBLIC_APP_URL=${VITE_PUBLIC_APP_URL}
22+
23+
# Install deps efficiently
24+
COPY package.json pnpm-lock.yaml* ./
25+
RUN pnpm fetch
26+
27+
# Copy source and build
28+
COPY . .
29+
# install with dev deps (needed to build)
30+
RUN pnpm install --offline --frozen-lockfile
31+
32+
# Build the Remix app (SSR + client)
33+
RUN NODE_OPTIONS=--max-old-space-size=4096 pnpm run build
34+
35+
# Keep only production deps for runtime
36+
RUN pnpm prune --prod --ignore-scripts
37+
38+
39+
# ---- runtime stage ----
40+
FROM node:22-bookworm-slim AS runtime
41+
WORKDIR /app
42+
43+
ENV NODE_ENV=production
44+
ENV PORT=3000
45+
ENV HOST=0.0.0.0
46+
47+
# Install curl so Coolify’s healthcheck works inside the image
48+
RUN apt-get update && apt-get install -y --no-install-recommends curl \
49+
&& rm -rf /var/lib/apt/lists/*
50+
51+
# Copy only what we need to run
52+
COPY --from=build /app/build /app/build
53+
COPY --from=build /app/node_modules /app/node_modules
54+
COPY --from=build /app/package.json /app/package.json
55+
56+
EXPOSE 3000
57+
58+
# Healthcheck for Coolify
59+
HEALTHCHECK --interval=10s --timeout=3s --start-period=5s --retries=5 \
60+
CMD curl -fsS http://localhost:3000/ || exit 1
61+
62+
# Start the Remix server
63+
CMD ["node", "build/server/index.js"]
64+
65+
66+
# ---- development stage ----
67+
FROM build AS codinit-ai-development
68+
69+
# Define environment variables for development
70+
ARG GROQ_API_KEY
71+
ARG HuggingFace_API_KEY
72+
ARG OPENAI_API_KEY
73+
ARG ANTHROPIC_API_KEY
74+
ARG OPEN_ROUTER_API_KEY
75+
ARG GOOGLE_GENERATIVE_AI_API_KEY
76+
ARG OLLAMA_API_BASE_URL
77+
ARG XAI_API_KEY
78+
ARG TOGETHER_API_KEY
79+
ARG TOGETHER_API_BASE_URL
80+
ARG VITE_LOG_LEVEL=debug
81+
ARG DEFAULT_NUM_CTX
82+
83+
ENV GROQ_API_KEY=${GROQ_API_KEY} \
84+
HuggingFace_API_KEY=${HuggingFace_API_KEY} \
85+
OPENAI_API_KEY=${OPENAI_API_KEY} \
86+
ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} \
87+
OPEN_ROUTER_API_KEY=${OPEN_ROUTER_API_KEY} \
88+
GOOGLE_GENERATIVE_AI_API_KEY=${GOOGLE_GENERATIVE_AI_API_KEY} \
89+
OLLAMA_API_BASE_URL=${OLLAMA_API_BASE_URL} \
90+
XAI_API_KEY=${XAI_API_KEY} \
91+
TOGETHER_API_KEY=${TOGETHER_API_KEY} \
92+
TOGETHER_API_BASE_URL=${TOGETHER_API_BASE_URL} \
93+
AWS_BEDROCK_CONFIG=${AWS_BEDROCK_CONFIG} \
94+
VITE_LOG_LEVEL=${VITE_LOG_LEVEL} \
95+
DEFAULT_NUM_CTX=${DEFAULT_NUM_CTX} \
96+
RUNNING_IN_DOCKER=true
97+
98+
RUN mkdir -p /app/run
99+
CMD ["pnpm", "run", "dev", "--host"]
100+
101+
# ---- production stage alias ----
102+
FROM runtime AS codinit-ai-production

apps/desktop/dmg-spec.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"title": "CodinIT.dev",
3+
"icon": "public/favicon.ico",
4+
"background": "assets/dmg-background.png",
5+
"icon-size": 80,
6+
"window": {
7+
"size": {
8+
"width": 600,
9+
"height": 400
10+
}
11+
},
12+
"contents": [
13+
{
14+
"x": 180,
15+
"y": 170,
16+
"type": "file",
17+
"path": "dist/CodinIT-darwin-arm64/CodinIT-dev.app"
18+
},
19+
{
20+
"x": 420,
21+
"y": 170,
22+
"type": "link",
23+
"path": "/Applications"
24+
}
25+
]
26+
}

apps/desktop/docker-compose.yaml

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
services:
2+
app-prod:
3+
image: codinit:production
4+
build:
5+
context: .
6+
dockerfile: Dockerfile
7+
target: codinit-production
8+
ports:
9+
- '5173:5173'
10+
env_file:
11+
- '.env'
12+
- '.env.local'
13+
environment:
14+
- NODE_ENV=production
15+
- COMPOSE_PROFILES=production
16+
# No strictly needed but serving as hints for Coolify
17+
- PORT=5173
18+
- GROQ_API_KEY=${GROQ_API_KEY}
19+
- HuggingFace_API_KEY=${HuggingFace_API_KEY}
20+
- OPENAI_API_KEY=${OPENAI_API_KEY}
21+
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
22+
- OPEN_ROUTER_API_KEY=${OPEN_ROUTER_API_KEY}
23+
- GOOGLE_GENERATIVE_AI_API_KEY=${GOOGLE_GENERATIVE_AI_API_KEY}
24+
- OLLAMA_API_BASE_URL=${OLLAMA_API_BASE_URL}
25+
- XAI_API_KEY=${XAI_API_KEY}
26+
- TOGETHER_API_KEY=${TOGETHER_API_KEY}
27+
- TOGETHER_API_BASE_URL=${TOGETHER_API_BASE_URL}
28+
- AWS_BEDROCK_CONFIG=${AWS_BEDROCK_CONFIG}
29+
- VITE_LOG_LEVEL=${VITE_LOG_LEVEL:-debug}
30+
- DEFAULT_NUM_CTX=${DEFAULT_NUM_CTX:-32768}
31+
- RUNNING_IN_DOCKER=true
32+
extra_hosts:
33+
- 'host.docker.internal:host-gateway'
34+
command: pnpm run dockerstart
35+
profiles:
36+
- production
37+
38+
app-dev:
39+
image: codinit:development
40+
build:
41+
target: codinit-development
42+
env_file:
43+
- '.env'
44+
- '.env.local'
45+
environment:
46+
- NODE_ENV=development
47+
- VITE_HMR_PROTOCOL=ws
48+
- VITE_HMR_HOST=localhost
49+
- VITE_HMR_PORT=5173
50+
- CHOKIDAR_USEPOLLING=true
51+
- WATCHPACK_POLLING=true
52+
- PORT=5173
53+
- GROQ_API_KEY=${GROQ_API_KEY}
54+
- HuggingFace_API_KEY=${HuggingFace_API_KEY}
55+
- OPENAI_API_KEY=${OPENAI_API_KEY}
56+
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
57+
- OPEN_ROUTER_API_KEY=${OPEN_ROUTER_API_KEY}
58+
- XAI_API_KEY=${XAI_API_KEY}
59+
- GOOGLE_GENERATIVE_AI_API_KEY=${GOOGLE_GENERATIVE_AI_API_KEY}
60+
- OLLAMA_API_BASE_URL=${OLLAMA_API_BASE_URL}
61+
- TOGETHER_API_KEY=${TOGETHER_API_KEY}
62+
- TOGETHER_API_BASE_URL=${TOGETHER_API_BASE_URL}
63+
- AWS_BEDROCK_CONFIG=${AWS_BEDROCK_CONFIG}
64+
- VITE_LOG_LEVEL=${VITE_LOG_LEVEL:-debug}
65+
- DEFAULT_NUM_CTX=${DEFAULT_NUM_CTX:-32768}
66+
- RUNNING_IN_DOCKER=true
67+
extra_hosts:
68+
- 'host.docker.internal:host-gateway'
69+
volumes:
70+
- type: bind
71+
source: .
72+
target: /app
73+
consistency: cached
74+
- /app/node_modules
75+
ports:
76+
- '5173:5173'
77+
command: pnpm run dev --host 0.0.0.0
78+
profiles: ['development', 'default']
79+
80+
app-prebuild:
81+
image: ghcr.io/gerome-elassaad/codingit:latest
82+
ports:
83+
- '5173:5173'
84+
environment:
85+
- NODE_ENV=production
86+
- COMPOSE_PROFILES=production
87+
# No strictly needed but serving as hints for Coolify
88+
- PORT=5173
89+
- OLLAMA_API_BASE_URL=http://127.0.0.1:11434
90+
- DEFAULT_NUM_CTX=${DEFAULT_NUM_CTX:-32768}
91+
- RUNNING_IN_DOCKER=true
92+
extra_hosts:
93+
- 'host.docker.internal:host-gateway'
94+
command: pnpm run dockerstart
95+
profiles:
96+
- prebuilt

apps/desktop/electron-builder.yml

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
appId: com.codinit.dev
2+
productName: CodinIT.dev
3+
4+
directories:
5+
buildResources: build
6+
output: dist
7+
8+
# Include built files and let electron-builder handle dependencies
9+
files:
10+
- build/electron/**/*
11+
- build/client/**/*
12+
- build/server/**/*
13+
- package.json
14+
- "!**/.git"
15+
- "!dist"
16+
- "!src"
17+
- "!app"
18+
- "!electron"
19+
- "!public"
20+
- "!tests"
21+
22+
# electron-builder will install production dependencies automatically
23+
24+
extraMetadata:
25+
main: build/electron/main/index.mjs
26+
27+
# Disable asar - it can cause hanging issues
28+
asar: false
29+
30+
mac:
31+
icon: public/icon.icns
32+
target: dmg
33+
identity: null
34+
hardenedRuntime: false
35+
gatekeeperAssess: false
36+
# macOS specific performance options
37+
type: development
38+
39+
dmg:
40+
title: ${productName} ${version}
41+
icon: public/icon.icns
42+
background: null
43+
window:
44+
width: 540
45+
height: 380
46+
contents:
47+
- x: 144
48+
y: 180
49+
type: file
50+
- x: 396
51+
y: 180
52+
type: link
53+
path: /Applications
54+
55+
win:
56+
icon: public/icon.png
57+
target: nsis
58+
59+
linux:
60+
icon: public/icon.png
61+
target: AppImage
62+
63+
# Performance and security optimizations
64+
npmRebuild: false
65+
nodeGypRebuild: false
66+
buildDependenciesFromSource: false
67+
68+
# Exclude all dev dependencies
69+
removePackageScripts: true

apps/desktop/electron-update.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
owner: Gerome-Elassaad
2+
repo: codinit-app
3+
provider: github
4+
private: true

apps/desktop/notarize.cjs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
const { notarize } = require('@electron/notarize');
2+
3+
exports.default = async function notarizing(context) {
4+
const { electronPlatformName, appOutDir } = context;
5+
6+
if (electronPlatformName !== 'darwin') {
7+
return;
8+
}
9+
10+
// Skip notarization when identity is null (development build)
11+
if (!context.packager.config.mac || context.packager.config.mac.identity === null) {
12+
console.log('Skipping notarization: identity is null');
13+
return;
14+
}
15+
16+
const appName = context.packager.appInfo.productFilename;
17+
const appBundleId = context.packager.config.appId;
18+
19+
try {
20+
console.log(`Notarizing ${appBundleId} found at ${appOutDir}/${appName}.app`);
21+
await notarize({
22+
tool: 'notarytool',
23+
appPath: `${appOutDir}/${appName}.app`,
24+
teamId: process.env.APPLE_TEAM_ID,
25+
});
26+
console.log(`Done notarizing ${appBundleId}`);
27+
} catch (error) {
28+
console.error('Notarization failed:', error);
29+
throw error;
30+
}
31+
};

0 commit comments

Comments
 (0)