Skip to content

Commit 152f77f

Browse files
authored
Merge pull request #158 from supabase-community/chore/assets-cdn
chore: static assets cdn
2 parents d63b3f5 + 96ac4ec commit 152f77f

File tree

4 files changed

+119
-2
lines changed

4 files changed

+119
-2
lines changed

apps/web/next.config.mjs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import webpack from 'webpack'
55

66
/** @type {import('next').NextConfig} */
77
const nextConfig = {
8+
assetPrefix: getAssetPrefix(),
89
reactStrictMode: false,
910
env: {
1011
NEXT_PUBLIC_PGLITE_VERSION: await getPackageVersion('@electric-sql/pglite'),
@@ -85,3 +86,20 @@ async function getPackageVersion(module) {
8586
const packageJson = await getPackageJson(module)
8687
return packageJson.version
8788
}
89+
90+
function getAssetPrefix() {
91+
// If not force enabled, but not production env, disable CDN
92+
if (process.env.FORCE_ASSET_CDN !== '1' && process.env.VERCEL_ENV !== 'production') {
93+
return undefined
94+
}
95+
96+
// Force disable CDN
97+
if (process.env.FORCE_ASSET_CDN === '-1') {
98+
return undefined
99+
}
100+
101+
// @ts-ignore
102+
return `https://frontend-assets.supabase.com/${
103+
process.env.SITE_NAME
104+
}/${process.env.VERCEL_GIT_COMMIT_SHA.substring(0, 12)}`
105+
}

apps/web/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"private": true,
55
"scripts": {
66
"dev": "npm run build:sw && next dev",
7-
"build": "npm run build:sw && next build",
7+
"build": "npm run build:sw && next build && ./../../scripts/upload-static-assets.sh",
88
"build:sw": "vite build",
99
"start": "next start",
1010
"lint": "next lint",

scripts/upload-static-assets.sh

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
#!/bin/bash
2+
3+
#######
4+
5+
# This script is used to upload static build assets (JS, CSS, ...) and public static files (public folder) to a CDN.
6+
# We're using Cloudflare R2 as CDN.
7+
# By using a CDN, we can serve static assets extremely fast while saving big time on egress costs.
8+
# An alternative is proxying via CF, but that comes with Orange-To-Orange issues (Cloudflare having issues with Cloudflare) and increased latency as there is a double TLS termination.
9+
# The script is only supposed to run on production deployments and is not run on any previews.
10+
11+
# By using a dynamic path including the env, app and commit hash, we can ensure that there are no conflicts.
12+
# Static assets from previous deployments stick around for a while to ensure there are no "downtimes".
13+
14+
# Advantages of the CDN approach we're using:
15+
16+
# Get rid of egress costs for static assets across our apps on Vercel
17+
# Disable CF proxying and get around these odd timeouts issues
18+
# Save ~20ms or so for asset requests, as there is no additional CF proxying and we avoid terminating SSL twice
19+
# Always hits the CDN, gonna be super quick
20+
# Does not run on local or preview environments, only on staging/prod deployments
21+
# There are no other disadvantages - you don't have to consider it when developing locally, previews still work, everything on Vercel works as we're used to
22+
23+
#######
24+
25+
# If asset CDN is specifically disabled (i.e. studio self-hosted), we skip
26+
if [[ "$FORCE_ASSET_CDN" == "-1" ]]; then
27+
echo "Skipping asset upload. Set FORCE_ASSET_CDN=1 or VERCEL_ENV=production to execute."
28+
exit 0
29+
fi
30+
31+
# Check for force env var or production environment
32+
if [[ "$FORCE_ASSET_CDN" != "1" ]] && [[ "$VERCEL_ENV" != "production" ]]; then
33+
echo "Skipping asset upload. Set FORCE_ASSET_CDN=1 or VERCEL_ENV=production to execute."
34+
exit 0
35+
fi
36+
37+
# Set the cdnBucket variable based on NEXT_PUBLIC_ENVIRONMENT
38+
if [[ "$NEXT_PUBLIC_ENVIRONMENT" == "staging" ]]; then
39+
BUCKET_NAME="frontend-assets-staging"
40+
else
41+
BUCKET_NAME="frontend-assets-prod"
42+
fi
43+
44+
STATIC_DIR=".next/static"
45+
PUBLIC_DIR="public"
46+
47+
# Colors for output
48+
GREEN='\033[0;32m'
49+
YELLOW='\033[1;33m'
50+
NC='\033[0m' # No Color
51+
52+
# Install AWS CLI if not present
53+
if ! command -v aws &> /dev/null; then
54+
echo -e "${YELLOW}Setting up AWS CLI...${NC}"
55+
curl -s "https://awscli.amazonaws.com/awscli-exe-linux-x86_64-2.22.35.zip" -o "awscliv2.zip"
56+
unzip -q awscliv2.zip
57+
export PATH=$PWD/aws/dist:$PATH
58+
rm awscliv2.zip
59+
fi
60+
61+
# Check if directory exists
62+
if [ ! -d "$STATIC_DIR" ]; then
63+
echo -e "${YELLOW}Directory $STATIC_DIR not found!${NC}"
64+
echo "Make sure you're running this script from your Next.js project root."
65+
exit 1
66+
fi
67+
68+
# Upload files with cache configuration and custom endpoint
69+
echo -e "${YELLOW}Uploading static files to R2...${NC}"
70+
aws s3 sync "$STATIC_DIR" "s3://$BUCKET_NAME/$SITE_NAME/${VERCEL_GIT_COMMIT_SHA:0:12}/_next/static" \
71+
--endpoint-url "$ASSET_CDN_S3_ENDPOINT" \
72+
--cache-control "public,max-age=604800,immutable" \
73+
--region auto \
74+
--only-show-errors
75+
76+
# Some public files may be referenced through CSS (relative path) and therefore they would be requested via the CDN url
77+
# To ensure we don't run into some nasty debugging issues, we upload the public files to the CDN as well
78+
echo -e "${YELLOW}Uploading public files to R2...${NC}"
79+
aws s3 sync "$PUBLIC_DIR" "s3://$BUCKET_NAME/$SITE_NAME/${VERCEL_GIT_COMMIT_SHA:0:12}" \
80+
--endpoint-url "$ASSET_CDN_S3_ENDPOINT" \
81+
--cache-control "public,max-age=604800,immutable" \
82+
--region auto \
83+
--only-show-errors
84+
85+
if [ $? -eq 0 ]; then
86+
echo -e "${GREEN}Upload completed successfully!${NC}"
87+
88+
# Clean up local static files so we prevent a double upload
89+
echo -e "${YELLOW}Cleaning up local static files...${NC}"
90+
rm -rf "$STATIC_DIR"/*
91+
echo -e "${GREEN}Local static files cleaned up${NC}"
92+
93+
# We still keep the public dir, as Next.js does not officially support serving the public files via CDN
94+
fi

turbo.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,12 @@
3939
"KV_*",
4040
"SUPABASE_*",
4141
"LOGFLARE_*",
42-
"REDIRECT_LEGACY_DOMAIN"
42+
"REDIRECT_LEGACY_DOMAIN",
43+
"AWS_ACCESS_KEY_ID",
44+
"AWS_SECRET_ACCESS_KEY",
45+
"FORCE_ASSET_CDN",
46+
"ASSET_CDN_S3_ENDPOINT",
47+
"SITE_NAME"
4348
],
4449
"outputs": [".next/**", "!.next/cache/**"],
4550
"cache": true

0 commit comments

Comments
 (0)