diff --git a/.env.sample b/.env.sample index c87806fb..40930b73 100644 --- a/.env.sample +++ b/.env.sample @@ -1 +1,3 @@ -VITE_BACKEND_URL=http://backend.com \ No newline at end of file +VITE_BACKEND_URL=http://backend.com +# Uncomment to build for a sub-path (defaults to /) +# VITE_BASE_PATH=/drawdb diff --git a/Dockerfile b/Dockerfile index ed35b52f..4daa51a6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,11 +5,14 @@ COPY package*.json ./ RUN npm ci COPY . . ENV NODE_OPTIONS="--max-old-space-size=4096" +ENV VITE_BASE_PATH=__BASE_PATH__ RUN npm run build # Stage 2: Setup the Nginx Server to serve the app FROM docker.io/library/nginx:stable-alpine3.17 AS production COPY --from=build /app/dist /usr/share/nginx/html -RUN echo 'server { listen 80; server_name _; root /usr/share/nginx/html; location / { try_files $uri /index.html; } }' > /etc/nginx/conf.d/default.conf +COPY docker-entrypoint.sh /docker-entrypoint.sh +RUN chmod +x /docker-entrypoint.sh && rm /etc/nginx/conf.d/default.conf EXPOSE 80 +ENTRYPOINT ["/docker-entrypoint.sh"] CMD ["nginx", "-g", "daemon off;"] diff --git a/README.md b/README.md index 2b6976c1..1177f801 100644 --- a/README.md +++ b/README.md @@ -64,4 +64,15 @@ docker build -t drawdb . docker run -p 3000:80 drawdb ``` +To serve the app from a sub-path, set the deployment context at runtime. Replace `/drawdb` with your desired base path. + +```bash +docker run -p 3000:80 -e DRAWDB_BASE_PATH=/drawdb drawdb +``` + +### Deployment Context + +- `VITE_BASE_PATH` (build-time) controls the base URL when building outside of Docker. Set it before running `npm run build`, for example `VITE_BASE_PATH=/drawdb npm run build`. The default `/` serves the app at the domain root. The Docker image sets a placeholder during build so you can usually leave this unset. +- `DRAWDB_BASE_PATH` (runtime, Docker only) updates the pre-built assets and Nginx routing when the container starts. It must match the path used at build time (default `/`). Provide a relative path such as `/drawdb`. + If you want to enable sharing, set up the [server](https://github.com/drawdb-io/drawdb-server) and environment variables according to `.env.sample`. This is optional unless you need to share files.. diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100644 index 00000000..8ca60d93 --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,82 @@ +#!/bin/sh +set -eu + +CONTENT_DIR="/usr/share/nginx/html" +# Allow overriding the served base path at runtime (default /) +BASE_PATH="${DRAWDB_BASE_PATH:-/}" + +if [ -z "$BASE_PATH" ]; then + BASE_PATH="/" +fi + +# Reject absolute URLs; only relative paths are supported +case "$BASE_PATH" in + http://*|https://*) + echo "DRAWDB_BASE_PATH must be a relative path (e.g. /drawdb)" >&2 + exit 1 + ;; +esac + +# Ensure the path has a single leading slash and no trailing slash +if [ "$BASE_PATH" != "/" ]; then + BASE_PATH="/${BASE_PATH#/}" + BASE_PATH="${BASE_PATH%/}" +fi + +# Derive helper variants used by the templated replacements below +if [ "$BASE_PATH" = "/" ]; then + BASE_PATH_WITH_SLASH="/" + BASE_PATH_NO_LEAD="" + BASE_PATH_NO_LEAD_WITH_SLASH="" +else + BASE_PATH_WITH_SLASH="$BASE_PATH/" + BASE_PATH_NO_LEAD="${BASE_PATH#/}" + BASE_PATH_NO_LEAD_WITH_SLASH="${BASE_PATH_NO_LEAD}/" +fi + +# Replace the placeholder base path in built assets, if present +if grep -R "__BASE_PATH__" "$CONTENT_DIR" >/dev/null 2>&1; then + find "$CONTENT_DIR" -type f \( -name '*.js' -o -name '*.css' -o -name '*.html' -o -name '*.json' -o -name '*.txt' \) -print0 | + while IFS= read -r -d '' file; do + sed -i \ + -e "s|/__BASE_PATH__/|${BASE_PATH_WITH_SLASH}|g" \ + -e "s|/__BASE_PATH__|${BASE_PATH}|g" \ + -e "s|__BASE_PATH__/|${BASE_PATH_NO_LEAD_WITH_SLASH}|g" \ + -e "s|__BASE_PATH__|${BASE_PATH_NO_LEAD}|g" \ + "$file" + done +fi + +# Generate Nginx configuration matching the selected base path +if [ "$BASE_PATH" = "/" ]; then + cat >/etc/nginx/conf.d/default.conf <<'EOF' +server { + listen 80; + server_name _; + root /usr/share/nginx/html; + + location / { + try_files $uri $uri/ /index.html; + } +} +EOF +else + cat >/etc/nginx/conf.d/default.conf < - + } /> diff --git a/vite.config.js b/vite.config.js index 5a33944a..de6b1808 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,7 +1,19 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' +/* eslint-env node */ +import { defineConfig, loadEnv } from "vite"; +import react from "@vitejs/plugin-react"; -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [react()], -}) +export default defineConfig(({ mode }) => { + const env = loadEnv(mode, process.cwd(), ""); + let base = env.VITE_BASE_PATH || "/"; + if (!base.startsWith("/") && !/^https?:\/\//.test(base)) { + base = `/${base}`; + } + if (!base.endsWith("/")) { + base += "/"; + } + + return { + base, + plugins: [react()], + }; +});