Skip to content

Commit 5dc831d

Browse files
committed
chore: push static assets to s3 to support old deployments
During new deployments old users might request old chunks. This commit adds a script to upload static assets to S3 to ensure persistent availability of chunks across deployments.
1 parent da1ab61 commit 5dc831d

File tree

5 files changed

+180
-9
lines changed

5 files changed

+180
-9
lines changed

.github/workflows/build-and-push.yml

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -194,15 +194,20 @@ jobs:
194194
cache-from: type=registry,ref=${{ matrix.private && format('{0}/{1}', env.ECR_REGISTRY, matrix.repo_name) || format('{0}/{1}/{2}', matrix.registry, matrix.owner, matrix.repo_name) }}:latest
195195
cache-to: type=inline
196196
secrets: ${{ matrix.private && format('SENTRY_AUTH_TOKEN={0}', secrets.SENTRY_AUTH_TOKEN) || '' }}
197-
build-args: |
198-
NEXT_PUBLIC_DOCS_URL=${{ matrix.private && vars.NEXT_PUBLIC_DOCS_URL || '' }}
199-
NEXT_PUBLIC_LATITUDE_CLOUD_PAYMENT_URL=${{ matrix.private && vars.NEXT_PUBLIC_LATITUDE_CLOUD_PAYMENT_URL || '' }}
200-
NEXT_PUBLIC_POSTHOG_HOST=${{ matrix.private && secrets.NEXT_PUBLIC_POSTHOG_HOST || '' }}
201-
NEXT_PUBLIC_POSTHOG_KEY=${{ matrix.private && secrets.NEXT_PUBLIC_POSTHOG_KEY || '' }}
202-
NEXT_PUBLIC_SENTRY_WEB_DSN=${{ matrix.private && vars.SENTRY_WEB_DSN || '' }}
203-
SENTRY_ORG=${{ matrix.private && secrets.SENTRY_ORG || '' }}
204-
SENTRY_PROJECT=${{ matrix.private && secrets.SENTRY_PROJECT || '' }}
205-
NEXT_SERVER_ACTIONS_ENCRYPTION_KEY=${{ secrets.NEXT_SERVER_ACTIONS_ENCRYPTION_KEY }}
197+
build-args: |
198+
NEXT_PUBLIC_DOCS_URL=${{ matrix.private && vars.NEXT_PUBLIC_DOCS_URL || '' }}
199+
NEXT_PUBLIC_LATITUDE_CLOUD_PAYMENT_URL=${{ matrix.private && vars.NEXT_PUBLIC_LATITUDE_CLOUD_PAYMENT_URL || '' }}
200+
NEXT_PUBLIC_POSTHOG_HOST=${{ matrix.private && secrets.NEXT_PUBLIC_POSTHOG_HOST || '' }}
201+
NEXT_PUBLIC_POSTHOG_KEY=${{ matrix.private && secrets.NEXT_PUBLIC_POSTHOG_KEY || '' }}
202+
NEXT_PUBLIC_SENTRY_WEB_DSN=${{ matrix.private && vars.SENTRY_WEB_DSN || '' }}
203+
SENTRY_ORG=${{ matrix.private && secrets.SENTRY_ORG || '' }}
204+
SENTRY_PROJECT=${{ matrix.private && secrets.SENTRY_PROJECT || '' }}
205+
NEXT_SERVER_ACTIONS_ENCRYPTION_KEY=${{ secrets.NEXT_SERVER_ACTIONS_ENCRYPTION_KEY }}
206+
AWS_ACCESS_KEY_ID=${{ matrix.private && secrets.AWS_ACCESS_KEY_ID || '' }}
207+
AWS_SECRET_ACCESS_KEY=${{ matrix.private && secrets.AWS_SECRET_ACCESS_KEY || '' }}
208+
AWS_REGION=${{ matrix.private && vars.AWS_REGION || '' }}
209+
S3_BUCKET=${{ matrix.private && vars.STATIC_ASSETS_S3_BUCKET || '' }}
210+
BUILD_ID=${{ github.sha }}
206211
207212
run-migrations:
208213
needs: [build-and-push]

