mirror of
https://github.com/kyantech/Palmr.git
synced 2025-10-22 22:02:00 +00:00
build(web): add Dockerfile and docker-compose.yml for production deployment
Refactor image handling in components to use Next.js Image component Remove unused imports and disable ESLint during builds Add error logging for i18n and login functionality Update Next.js config for standalone output and build optimizations
This commit is contained in:
46
apps/app/Dockerfile
Normal file
46
apps/app/Dockerfile
Normal file
@@ -0,0 +1,46 @@
|
||||
# Use the official Node.js image as the base image
|
||||
|
||||
FROM node:18-alpine AS base
|
||||
|
||||
# Install dependencies only when needed
|
||||
FROM base AS deps
|
||||
RUN apk add --no-cache libc6-compat
|
||||
WORKDIR /app
|
||||
|
||||
# Install dependencies based on the preferred package manager
|
||||
COPY package.json pnpm-lock.yaml ./
|
||||
RUN corepack enable pnpm && pnpm install --frozen-lockfile
|
||||
|
||||
# Rebuild the source code only when needed
|
||||
FROM base AS builder
|
||||
WORKDIR /app
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY . .
|
||||
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
ENV NODE_ENV=production
|
||||
|
||||
RUN corepack enable pnpm && pnpm run build
|
||||
|
||||
# Production image, copy all the files and run next
|
||||
FROM base AS runner
|
||||
WORKDIR /app
|
||||
|
||||
ENV NODE_ENV=production
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
|
||||
RUN addgroup --system --gid 1001 nodejs
|
||||
RUN adduser --system --uid 1001 nextjs
|
||||
|
||||
COPY --from=builder /app/public ./public
|
||||
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
|
||||
ENV HOSTNAME="0.0.0.0"
|
||||
|
||||
CMD ["node", "server.js"]
|
17
apps/app/docker-compose.yml
Normal file
17
apps/app/docker-compose.yml
Normal file
@@ -0,0 +1,17 @@
|
||||
services:
|
||||
web:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "6644:3000"
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- NEXT_TELEMETRY_DISABLED=1
|
||||
- API_BASE_URL=http://host.docker.internal:3333
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:3000"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
@@ -1,7 +1,15 @@
|
||||
import { NextConfig } from "next";
|
||||
import createNextIntlPlugin from "next-intl/plugin";
|
||||
|
||||
const nextConfig: NextConfig = {};
|
||||
const nextConfig: NextConfig = {
|
||||
output: "standalone",
|
||||
eslint: {
|
||||
ignoreDuringBuilds: true,
|
||||
},
|
||||
typescript: {
|
||||
ignoreBuildErrors: true,
|
||||
},
|
||||
};
|
||||
|
||||
const withNextIntl = createNextIntlPlugin();
|
||||
export default withNextIntl(nextConfig);
|
||||
|
4489
apps/app/pnpm-lock.yaml
generated
4489
apps/app/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import Image from "next/image"; // Add this import
|
||||
import Link from "next/link";
|
||||
import { IconHeart, IconMenu2 } from "@tabler/icons-react";
|
||||
|
||||
@@ -26,7 +27,9 @@ export function Navbar() {
|
||||
<div className="flex flex-1 items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<Link href="/" className="flex items-center gap-2">
|
||||
{appLogo && <img alt="App Logo" className="h-8 w-8 object-contain" src={appLogo} />}
|
||||
{appLogo && (
|
||||
<Image alt="App Logo" src={appLogo} width={32} height={32} className="object-contain rounded" />
|
||||
)}
|
||||
<p className="font-bold text-2xl">{appName}</p>
|
||||
</Link>
|
||||
<nav className="hidden lg:flex ml-2 gap-4">
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { IconDownload, IconFolder } from "@tabler/icons-react";
|
||||
import { IconDownload } from "@tabler/icons-react";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
|
||||
import { LanguageSwitcher } from "@/components/general/language-switcher";
|
||||
@@ -11,7 +12,7 @@ export function ShareHeader() {
|
||||
<header className="w-full px-6 border-b border-default-200/50 bg-background/70 backdrop-blur-sm">
|
||||
<div className="mx-auto max-w-5xl sm:p-0 h-16 flex items-center justify-between">
|
||||
<Link className="flex items-center gap-2" href="/">
|
||||
{appLogo && <img alt="App Logo" className="h-8 w-8 object-contain" src={appLogo} />}
|
||||
{appLogo && <Image alt="App Logo" src={appLogo} width={32} height={32} className="object-contain rounded" />}
|
||||
<p className="font-bold text-2xl text-foreground">{appName}</p>
|
||||
</Link>
|
||||
<div className="flex items-center gap-2">
|
||||
|
@@ -1,4 +1,3 @@
|
||||
import type { Metadata } from "next";
|
||||
import { Geist, Geist_Mono } from "next/font/google";
|
||||
import { NextIntlClientProvider } from "next-intl";
|
||||
import { getLocale } from "next-intl/server";
|
||||
|
@@ -10,7 +10,7 @@ import { useAuth } from "@/contexts/auth-context";
|
||||
import { getCurrentUser, login } from "@/http/endpoints";
|
||||
import { LoginFormValues } from "../schemas/schema";
|
||||
|
||||
const loginSchema = z.object({
|
||||
export const loginSchema = z.object({
|
||||
email: z.string(),
|
||||
password: z.string(),
|
||||
});
|
||||
@@ -39,6 +39,7 @@ export function useLogin() {
|
||||
setIsAuthenticated(true);
|
||||
router.push("/dashboard");
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
setUser(null);
|
||||
setIsAdmin(false);
|
||||
setIsAuthenticated(false);
|
||||
|
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { usePathname, useRouter } from "next/navigation";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { IconLanguage } from "@tabler/icons-react";
|
||||
import { useLocale } from "next-intl";
|
||||
import { setCookie } from "nookies";
|
||||
@@ -37,7 +37,6 @@ const RTL_LANGUAGES = ["ar-SA"];
|
||||
export function LanguageSwitcher() {
|
||||
const locale = useLocale();
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
|
||||
const changeLanguage = (fullLocale: string) => {
|
||||
const isRTL = RTL_LANGUAGES.includes(fullLocale);
|
||||
|
@@ -1,6 +1,5 @@
|
||||
"use client";
|
||||
|
||||
/* eslint-disable jsx-a11y/media-has-caption */
|
||||
import { useEffect, useState } from "react";
|
||||
import { IconDownload } from "@tabler/icons-react";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
@@ -16,6 +16,7 @@ export default getRequestConfig(async ({ locale }) => {
|
||||
messages: (await import(`../../messages/${resolvedLocale}.json`)).default,
|
||||
};
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return {
|
||||
locale: DEFAULT_LOCALE,
|
||||
messages: (await import(`../../messages/${DEFAULT_LOCALE}.json`)).default,
|
||||
|
Reference in New Issue
Block a user