diff --git a/apps/frontend/.env.local.example b/apps/frontend/.env.local.example index 141a04f5..d312503f 100644 --- a/apps/frontend/.env.local.example +++ b/apps/frontend/.env.local.example @@ -1,5 +1,6 @@ THUMBNAIL_URL=localhost #THUMBNAIL_URL=localhost:9000 +APP_ENV=local NEXT_PUBLIC_RECAPTCHA_SITE_KEY= NEXT_PUBLIC_URL=http://localhost:3000 NEXT_PUBLIC_API_URL=http://localhost:4000/v1 diff --git a/apps/frontend/next.config.mjs b/apps/frontend/next.config.mjs index 46a3c3fd..b3992d56 100644 --- a/apps/frontend/next.config.mjs +++ b/apps/frontend/next.config.mjs @@ -2,7 +2,12 @@ import createMDX from '@next/mdx'; /** @type {import('next').NextConfig} */ +const appEnv = process.env.APP_ENV ?? 'local'; + const nextConfig = { + env: { + NEXT_PUBLIC_APP_ENV: appEnv, + }, pageExtensions: ['js', 'jsx', 'md', 'mdx', 'ts', 'tsx'], // Externalize packages that use Node.js built-in modules for server components serverExternalPackages: ['@nbw/database', '@nbw/config'], diff --git a/apps/frontend/src/app/layout.tsx b/apps/frontend/src/app/layout.tsx index 9e25cfbf..f3f6dbf5 100644 --- a/apps/frontend/src/app/layout.tsx +++ b/apps/frontend/src/app/layout.tsx @@ -13,6 +13,7 @@ import { WebSite, WithContext } from 'schema-dts'; import DetectAdBlock from '../modules/shared/components/client/ads/DetectAdBlock'; import GoogleAdSense from '../modules/shared/components/GoogleAdSense'; +import { isProductionAppEnv } from '@web/lib/appEnv'; import { TooltipProvider } from '../modules/shared/components/tooltip'; // Pre-import FontAwesome CSS to avoid FOUC @@ -126,10 +127,9 @@ export default function RootLayout({ - {process.env.NODE_ENV === 'production' && - process.env.NEXT_PUBLIC_GA_ID && ( - - )} + {isProductionAppEnv() && process.env.NEXT_PUBLIC_GA_ID && ( + + )} ); diff --git a/apps/frontend/src/app/robots.ts b/apps/frontend/src/app/robots.ts index ceb96f91..a83bd3a3 100644 --- a/apps/frontend/src/app/robots.ts +++ b/apps/frontend/src/app/robots.ts @@ -1,8 +1,9 @@ import { MetadataRoute } from 'next'; +import { isProductionAppEnv } from '@web/lib/appEnv'; + export default function robots(): MetadataRoute.Robots { - // Check if the current deployment is Production - const isProd = process.env.NODE_ENV === 'production'; + const isProd = isProductionAppEnv(); if (isProd) { return { diff --git a/apps/frontend/src/lib/appEnv.ts b/apps/frontend/src/lib/appEnv.ts new file mode 100644 index 00000000..eed16306 --- /dev/null +++ b/apps/frontend/src/lib/appEnv.ts @@ -0,0 +1,29 @@ +export const APP_ENVS = [ + 'local', + 'development', + 'staging', + 'production', +] as const; + +export type AppEnv = (typeof APP_ENVS)[number]; + +function parseAppEnv(value: string | undefined): AppEnv { + if (value && APP_ENVS.includes(value as AppEnv)) { + return value as AppEnv; + } + + return 'local'; +} + +/** Deployment environment for app behavior (not Node.js build optimizations). */ +export function getAppEnv(): AppEnv { + return parseAppEnv(process.env.APP_ENV ?? process.env.NEXT_PUBLIC_APP_ENV); +} + +export function isProductionAppEnv(): boolean { + return getAppEnv() === 'production'; +} + +export function isLocalAppEnv(): boolean { + return getAppEnv() === 'local'; +} diff --git a/apps/frontend/src/modules/auth/components/client/login.util.ts b/apps/frontend/src/modules/auth/components/client/login.util.ts index 98750629..f0362e1d 100644 --- a/apps/frontend/src/modules/auth/components/client/login.util.ts +++ b/apps/frontend/src/modules/auth/components/client/login.util.ts @@ -2,6 +2,8 @@ //import { useRouter } from 'next/navigation'; import { useEffect } from 'react'; +import { isLocalAppEnv } from '@web/lib/appEnv'; + export function deleteAuthCookies() { // delete cookie const cookiesToBeDeleted = ['refresh_token', 'token']; @@ -9,7 +11,7 @@ export function deleteAuthCookies() { cookiesToBeDeleted.forEach((cookie) => { if (!document) return; - if (process.env.NODE_ENV === 'development') { + if (isLocalAppEnv()) { document.cookie = `${cookie}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=/`; } else { document.cookie = `${cookie}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=/; Domain=${process.env.NEXT_PUBLIC_APP_DOMAIN}`; diff --git a/apps/frontend/src/modules/shared/components/GoogleAdSense.tsx b/apps/frontend/src/modules/shared/components/GoogleAdSense.tsx index 065ca205..f03aa4b6 100644 --- a/apps/frontend/src/modules/shared/components/GoogleAdSense.tsx +++ b/apps/frontend/src/modules/shared/components/GoogleAdSense.tsx @@ -1,5 +1,7 @@ +import { isProductionAppEnv } from '@web/lib/appEnv'; + const GoogleAdSense = ({ pId }: { pId?: string }) => { - if (process.env.NODE_ENV !== 'production' || !pId) { + if (!isProductionAppEnv() || !pId) { return null; } diff --git a/apps/frontend/src/modules/shared/components/client/ads/useAdSenseClient.tsx b/apps/frontend/src/modules/shared/components/client/ads/useAdSenseClient.tsx index 714b7375..4791574b 100644 --- a/apps/frontend/src/modules/shared/components/client/ads/useAdSenseClient.tsx +++ b/apps/frontend/src/modules/shared/components/client/ads/useAdSenseClient.tsx @@ -1,8 +1,10 @@ import { useMemo } from 'react'; +import { isProductionAppEnv } from '@web/lib/appEnv'; + const useAdSenseClient = () => { const pubId = useMemo(() => { - if (process.env.NODE_ENV !== 'production') { + if (!isProductionAppEnv()) { return null; }