diff --git a/docker/README.md b/docker/README.md index 1573ca816..458ce571b 100644 --- a/docker/README.md +++ b/docker/README.md @@ -40,5 +40,5 @@ docker network create mono-network # run postgres docker run --rm -it -d --name mono-pg --network mono-network -v /mnt/data/mono/pg-data:/var/lib/postgresql/data -p 5432:5432 mono-pg:0.1-pre-release docker run --rm -it -d --name mono-engine --network mono-network -v /mnt/data/mono/mono-data:/opt/mega -p 8000:8000 -p 22:9000 mono-engine:0.1-pre-release -docker run --rm -it -d --name mono-ui --network mono-network -e MEGA_HOST=http://mono-engine:8000 -e MOON_HOST=http://localhost:3000 -p 3000:3000 mono-ui:0.1-pre-release +docker run --rm -it -d --name mono-ui --network mono-network -e MEGA_HOST=http://git.gitmono.com -e MOON_HOST=https://console.gitmono.com -p 3000:3000 mono-ui:0.1-pre-release ``` \ No newline at end of file diff --git a/docker/mono-ui-dockerfile b/docker/mono-ui-dockerfile index e56bac5ef..27a32657d 100644 --- a/docker/mono-ui-dockerfile +++ b/docker/mono-ui-dockerfile @@ -1,22 +1,66 @@ -FROM node:22-alpine +## exmaple: https://github.com/vercel/next.js/blob/canary/examples/with-docker/Dockerfile +FROM node:20-alpine AS base +# Install dependencies only when needed +FROM base AS deps +# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. +RUN apk add --no-cache libc6-compat WORKDIR /app # set mirror for npm # RUN npm config set registry https://registry.npmmirror.com +# Install dependencies based on the preferred package manager COPY ./moon/package*.json ./ - RUN npm install + +# Rebuild the source code only when needed +FROM base AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules COPY ./moon . +# Next.js collects completely anonymous telemetry data about general usage. +# Learn more here: https://nextjs.org/telemetry +# Uncomment the following line in case you want to disable telemetry during the build. +ENV NEXT_TELEMETRY_DISABLED=1 + RUN npm run build +# Production image, copy all the files and run next +FROM base AS runner +WORKDIR /app + +ENV NODE_ENV=production +# Uncomment the following line in case you want to disable telemetry during runtime. +ENV NEXT_TELEMETRY_DISABLED=1 + +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs + +COPY --from=builder /app/public ./public + COPY ./docker/start-moon.sh /app/start-moon.sh RUN chmod +x /app/start-moon.sh +# Set the correct permission for prerender cache +RUN mkdir .next +RUN chown nextjs:nodejs .next + +# Automatically leverage output traces to reduce image size +# https://nextjs.org/docs/advanced-features/output-file-tracing +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + +USER nextjs + EXPOSE 3000 +ENV PORT=3000 + +# server.js is created by next build from the standalone output +# https://nextjs.org/docs/pages/api-reference/next-config-js/output +ENV HOSTNAME="0.0.0.0" ENTRYPOINT ["/bin/sh", "/app/start-moon.sh"] \ No newline at end of file diff --git a/docker/start-moon.sh b/docker/start-moon.sh index feede2657..744b072a7 100755 --- a/docker/start-moon.sh +++ b/docker/start-moon.sh @@ -1,4 +1,14 @@ #!/bin/bash -# TODO: run `npm run s start` didn't work, use `npm run dev` temporarily -exec npm run start \ No newline at end of file +# user must set the NEXT_PUBLIC_API_URL +if [ -z "$MEGA_HOST" ]; then + echo "MEGA_HOST is not set" + exit 1 +fi + +if [ -z "$MOON_HOST" ]; then + echo "MOON_HOST is not set" + exit 1 +fi + +exec node server.js \ No newline at end of file diff --git a/moon/next.config.js b/moon/next.config.js index d098ce912..d9f02c93a 100644 --- a/moon/next.config.js +++ b/moon/next.config.js @@ -1,6 +1,7 @@ /** @type {import('next').NextConfig} */ const nextConfig = { + output: "standalone", images: { remotePatterns: [ { diff --git a/moon/package.json b/moon/package.json index 0f5d29a57..bf0379a30 100644 --- a/moon/package.json +++ b/moon/package.json @@ -10,8 +10,8 @@ }, "dependencies": { "@ant-design/icons": "^5.4.0", - "@ant-design/nextjs-registry": "^1.0.0", - "@headlessui/react": "^2.1.2", + "@ant-design/nextjs-registry": "^1.0.1", + "@headlessui/react": "^2.1.3", "@headlessui/tailwindcss": "^0.2.1", "@heroicons/react": "^2.1.5", "@lexical/react": "^0.17.0", @@ -22,7 +22,7 @@ "github-markdown-css": "^5.6.1", "highlight.js": "^11.10.0", "lexical": "^0.17.0", - "next": "^14.2.5", + "next": "^14.2.6", "prism-react-renderer": "^2.3.1", "react": "^18.3.1", "react-dom": "^18.3.1", diff --git a/moon/src/app/application-layout.tsx b/moon/src/app/application-layout.tsx index 1d06c6bbc..6cf7b67ba 100644 --- a/moon/src/app/application-layout.tsx +++ b/moon/src/app/application-layout.tsx @@ -101,7 +101,7 @@ export function ApplicationLayout({ fetchMessage(); } async function fetchMessage() { - const response = await fetch('http://localhost:3000/api/auth/github/user'); + const response = await fetch('/api/auth/github/user'); const user = await response.json(); setUser(user.data); } diff --git a/moon/src/app/auth/github/callback/page.tsx b/moon/src/app/auth/github/callback/page.tsx index 6cb1bd253..a69a179ee 100644 --- a/moon/src/app/auth/github/callback/page.tsx +++ b/moon/src/app/auth/github/callback/page.tsx @@ -15,7 +15,7 @@ export default function AuthPage({ searchParams }) { useEffect(() => { async function fetchData() { try { - const res = await fetch(`http://localhost:3000/api/env`); + const res = await fetch(`/api/env`); if (!res.ok) { throw new Error('Failed to fetch data'); } diff --git a/moon/src/app/blob/[...path]/page.tsx b/moon/src/app/blob/[...path]/page.tsx index 590833ae3..840ffe814 100644 --- a/moon/src/app/blob/[...path]/page.tsx +++ b/moon/src/app/blob/[...path]/page.tsx @@ -27,7 +27,7 @@ export default function BlobPage({ params }: { params: { path: string[] } }) { } async function getReadmeContent(pathname: string) { - const res = await fetch(`http://localhost:3000/api/blob?path=${pathname}`); + const res = await fetch(`/api/blob?path=${pathname}`); const response = await res.json(); const directory = response.data.data; return directory diff --git a/moon/src/app/login/page.tsx b/moon/src/app/login/page.tsx index 7b58f9699..6413d321b 100644 --- a/moon/src/app/login/page.tsx +++ b/moon/src/app/login/page.tsx @@ -1,6 +1,5 @@ -'use server' - import Image from "next/image"; +export const revalidate = 0 export default async function Login() { const res = await fetch(`http://localhost:3000/api/env`); diff --git a/moon/src/app/mr/[id]/page.tsx b/moon/src/app/mr/[id]/page.tsx index 2139cbb36..975e3d51e 100644 --- a/moon/src/app/mr/[id]/page.tsx +++ b/moon/src/app/mr/[id]/page.tsx @@ -8,7 +8,7 @@ export default function MRDetailPage( { params }: { params: { id: string } }) { useEffect(() => { const fetchData = async () => { try { - const res = await fetch(`http://localhost:3000/api/mr/${params.id}/detail`); + const res = await fetch(`/api/mr/${params.id}/detail`); const response = await res.json(); const data = response.data.data; setMrDetail(data); diff --git a/moon/src/app/mr/page.tsx b/moon/src/app/mr/page.tsx index 1d3d87182..4e22bcb0a 100644 --- a/moon/src/app/mr/page.tsx +++ b/moon/src/app/mr/page.tsx @@ -7,7 +7,7 @@ export default function MergeRequestPage() { useEffect(() => { const fetchData = async () => { try { - const res = await fetch(`http://localhost:3000/api/mr/list?status=`); + const res = await fetch(`/api/mr/list?status=`); const response = await res.json(); const mrList = response.data.data; setMrList(mrList); diff --git a/moon/src/app/tree/[...path]/page.tsx b/moon/src/app/tree/[...path]/page.tsx index b1293f74c..fcff29a31 100644 --- a/moon/src/app/tree/[...path]/page.tsx +++ b/moon/src/app/tree/[...path]/page.tsx @@ -33,7 +33,7 @@ export default function Page({ params }: { params: { path: string[] } }) { } async function getDirectory(pathname: string) { - const res = await fetch(`http://localhost:3000/api/tree/commit-info?path=${pathname}`); + const res = await fetch(`/api/tree/commit-info?path=${pathname}`); const response = await res.json(); const directory = response.data.data; return directory @@ -43,7 +43,7 @@ async function getReadmeContent(pathname, directory) { var readmeContent = ''; for (const project of directory || []) { if (project.name === 'README.md' && project.content_type === 'file') { - const res = await fetch(`http://localhost:3000/api/blob?path=${pathname}/README.md`); + const res = await fetch(`/api/blob?path=${pathname}/README.md`); const response = await res.json(); readmeContent = response.data.data; break;