From 1c90cf63ce01cc00d5dffa056262a68978643fe9 Mon Sep 17 00:00:00 2001 From: Elias Schneider Date: Mon, 2 May 2022 08:22:53 +0200 Subject: [PATCH] Change environment variables strategy --- .env.example | 5 ++--- Dockerfile | 14 +++++++++++--- README.md | 7 +++---- docker-compose.yml | 4 ++-- package.json | 1 - src/components/upload/Dropzone.tsx | 4 +++- src/pages/_app.tsx | 26 +++++++++++++++++--------- src/pages/api/config.ts | 15 +++++++++++++++ src/utils/appwrite.util.ts | 3 +-- src/utils/appwriteServer.util.ts | 2 +- src/utils/config.util.ts | 12 ++++++++++++ 11 files changed, 67 insertions(+), 26 deletions(-) create mode 100644 src/pages/api/config.ts create mode 100644 src/utils/config.util.ts diff --git a/.env.example b/.env.example index a9f88cc0..e8bee8ff 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,3 @@ APPWRITE_FUNCTION_API_KEY= -NEXT_PUBLIC_APPWRITE_HOST=http://localhost:86/v1 -# Must be the same as in the _APP_STORAGE_LIMIT in the Appwrite env file -NEXT_PUBLIC_MAX_FILE_SIZE=300000000 \ No newline at end of file +PUBLIC_APPWRITE_HOST=http://localhost/v1 +PUBLIC_MAX_FILE_SIZE="300000000" # Must be the same as in the _APP_STORAGE_LIMIT in the Appwrite env file \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 5b76f30a..24a68b7b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,6 +4,12 @@ WORKDIR /opt/app COPY package.json package-lock.json ./ RUN npm ci +FROM node:16-alpine AS builder +ENV NODE_ENV=production +WORKDIR /opt/app +COPY . . +COPY --from=deps /opt/app/node_modules ./node_modules +RUN npm run build FROM node:16-alpine AS script-builder WORKDIR /opt/app @@ -17,9 +23,11 @@ RUN ncc build index.ts FROM node:16-alpine AS runner WORKDIR /opt/app ENV NODE_ENV=production -COPY . . -COPY --from=deps /opt/app/node_modules ./node_modules +COPY --from=builder /opt/app/next.config.js ./ +COPY --from=builder /opt/app/public ./public +COPY --from=builder /opt/app/.next ./.next +COPY --from=builder /opt/app/node_modules ./node_modules COPY --from=script-builder /opt/app/.setup/dist/index.js ./scripts/setup.js EXPOSE 3000 -CMD npm run build && npm start \ No newline at end of file +CMD ["node_modules/.bin/next", "start"] \ No newline at end of file diff --git a/README.md b/README.md index 02f23d25..594d97ce 100644 --- a/README.md +++ b/README.md @@ -30,14 +30,14 @@ First of all you have to start the Docker container. The container is now running. Now you have to setup the Appwrite structure, but no worries I made a setup script. -To start the script run `docker-compose exec pingvin-share node scripts/setup.js`. +To run the script run `docker-compose exec pingvin-share node scripts/setup.js`. You're almost done, now you have to change your environment variables that they fit to your setup. 1. Go to your Appwrite console, visit "API Keys" and copy the "Functions API Key" secret to your clipboard. 2. Paste the key to the `APPWRITE_FUNCTION_API_KEY` variable in the `.env` file -3. Change `NEXT_PUBLIC_APPWRITE_HOST` in the `.env` file to the host where your Appwrite instance runs -4. Change `NEXT_PUBLIC_MAX_FILE_SIZE` in the `.env` file to the max file size limit you want +3. Change `PUBLIC_APPWRITE_HOST` in the `.env` file to the host where your Appwrite instance runs +4. Change `PUBLIC_MAX_FILE_SIZE` in the `.env` file to the max file size limit you want ## Known issues / Limitations @@ -45,7 +45,6 @@ Pingvin Share is currently in beta and there are issues and limitations that sho - `DownloadAll` generates the zip file on the client side. This takes alot of time. Because of that I temporarily limited this function to maximal 150 MB. - If a user knows the share id, he can list and download the files directly from the Appwrite API even if the share is secured by a password or a visitor limit. -- Because NextJS injects environments variables at build time, the website must be rebuilt when an environment variable changes. At the moment the container rebuilts the website after every restart. This takes some time. ## Contribute diff --git a/docker-compose.yml b/docker-compose.yml index 73175a15..36f65eb3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,5 +6,5 @@ services: image: stonith404/pingvin-share environment: - APPWRITE_FUNCTION_API_KEY=${APPWRITE_FUNCTION_API_KEY} - - NEXT_PUBLIC_APPWRITE_HOST=${NEXT_PUBLIC_APPWRITE_HOST} - - NEXT_PUBLIC_MAX_FILE_SIZE=${NEXT_PUBLIC_MAX_FILE_SIZE} \ No newline at end of file + - PUBLIC_APPWRITE_HOST=${PUBLIC_APPWRITE_HOST} + - PUBLIC_MAX_FILE_SIZE=${PUBLIC_MAX_FILE_SIZE} \ No newline at end of file diff --git a/package.json b/package.json index 20669b78..b4763062 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,6 @@ "build": "next build", "start": "next start", "lint": "next lint", - "start:docker": "docker build -t pingvin-share:latest . && docker run pingvin-share:latest", "init:appwrite": "cd .setup && npm install && npx ts-node index.ts", "deploy": "docker buildx build -t stonith404/pingvin-share --platform linux/amd64,linux/arm64 --push ." }, diff --git a/src/components/upload/Dropzone.tsx b/src/components/upload/Dropzone.tsx index f096a241..3e1dbdf3 100644 --- a/src/components/upload/Dropzone.tsx +++ b/src/components/upload/Dropzone.tsx @@ -10,6 +10,7 @@ import { import { Dropzone as MantineDropzone, DropzoneStatus } from "@mantine/dropzone"; import React, { Dispatch, ForwardedRef, SetStateAction, useRef } from "react"; import { CloudUpload, Upload } from "tabler-icons-react"; +import { useConfig } from "../../utils/config.util"; import toast from "../../utils/toast.util"; const useStyles = createStyles((theme) => ({ @@ -52,13 +53,14 @@ const Dropzone = ({ setFiles: Dispatch>; }) => { const theme = useMantineTheme(); + const config = useConfig() const { classes } = useStyles(); const openRef = useRef<() => void>(); return (
{ toast.error(e[0].errors[0].message); }} diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 3edb1fae..6da050e2 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -14,7 +14,9 @@ import "../../styles/globals.css"; import ThemeProvider from "../components/mantine/ThemeProvider"; import Header from "../components/navBar/NavBar"; import globalStyle from "../styles/global.style"; +import aw from "../utils/appwrite.util"; import authUtil, { IsSignedInContext } from "../utils/auth.util"; +import configUtil, { ConfigContext } from "../utils/config.util"; import { GlobalLoadingContext } from "../utils/loading.util"; function App(props: AppProps & { colorScheme: ColorScheme }) { @@ -26,13 +28,17 @@ function App(props: AppProps & { colorScheme: ColorScheme }) { const [isLoading, setIsLoading] = useState(true); const [isSignedIn, setIsSignedIn] = useState(false); - const checkIfSignedIn = async () => { + let environmentVariables: any = {}; + + const getInitalData = async () => { setIsLoading(true); + environmentVariables = await configUtil.getGonfig(); + aw.setEndpoint(environmentVariables.APPWRITE_HOST); setIsSignedIn(await authUtil.isSignedIn()); setIsLoading(false); }; useEffect(() => { - checkIfSignedIn(); + getInitalData(); }, []); return ( @@ -44,13 +50,15 @@ function App(props: AppProps & { colorScheme: ColorScheme }) { {isLoading ? ( ) : ( - - -
- - - - + + + +
+ + + + + )} diff --git a/src/pages/api/config.ts b/src/pages/api/config.ts new file mode 100644 index 00000000..45ed9233 --- /dev/null +++ b/src/pages/api/config.ts @@ -0,0 +1,15 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +const handler = async (req: NextApiRequest, res: NextApiResponse) => { + let publicEnvironmentVariables: any = {}; + Object.entries(process.env).forEach(([key, value]) => { + if (key.startsWith("PUBLIC")) { + key = key.replace("PUBLIC_", ""); + publicEnvironmentVariables[key] = value; + } + }); + res.setHeader("cache-control", "max-age=100"); + res.status(200).json(publicEnvironmentVariables); +}; + +export default handler; diff --git a/src/utils/appwrite.util.ts b/src/utils/appwrite.util.ts index b940db47..75e6082a 100644 --- a/src/utils/appwrite.util.ts +++ b/src/utils/appwrite.util.ts @@ -3,7 +3,6 @@ import { Appwrite } from "appwrite"; // SDK for client side (browser) const aw = new Appwrite(); -aw.setEndpoint(process.env["NEXT_PUBLIC_APPWRITE_HOST"] as string) - .setProject("pingvin-share"); +aw.setProject("pingvin-share"); export default aw; diff --git a/src/utils/appwriteServer.util.ts b/src/utils/appwriteServer.util.ts index dfea00b8..f879d0d0 100644 --- a/src/utils/appwriteServer.util.ts +++ b/src/utils/appwriteServer.util.ts @@ -5,7 +5,7 @@ const client = new sdk.Client(); client .setEndpoint( - (process.env["NEXT_PUBLIC_APPWRITE_HOST"] as string).replace( + (process.env["PUBLIC_APPWRITE_HOST"] as string).replace( "localhost", process.env.NODE_ENV == "production" ? "host.docker.internal" diff --git a/src/utils/config.util.ts b/src/utils/config.util.ts new file mode 100644 index 00000000..b3c246df --- /dev/null +++ b/src/utils/config.util.ts @@ -0,0 +1,12 @@ +import axios from "axios"; +import { createContext, useContext } from "react"; + +export const ConfigContext = createContext({}); + +export const useConfig = () => useContext(ConfigContext); + +const getGonfig = async() => { + return (await axios.get("/api/config")).data; +}; + +export default { getGonfig };