Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .env.sample
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
VITE_BACKEND_URL=http://backend.com
VITE_BACKEND_URL=http://backend.com
# Uncomment to build for a sub-path (defaults to /)
# VITE_BASE_PATH=/drawdb
5 changes: 4 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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;"]
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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..
82 changes: 82 additions & 0 deletions docker-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -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 <<EOF
server {
listen 80;
server_name _;
root /usr/share/nginx/html;

location = $BASE_PATH {
return 301 $BASE_PATH/;
}

location $BASE_PATH/ {
rewrite ^$BASE_PATH/(.*)$ /\$1 break;
try_files \$uri \$uri/ /index.html;
}
}
EOF
fi

exec "$@"
4 changes: 3 additions & 1 deletion src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ import SettingsContextProvider from "./context/SettingsContext";
import NotFound from "./pages/NotFound";

export default function App() {
const basename = import.meta.env.BASE_URL.replace(/\/$/, "");

return (
<SettingsContextProvider>
<BrowserRouter>
<BrowserRouter basename={basename || undefined}>
<RestoreScroll />
<Routes>
<Route path="/" element={<LandingPage />} />
Expand Down
24 changes: 18 additions & 6 deletions vite.config.js
Original file line number Diff line number Diff line change
@@ -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()],
};
});