Skip to content

Commit 415783f

Browse files
authored
Merge pull request #2819 from venku122/pr1-docker-website-storybook
deploy: Docker build for website + Storybook
2 parents 2cf2243 + fddc687 commit 415783f

File tree

9 files changed

+237
-5
lines changed

9 files changed

+237
-5
lines changed

.dockerignore

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
.git
2+
.github
3+
.codesandbox
4+
5+
**/node_modules
6+
**/.cache
7+
**/.turbo
8+
**/.next
9+
**/dist
10+
**/cjs
11+
**/*.tsbuildinfo
12+
13+
website/public
14+
storybook/storybook-static
15+
api/dist
16+
17+
*.log
18+
*.swp
19+
*.swo
20+
*~
21+

ACCEPTANCE_TEST.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Acceptance Test Plan (Docker Compose)
2+
3+
This plan verifies a containerized Nivo website build with a co-located Storybook at `/storybook/`.
4+
5+
## Preconditions
6+
7+
- Docker is running.
8+
- You are in the repo root.
9+
10+
## A. Website + Storybook (No Render API)
11+
12+
Bring up the website-only stack:
13+
14+
```bash
15+
docker compose -f deploy/compose.website.yml up -d --build
16+
```
17+
18+
Smoke checks:
19+
20+
```bash
21+
curl -sS -I http://localhost:8080/ | tr -d '\r'
22+
curl -sS -I http://localhost:8080/storybook/ | tr -d '\r'
23+
curl -sS -I http://localhost:8080/storybook/sb-manager/runtime.js | tr -d '\r'
24+
```
25+
26+
Expect:
27+
28+
- `/` returns `200` and `Cache-Control: public, max-age=1800`
29+
- `/storybook/` returns `200`
30+
- Storybook hashed assets return `Cache-Control: public, max-age=31536000, immutable`
31+
32+
Bring it down:
33+
34+
```bash
35+
docker compose -f deploy/compose.website.yml down --remove-orphans
36+
```
37+
38+
## Optional: Render API
39+
40+
The website includes `/<chart>/api/` pages that POST chart props to a render API.
41+
42+
This repo historically used `https://nivo-api.herokuapp.com/nivo` for that, but if you want those pages to work without relying on an external service, the render API needs to be self-hosted and proxied under the same origin (e.g. at `/nivo/`).

DEPLOY_DOCKER.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Docker Deployment (Website + Storybook, Optional Render API)
2+
3+
This repo includes Dockerfiles and docker-compose examples to build and serve:
4+
5+
- the Nivo website (Gatsby static build)
6+
- Storybook at `/storybook/`
7+
8+
## Website + Storybook
9+
10+
```bash
11+
docker compose -f deploy/compose.website.yml up -d --build
12+
```
13+
14+
Open:
15+
16+
- Website: `http://localhost:8080/`
17+
- Storybook: `http://localhost:8080/storybook/`
18+
19+
## Notes
20+
21+
- Gatsby inlines `GATSBY_*` variables at build time.
22+
- `SITE_URL` is also a build-time value used by Gatsby.

Dockerfile.nivo-website

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# syntax=docker/dockerfile:1.7
2+
#
3+
# Builds the Gatsby site in ./website (monorepo workspace) and serves it via nginx.
4+
#
5+
# Build-time:
6+
# docker build -f Dockerfile.nivo-website --build-arg SITE_URL=http://localhost:8080 -t nivo-website:dev .
7+
#
8+
# Run:
9+
# docker run --rm -p 8080:80 nivo-website:dev
10+
#
11+
FROM node:22-bookworm-slim AS builder
12+
13+
WORKDIR /app
14+
15+
# Avoid downloading large E2E/browser binaries during image build.
16+
ENV CYPRESS_INSTALL_BINARY=0
17+
ENV PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1
18+
ENV PUPPETEER_SKIP_DOWNLOAD=1
19+
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1
20+
21+
# Use the repo's pinned pnpm version via corepack.
22+
ENV PNPM_HOME=/pnpm
23+
ENV PATH="$PNPM_HOME:$PATH"
24+
RUN corepack enable && corepack prepare pnpm@10.11.0 --activate
25+
26+
# Copy only what's needed to build the website.
27+
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml .npmrc ./
28+
COPY tsconfig*.json babel.config.js lerna.json eslint.config.mjs ./
29+
COPY Makefile ./Makefile
30+
COPY conf ./conf
31+
COPY scripts ./scripts
32+
COPY packages ./packages
33+
COPY storybook ./storybook
34+
COPY website ./website
35+
36+
RUN pnpm install --frozen-lockfile
37+
38+
# The website depends on workspace packages, so build them first.
39+
RUN pnpm run pkgs:types:check && pnpm run pkgs:build
40+
41+
# Gatsby uses SITE_URL during build (see website/gatsby-config.ts).
42+
ARG SITE_URL=http://localhost:8080
43+
ENV SITE_URL="$SITE_URL"
44+
45+
# Client-side API base URL for the "HTTP API" demo pages (Gatsby inlines GATSBY_* at build time).
46+
# Keep WITHOUT a trailing slash.
47+
# Default to the historical render API (override to use your own).
48+
ARG GATSBY_NIVO_API_URL=https://nivo-api.herokuapp.com/nivo
49+
ENV GATSBY_NIVO_API_URL="$GATSBY_NIVO_API_URL"
50+
51+
# Client-side Storybook base URL (also inlined by Gatsby).
52+
# Keep WITHOUT a trailing slash unless you're using a path-only URL like /storybook/.
53+
ARG GATSBY_STORYBOOK_URL=/storybook/
54+
ENV GATSBY_STORYBOOK_URL="$GATSBY_STORYBOOK_URL"
55+
56+
RUN pnpm -C website build
57+
RUN pnpm --filter storybook build
58+
59+
60+
FROM nginx:1.27-alpine AS runtime
61+
62+
COPY --from=builder /app/website/public /usr/share/nginx/html
63+
COPY --from=builder /app/storybook/storybook-static /usr/share/nginx/html/storybook
64+
65+
# Default to the website-only nginx config; use NGINX_CONF to include an API proxy.
66+
ARG NGINX_CONF=deploy/nginx.website.conf
67+
COPY ${NGINX_CONF} /etc/nginx/conf.d/default.conf
68+
69+
EXPOSE 80

deploy/compose.website.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
services:
2+
website:
3+
build:
4+
context: ..
5+
dockerfile: Dockerfile.nivo-website
6+
args:
7+
# Serve website+storybook only (no /nivo proxy).
8+
NGINX_CONF: deploy/nginx.website.conf
9+
restart: unless-stopped
10+
ports:
11+
- "8080:80"

deploy/nginx.website.conf

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
server {
2+
listen 80;
3+
server_name _;
4+
5+
root /usr/share/nginx/html;
6+
index index.html;
7+
8+
# Compression helps a lot for Gatsby's JS/CSS bundles.
9+
gzip on;
10+
gzip_vary on;
11+
gzip_comp_level 5;
12+
gzip_min_length 1024;
13+
gzip_types
14+
text/plain
15+
text/css
16+
application/javascript
17+
application/json
18+
image/svg+xml;
19+
20+
# These should update quickly when you redeploy.
21+
location = /sw.js {
22+
add_header Cache-Control "no-cache" always;
23+
try_files $uri =404;
24+
}
25+
26+
location = /manifest.webmanifest {
27+
add_header Cache-Control "no-cache" always;
28+
try_files $uri =404;
29+
}
30+
31+
# Self-hosted Storybook (built from ./storybook) served at /storybook/.
32+
# Storybook assets will be matched by the global hashed-asset cache rule below.
33+
location /storybook/ {
34+
add_header Cache-Control "public, max-age=1800" always;
35+
try_files $uri $uri/ /storybook/index.html =404;
36+
}
37+
38+
# Serve pre-built Gatsby pages as-is.
39+
location / {
40+
# Cache HTML for 30 minutes to reduce origin load.
41+
# Tradeoff: users may see stale HTML briefly after a deploy.
42+
add_header Cache-Control "public, max-age=1800" always;
43+
try_files $uri $uri/ =404;
44+
}
45+
46+
# Root-level and /static assets are content-hashed in their filenames: cache aggressively.
47+
location ~* \.(?:css|js|png|jpg|jpeg|gif|svg|ico|webp|avif|woff2?|ttf|eot)$ {
48+
add_header Cache-Control "public, max-age=31536000, immutable" always;
49+
try_files $uri =404;
50+
}
51+
52+
# Gatsby page-data isn't content-hashed; cache briefly to reduce chatter, but allow quick updates.
53+
location ^~ /page-data/ {
54+
add_header Cache-Control "public, max-age=300" always;
55+
try_files $uri =404;
56+
}
57+
58+
# Basic hardening headers (safe for static content).
59+
add_header X-Content-Type-Options "nosniff" always;
60+
add_header X-Frame-Options "SAMEORIGIN" always;
61+
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
62+
}
63+

website/src/components/nav/FullNav.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
import media from '../../theming/mediaQueries'
1212
import * as nav from '../../data/nav'
1313
import { FullNavComponentLink } from './FullNavComponentLink'
14+
import config from '../../data/config'
1415

1516
export const FullNav = memo(() => {
1617
return (
@@ -37,7 +38,7 @@ export const FullNav = memo(() => {
3738
<InternalLink to="/references/">References</InternalLink>
3839
<InternalLink to="/faq/">FAQ</InternalLink>
3940
<ExternalLink
40-
href="https://nivo.rocks/storybook/"
41+
href={config.storybookUrl}
4142
target="_blank"
4243
rel="noopener noreferrer"
4344
>

website/src/components/nav/HeaderNav.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import media from '../../theming/mediaQueries'
77
import ThemeSelector from '../ThemeSelector'
88
import * as nav from '../../data/nav'
99
import { NavToggleButton } from './NavToggleButton'
10+
import config from '../../data/config'
1011

1112
interface HeaderNavProps {
1213
isNavOpen: boolean
@@ -35,7 +36,7 @@ export const HeaderNav = ({ isNavOpen, toggleNav }: HeaderNavProps) => {
3536
</HeaderSub>
3637
</HeaderItem>
3738
<HeaderExternalLink
38-
href="https://nivo.rocks/storybook/"
39+
href={config.storybookUrl}
3940
target="_blank"
4041
rel="noopener noreferrer"
4142
>

website/src/data/config.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ export default {
33
// nivoApiUrl: 'http://localhost:3030/nivo',
44
// storybookUrl: 'http://localhost:6006/',
55

6-
// production
7-
nivoApiUrl: 'https://nivo-api.herokuapp.com/nivo',
8-
storybookUrl: 'https://nivo.rocks/storybook/',
6+
// production (override at build time via Gatsby env vars)
7+
// Note: keep these base URLs WITHOUT a trailing slash.
8+
nivoApiUrl: process.env.GATSBY_NIVO_API_URL || 'https://nivo-api.herokuapp.com/nivo',
9+
// Default to the self-hosted storybook served from this same origin.
10+
storybookUrl: process.env.GATSBY_STORYBOOK_URL || '/storybook/',
911
}

0 commit comments

Comments
 (0)