diff options
| author | Jan T <jans.tuomi@gmail.com> | 2024-02-14 17:18:30 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-02-14 10:18:30 -0500 |
| commit | 2af066038351ab0634c359a688fe712a539992b4 (patch) | |
| tree | 3ca4bb30f4813ff7e7d87354c5fdd83dcb19cb59 /src | |
| parent | 50525ad8810de356856eb098a1e0882ce3607b9f (diff) | |
Optimize docker image size (#91)
* Move prisma to runtime dependencies
* Optimize Dockerfile and build script
* Fix: remove mention of generated next-env.d.ts in Dockerfile
* Add missing reset.d.ts file to Dockerfile
* Remove compression steps from Dockerfile and entrypoint script
* Add an env file with mocked env vars added for Docker production builds
* Use server actions to get runtime env vars
* Refactor types and names
* Rollback serverActions, use parsed Zod object for runtime env
* Reintroduce featureFlags object to avoid passing secret envs to the frontend
* Improve string to boolean coercion
Co-authored-by: Sebastien Castiel <sebastien@castiel.me>
* Run prettier autoformat
* Fix type issue, rename function to match behaviour better
---------
Co-authored-by: Lauri Vuorela <lauri.vuorela@gmail.com>
Co-authored-by: Sebastien Castiel <sebastien@castiel.me>
Diffstat (limited to 'src')
| -rw-r--r-- | src/app/groups/[groupId]/expenses/[expenseId]/edit/page.tsx | 2 | ||||
| -rw-r--r-- | src/app/groups/[groupId]/expenses/create/page.tsx | 2 | ||||
| -rw-r--r-- | src/components/expense-form.tsx | 7 | ||||
| -rw-r--r-- | src/lib/env.ts | 20 | ||||
| -rw-r--r-- | src/lib/featureFlags.ts | 15 |
5 files changed, 41 insertions, 5 deletions
diff --git a/src/app/groups/[groupId]/expenses/[expenseId]/edit/page.tsx b/src/app/groups/[groupId]/expenses/[expenseId]/edit/page.tsx index 65b2b50..2514a77 100644 --- a/src/app/groups/[groupId]/expenses/[expenseId]/edit/page.tsx +++ b/src/app/groups/[groupId]/expenses/[expenseId]/edit/page.tsx @@ -6,6 +6,7 @@ import { getExpense, updateExpense, } from '@/lib/api' +import { getRuntimeFeatureFlags } from '@/lib/featureFlags' import { expenseFormSchema } from '@/lib/schemas' import { Metadata } from 'next' import { notFound, redirect } from 'next/navigation' @@ -47,6 +48,7 @@ export default async function EditExpensePage({ categories={categories} onSubmit={updateExpenseAction} onDelete={deleteExpenseAction} + runtimeFeatureFlags={await getRuntimeFeatureFlags()} /> </Suspense> ) diff --git a/src/app/groups/[groupId]/expenses/create/page.tsx b/src/app/groups/[groupId]/expenses/create/page.tsx index 2d580d3..6398fd1 100644 --- a/src/app/groups/[groupId]/expenses/create/page.tsx +++ b/src/app/groups/[groupId]/expenses/create/page.tsx @@ -1,6 +1,7 @@ import { cached } from '@/app/cached-functions' import { ExpenseForm } from '@/components/expense-form' import { createExpense, getCategories } from '@/lib/api' +import { getRuntimeFeatureFlags } from '@/lib/featureFlags' import { expenseFormSchema } from '@/lib/schemas' import { Metadata } from 'next' import { notFound, redirect } from 'next/navigation' @@ -32,6 +33,7 @@ export default async function ExpensePage({ group={group} categories={categories} onSubmit={createExpenseAction} + runtimeFeatureFlags={await getRuntimeFeatureFlags()} /> </Suspense> ) diff --git a/src/components/expense-form.tsx b/src/components/expense-form.tsx index fd3f6e2..a7e549c 100644 --- a/src/components/expense-form.tsx +++ b/src/components/expense-form.tsx @@ -35,6 +35,7 @@ import { SelectValue, } from '@/components/ui/select' import { getCategories, getExpense, getGroup, randomId } from '@/lib/api' +import { RuntimeFeatureFlags } from '@/lib/featureFlags' import { ExpenseFormValues, expenseFormSchema } from '@/lib/schemas' import { cn } from '@/lib/utils' import { zodResolver } from '@hookform/resolvers/zod' @@ -52,6 +53,7 @@ export type Props = { categories: NonNullable<Awaited<ReturnType<typeof getCategories>>> onSubmit: (values: ExpenseFormValues) => Promise<void> onDelete?: () => Promise<void> + runtimeFeatureFlags: RuntimeFeatureFlags } export function ExpenseForm({ @@ -60,6 +62,7 @@ export function ExpenseForm({ categories, onSubmit, onDelete, + runtimeFeatureFlags, }: Props) { const isCreate = expense === undefined const searchParams = useSearchParams() @@ -161,7 +164,7 @@ export function ExpenseForm({ {...field} onBlur={async () => { field.onBlur() // avoid skipping other blur event listeners since we overwrite `field` - if (process.env.NEXT_PUBLIC_ENABLE_CATEGORY_EXTRACT) { + if (runtimeFeatureFlags.enableCategoryExtract) { setCategoryLoading(true) const { categoryId } = await extractCategoryFromTitle( field.value, @@ -541,7 +544,7 @@ export function ExpenseForm({ </CardContent> </Card> - {process.env.NEXT_PUBLIC_ENABLE_EXPENSE_DOCUMENTS && ( + {runtimeFeatureFlags.enableExpenseDocuments && ( <Card className="mt-4"> <CardHeader> <CardTitle className="flex justify-between"> diff --git a/src/lib/env.ts b/src/lib/env.ts index 927e756..920df14 100644 --- a/src/lib/env.ts +++ b/src/lib/env.ts @@ -1,5 +1,10 @@ import { ZodIssueCode, z } from 'zod' +const interpretEnvVarAsBool = (val: unknown): boolean => { + if (typeof val !== 'string') return false + return ['true', 'yes', '1', 'on'].includes(val.toLowerCase()) +} + const envSchema = z .object({ POSTGRES_URL_NON_POOLING: z.string().url(), @@ -12,14 +17,23 @@ const envSchema = z ? `https://${process.env.VERCEL_URL}` : 'http://localhost:3000', ), - NEXT_PUBLIC_ENABLE_EXPENSE_DOCUMENTS: z.coerce.boolean().default(false), + NEXT_PUBLIC_ENABLE_EXPENSE_DOCUMENTS: z.preprocess( + interpretEnvVarAsBool, + z.boolean().default(false), + ), S3_UPLOAD_KEY: z.string().optional(), S3_UPLOAD_SECRET: z.string().optional(), S3_UPLOAD_BUCKET: z.string().optional(), S3_UPLOAD_REGION: z.string().optional(), S3_UPLOAD_ENDPOINT: z.string().optional(), - NEXT_PUBLIC_ENABLE_RECEIPT_EXTRACT: z.coerce.boolean().default(false), - NEXT_PUBLIC_ENABLE_CATEGORY_EXTRACT: z.coerce.boolean().default(false), + NEXT_PUBLIC_ENABLE_RECEIPT_EXTRACT: z.preprocess( + interpretEnvVarAsBool, + z.boolean().default(false), + ), + NEXT_PUBLIC_ENABLE_CATEGORY_EXTRACT: z.preprocess( + interpretEnvVarAsBool, + z.boolean().default(false), + ), OPENAI_API_KEY: z.string().optional(), }) .superRefine((env, ctx) => { diff --git a/src/lib/featureFlags.ts b/src/lib/featureFlags.ts new file mode 100644 index 0000000..e57ca9c --- /dev/null +++ b/src/lib/featureFlags.ts @@ -0,0 +1,15 @@ +'use server' + +import { env } from './env' + +export async function getRuntimeFeatureFlags() { + return { + enableExpenseDocuments: env.NEXT_PUBLIC_ENABLE_EXPENSE_DOCUMENTS, + enableReceiptExtract: env.NEXT_PUBLIC_ENABLE_RECEIPT_EXTRACT, + enableCategoryExtract: env.NEXT_PUBLIC_ENABLE_CATEGORY_EXTRACT, + } +} + +export type RuntimeFeatureFlags = Awaited< + ReturnType<typeof getRuntimeFeatureFlags> +> |