apps/web/docker/Dockerfile

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,27 @@ RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
108108
NODE_OPTIONS="--max-old-space-size=8192" \
109109
pnpm turbo build --filter="${PROJECT}..."
110110

111+
# Upload static assets to S3 for persistent availability
112+
ARG AWS_ACCESS_KEY_ID
113+
ARG AWS_SECRET_ACCESS_KEY
114+
ARG AWS_REGION
115+
ARG S3_BUCKET
116+
ARG BUILD_ID
117+
ENV AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID
118+
ENV AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY
119+
ENV AWS_REGION=$AWS_REGION
120+
ENV S3_BUCKET=$S3_BUCKET
121+
ENV BUILD_ID=$BUILD_ID
122+
123+
RUN if [ -n "$S3_BUCKET" ] && [ -n "$BUILD_ID" ]; then \
124+
echo "Uploading static assets to S3..."; \
125+
chmod +x ./apps/web/scripts/upload-static-assets.sh && \
126+
cd apps/web && \
127+
./scripts/upload-static-assets.sh; \
128+
else \
129+
echo "Skipping S3 upload - S3_BUCKET or BUILD_ID not provided"; \
130+
fi
131+
111132
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm prune --prod --no-optional
112133

113134
# PRODUCTION

apps/web/next.config.mjs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ const nextConfig = {
3838
images: {
3939
remotePatterns: [new URL('https://assets.pipedream.net/**')],
4040
},
41+
// Serve static assets from S3 for persistent chunk availability
42+
assetPrefix: process.env.NEXT_PUBLIC_STATIC_ASSETS_URL,
4143
}
4244

4345
let config
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#!/bin/bash
2+
3+
# Script to set up S3 bucket for static assets with proper configuration
4+
# Run this once to configure the bucket for static asset hosting
5+
6+
set -e
7+
8+
# Environment variables required:
9+
# S3_BUCKET - S3 bucket name for static assets
10+
# AWS_REGION - AWS region (optional, defaults to us-east-1)
11+
12+
BUCKET=${S3_BUCKET:-"latitude-static-assets"}
13+
REGION=${AWS_REGION:-"us-east-1"}
14+
15+
echo "Setting up S3 bucket: $BUCKET in region: $REGION"
16+
17+
# Create bucket if it doesn't exist
18+
if ! aws s3api head-bucket --bucket "$BUCKET" 2>/dev/null; then
19+
echo "Creating bucket $BUCKET..."
20+
if [ "$REGION" = "us-east-1" ]; then
21+
aws s3api create-bucket --bucket "$BUCKET"
22+
else
23+
aws s3api create-bucket --bucket "$BUCKET" --region "$REGION" --create-bucket-configuration LocationConstraint="$REGION"
24+
fi
25+
else
26+
echo "Bucket $BUCKET already exists"
27+
fi
28+
29+
# Enable versioning (optional but recommended for backup)
30+
echo "Enabling versioning..."
31+
aws s3api put-bucket-versioning \
32+
--bucket "$BUCKET" \
33+
--versioning-configuration Status=Enabled
34+
35+
# Set up CORS configuration for web access
36+
echo "Configuring CORS..."
37+
cat > /tmp/cors-config.json << EOF
38+
{
39+
"CORSRules": [
40+
{
41+
"AllowedHeaders": ["*"],
42+
"AllowedMethods": ["GET"],
43+
"AllowedOrigins": ["*"],
44+
"MaxAgeSeconds": 3000
45+
}
46+
]
47+
}
48+
EOF
49+
50+
aws s3api put-bucket-cors \
51+
--bucket "$BUCKET" \
52+
--cors-configuration file:///tmp/cors-config.json
53+
54+
# Set up bucket policy for public read access to static assets
55+
echo "Configuring bucket policy..."
56+
cat > /tmp/bucket-policy.json << EOF
57+
{
58+
"Version": "2012-10-17",
59+
"Statement": [
60+
{
61+
"Sid": "PublicReadGetObject",
62+
"Effect": "Allow",
63+
"Principal": "*",
64+
"Action": "s3:GetObject",
65+
"Resource": "arn:aws:s3:::$BUCKET/static-assets/*"
66+
}
67+
]
68+
}
69+
EOF
70+
71+
aws s3api put-bucket-policy \
72+
--bucket "$BUCKET" \
73+
--policy file:///tmp/bucket-policy.json
74+
75+
# Enable static website hosting (optional, for direct access)
76+
echo "Configuring static website hosting..."
77+
aws s3 website "s3://$BUCKET" \
78+
--index-document index.html \
79+
--error-document error.html
80+
81+
echo "S3 bucket setup complete!"
82+
echo "Bucket: $BUCKET"
83+
echo "Website URL: http://$BUCKET.s3-website-$REGION.amazonaws.com"
84+
echo "Static assets will be served from: https://$BUCKET.s3.$REGION.amazonaws.com/static-assets/"
85+
86+
# Clean up
87+
rm -f /tmp/cors-config.json /tmp/bucket-policy.json
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#!/bin/bash
2+
3+
# Script to upload Next.js static assets to S3
4+
# This ensures persistent availability of chunks across deployments
5+
6+
set -e
7+
8+
# Environment variables required:
9+
# AWS_ACCESS_KEY_ID - AWS access key
10+
# AWS_SECRET_ACCESS_KEY - AWS secret key
11+
# AWS_REGION - AWS region
12+
# S3_BUCKET - S3 bucket name for static assets
13+
# BUILD_ID - Unique build identifier (e.g., git commit SHA)
14+
15+
if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ] || [ -z "$AWS_REGION" ] || [ -z "$S3_BUCKET" ] || [ -z "$BUILD_ID" ]; then
16+
echo "Error: Missing required environment variables"
17+
echo "Required: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION, S3_BUCKET, BUILD_ID"
18+
exit 1
19+
fi
20+
21+
STATIC_DIR="./.next/static"
22+
S3_PREFIX="static-assets/$BUILD_ID"
23+
24+
echo "Uploading static assets to S3..."
25+
echo "Bucket: $S3_BUCKET"
26+
echo "Prefix: $S3_PREFIX"
27+
echo "Source: $STATIC_DIR"
28+
29+
if [ ! -d "$STATIC_DIR" ]; then
30+
echo "Error: Static directory $STATIC_DIR does not exist"
31+
exit 1
32+
fi
33+
34+
# Upload static assets with appropriate cache control headers
35+
# JS/CSS chunks: cache for 1 year (immutable)
36+
# Other assets: cache for 1 hour
37+
aws s3 cp "$STATIC_DIR" "s3://$S3_BUCKET/$S3_PREFIX/" \
38+
--recursive \
39+
--cache-control "public, max-age=31536000, immutable" \
40+
--exclude "*" \
41+
--include "*.js" \
42+
--include "*.css"
43+
44+
# Upload other static assets (images, fonts, etc.) with shorter cache
45+
aws s3 cp "$STATIC_DIR" "s3://$S3_BUCKET/$S3_PREFIX/" \
46+
--recursive \
47+
--cache-control "public, max-age=3600" \
48+
--exclude "*.js" \
49+
--exclude "*.css"
50+
51+
echo "Static assets uploaded successfully to s3://$S3_BUCKET/$S3_PREFIX/"
52+
53+
# Output the S3 URL for use in Next.js configuration
54+
S3_URL="https://$S3_BUCKET.s3.$AWS_REGION.amazonaws.com/$S3_PREFIX"
55+
echo "Static assets URL: $S3_URL"
56+
echo "NEXT_PUBLIC_STATIC_ASSETS_URL=$S3_URL" >> $GITHUB_ENV

0 commit comments

Comments
 (0)