chore: Improve startup speed of containers
This commit is contained in:
+14
@@ -123,6 +123,10 @@ COPY --from=deps /app/yarn.lock ./
|
|||||||
# Copy root config files needed for Turbo
|
# Copy root config files needed for Turbo
|
||||||
COPY turbo.json ./
|
COPY turbo.json ./
|
||||||
|
|
||||||
|
# Copy manifest generation script
|
||||||
|
COPY docker/generate-url-manifest.sh /usr/local/bin/
|
||||||
|
RUN chmod +x /usr/local/bin/generate-url-manifest.sh
|
||||||
|
|
||||||
# Step 1: Copy and build shared packages (these change less frequently)
|
# Step 1: Copy and build shared packages (these change less frequently)
|
||||||
# Shared packages are dependencies for apps, so build them first
|
# Shared packages are dependencies for apps, so build them first
|
||||||
COPY packages ./packages
|
COPY packages ./packages
|
||||||
@@ -173,6 +177,8 @@ RUN --mount=type=cache,target=/app/.turbo,sharing=locked \
|
|||||||
yarn turbo build --filter=wiki
|
yarn turbo build --filter=wiki
|
||||||
# Generate sitemap for wiki
|
# Generate sitemap for wiki
|
||||||
RUN NEXT_PUBLIC_WIKI_URI=${WIKI_URI} yarn workspace wiki sitemap
|
RUN NEXT_PUBLIC_WIKI_URI=${WIKI_URI} yarn workspace wiki sitemap
|
||||||
|
# Generate URL replacement manifest for wiki (build-time optimization)
|
||||||
|
RUN generate-url-manifest.sh wiki /app/apps/wiki
|
||||||
|
|
||||||
# Step 4: Copy and build Web dashboard
|
# Step 4: Copy and build Web dashboard
|
||||||
COPY apps/web ./apps/web
|
COPY apps/web ./apps/web
|
||||||
@@ -188,6 +194,8 @@ RUN --mount=type=cache,target=/app/.turbo,sharing=locked \
|
|||||||
yarn turbo build --filter=web
|
yarn turbo build --filter=web
|
||||||
# Generate sitemap for web
|
# Generate sitemap for web
|
||||||
RUN NEXT_PUBLIC_DASHBOARD_URI=${DASHBOARD_URI} yarn workspace web sitemap
|
RUN NEXT_PUBLIC_DASHBOARD_URI=${DASHBOARD_URI} yarn workspace web sitemap
|
||||||
|
# Generate URL replacement manifest for web (build-time optimization)
|
||||||
|
RUN generate-url-manifest.sh web /app/apps/web
|
||||||
|
|
||||||
# Step 5: Copy and build Landing page
|
# Step 5: Copy and build Landing page
|
||||||
COPY apps/landing ./apps/landing
|
COPY apps/landing ./apps/landing
|
||||||
@@ -203,6 +211,8 @@ RUN --mount=type=cache,target=/app/.turbo,sharing=locked \
|
|||||||
yarn turbo build --filter=landing
|
yarn turbo build --filter=landing
|
||||||
# Generate sitemap for landing
|
# Generate sitemap for landing
|
||||||
RUN NEXT_PUBLIC_LANDING_URI=${LANDING_URI} yarn workspace landing sitemap
|
RUN NEXT_PUBLIC_LANDING_URI=${LANDING_URI} yarn workspace landing sitemap
|
||||||
|
# Generate URL replacement manifest for landing (build-time optimization)
|
||||||
|
RUN generate-url-manifest.sh landing /app/apps/landing
|
||||||
|
|
||||||
# Copy any remaining root files (if needed)
|
# Copy any remaining root files (if needed)
|
||||||
COPY . .
|
COPY . .
|
||||||
@@ -317,6 +327,10 @@ COPY --from=builder --chown=plunk:nodejs /app/apps/wiki/openapi.local.json ./app
|
|||||||
COPY --chown=plunk:nodejs docker/nginx/ /app/docker/nginx/
|
COPY --chown=plunk:nodejs docker/nginx/ /app/docker/nginx/
|
||||||
RUN chmod +x /app/docker/nginx/setup-nginx.sh
|
RUN chmod +x /app/docker/nginx/setup-nginx.sh
|
||||||
|
|
||||||
|
# Copy optimized URL replacement script
|
||||||
|
COPY --chown=plunk:nodejs docker/replace-urls-optimized.sh /app/docker/
|
||||||
|
RUN chmod +x /app/docker/replace-urls-optimized.sh
|
||||||
|
|
||||||
# Copy entrypoint script
|
# Copy entrypoint script
|
||||||
COPY --chown=plunk:nodejs docker-entrypoint-nginx.sh /usr/local/bin/
|
COPY --chown=plunk:nodejs docker-entrypoint-nginx.sh /usr/local/bin/
|
||||||
RUN chmod +x /usr/local/bin/docker-entrypoint-nginx.sh
|
RUN chmod +x /usr/local/bin/docker-entrypoint-nginx.sh
|
||||||
|
|||||||
@@ -16,8 +16,9 @@ fi
|
|||||||
|
|
||||||
# Run database migrations
|
# Run database migrations
|
||||||
echo "🗄️ Running database migrations..."
|
echo "🗄️ Running database migrations..."
|
||||||
cd /app
|
# Call Prisma binary directly for fastest startup (avoids Yarn workspace resolution and npx overhead)
|
||||||
if ! yarn workspace @plunk/db migrate:prod; then
|
# The Prisma client and schema are already available from the build
|
||||||
|
if ! /app/node_modules/.bin/prisma migrate deploy --schema=/app/packages/db/prisma/schema.prisma; then
|
||||||
echo ""
|
echo ""
|
||||||
echo "❌ ERROR: Database migration failed!"
|
echo "❌ ERROR: Database migration failed!"
|
||||||
echo " The container cannot start with failed migrations."
|
echo " The container cannot start with failed migrations."
|
||||||
@@ -71,104 +72,11 @@ echo " LANDING_DOMAIN=www.example.com"
|
|||||||
echo " WIKI_DOMAIN=docs.example.com"
|
echo " WIKI_DOMAIN=docs.example.com"
|
||||||
echo " USE_HTTPS=true"
|
echo " USE_HTTPS=true"
|
||||||
|
|
||||||
# Replace URLs in built files with runtime configuration
|
# Source the optimized URL replacement script
|
||||||
# This approach is simpler and more reliable than window.__ENV__
|
. /app/docker/replace-urls-optimized.sh
|
||||||
replace_urls_in_app() {
|
|
||||||
local app=$1
|
|
||||||
local app_dir=$2
|
|
||||||
|
|
||||||
echo "📝 Replacing URLs in $app build files..."
|
# Replace URLs in all Next.js apps using optimized function
|
||||||
|
# This uses pre-generated manifests from build time instead of scanning all files
|
||||||
# Define placeholder URLs (built into the app at compile time)
|
|
||||||
local PLACEHOLDER_API="https://api.useplunk.com"
|
|
||||||
local PLACEHOLDER_DASHBOARD="https://app.useplunk.com"
|
|
||||||
local PLACEHOLDER_LANDING="https://www.useplunk.com"
|
|
||||||
local PLACEHOLDER_WIKI="https://docs.useplunk.com"
|
|
||||||
|
|
||||||
# Find and replace URLs in all built files
|
|
||||||
# Process .next directory (contains all built output: static/, server/, standalone bundles)
|
|
||||||
# Include .js, .json, .html files to catch all possible occurrences
|
|
||||||
echo " 🔍 Scanning for files with placeholder URLs..."
|
|
||||||
|
|
||||||
# Create a temporary file list of files that need processing
|
|
||||||
local temp_file_list="/tmp/replace_urls_${app}.txt"
|
|
||||||
|
|
||||||
# Search in .next directory for all file types that might contain URLs
|
|
||||||
# Include: .js (bundles), .json (manifests), .html (static pages), .rsc (React Server Components)
|
|
||||||
find "$app_dir/.next" -type f \( -name "*.js" -o -name "*.json" -o -name "*.html" -o -name "*.rsc" \) \
|
|
||||||
-exec grep -l -E "$PLACEHOLDER_API|$PLACEHOLDER_DASHBOARD|$PLACEHOLDER_LANDING|$PLACEHOLDER_WIKI" {} \; \
|
|
||||||
2>/dev/null > "$temp_file_list" || true
|
|
||||||
|
|
||||||
# Count and process files
|
|
||||||
local file_count=$(wc -l < "$temp_file_list" | tr -d ' ')
|
|
||||||
echo " 📊 Found $file_count files containing placeholder URLs"
|
|
||||||
|
|
||||||
if [ "$file_count" -gt 0 ]; then
|
|
||||||
while IFS= read -r file; do
|
|
||||||
# Show relative path for better readability
|
|
||||||
local rel_path="${file#$app_dir/}"
|
|
||||||
echo " 🔄 $rel_path"
|
|
||||||
|
|
||||||
# Replace all URLs - compatible with both GNU and BSD sed
|
|
||||||
# Create temp file, replace, then move
|
|
||||||
sed -e "s|$PLACEHOLDER_API|$API_URI|g" \
|
|
||||||
-e "s|$PLACEHOLDER_DASHBOARD|$DASHBOARD_URI|g" \
|
|
||||||
-e "s|$PLACEHOLDER_LANDING|$LANDING_URI|g" \
|
|
||||||
-e "s|$PLACEHOLDER_WIKI|$WIKI_URI|g" \
|
|
||||||
"$file" > "${file}.tmp" && mv "${file}.tmp" "$file"
|
|
||||||
done < "$temp_file_list"
|
|
||||||
|
|
||||||
echo " ✅ Successfully replaced URLs in $file_count files"
|
|
||||||
else
|
|
||||||
echo " ⚠️ No files found with placeholder URLs"
|
|
||||||
fi
|
|
||||||
|
|
||||||
rm -f "$temp_file_list"
|
|
||||||
|
|
||||||
# Replace URLs in sitemap.xml and robots.txt (generated by next-sitemap)
|
|
||||||
echo " 🗺️ Processing sitemap and robots.txt..."
|
|
||||||
|
|
||||||
# Find all sitemap files (sitemap.xml, sitemap-0.xml, etc.)
|
|
||||||
find "$app_dir/public" -type f \( -name "sitemap*.xml" -o -name "robots.txt" \) 2>/dev/null | while IFS= read -r sitemap_file; do
|
|
||||||
if [ -f "$sitemap_file" ]; then
|
|
||||||
local rel_path="${sitemap_file#$app_dir/}"
|
|
||||||
echo " 🔄 $rel_path"
|
|
||||||
sed -e "s|$PLACEHOLDER_API|$API_URI|g" \
|
|
||||||
-e "s|$PLACEHOLDER_DASHBOARD|$DASHBOARD_URI|g" \
|
|
||||||
-e "s|$PLACEHOLDER_LANDING|$LANDING_URI|g" \
|
|
||||||
-e "s|$PLACEHOLDER_WIKI|$WIKI_URI|g" \
|
|
||||||
"$sitemap_file" > "${sitemap_file}.tmp" && mv "${sitemap_file}.tmp" "$sitemap_file"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Special handling for wiki: also replace URLs in openapi.local.json
|
|
||||||
if [ "$app" = "wiki" ]; then
|
|
||||||
local openapi_file="$app_dir/openapi.local.json"
|
|
||||||
if [ -f "$openapi_file" ]; then
|
|
||||||
echo " 🔄 Replacing URLs in openapi.local.json"
|
|
||||||
sed -e "s|$PLACEHOLDER_API|$API_URI|g" \
|
|
||||||
-e "s|$PLACEHOLDER_DASHBOARD|$DASHBOARD_URI|g" \
|
|
||||||
-e "s|$PLACEHOLDER_LANDING|$LANDING_URI|g" \
|
|
||||||
-e "s|$PLACEHOLDER_WIKI|$WIKI_URI|g" \
|
|
||||||
"$openapi_file" > "${openapi_file}.tmp" && mv "${openapi_file}.tmp" "$openapi_file"
|
|
||||||
echo " ✅ Updated OpenAPI spec with runtime URLs"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Also generate .env file for server-side Next.js standalone
|
|
||||||
cat > "$app_dir/.env" << EOF
|
|
||||||
# Runtime environment configuration
|
|
||||||
# Generated at container startup from environment variables
|
|
||||||
API_URI=${API_URI}
|
|
||||||
DASHBOARD_URI=${DASHBOARD_URI}
|
|
||||||
LANDING_URI=${LANDING_URI}
|
|
||||||
WIKI_URI=${WIKI_URI}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
echo "✅ URL replacement complete for $app"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Replace URLs in all Next.js apps
|
|
||||||
replace_urls_in_app "web" "/app/apps/web/.next/standalone/apps/web"
|
replace_urls_in_app "web" "/app/apps/web/.next/standalone/apps/web"
|
||||||
replace_urls_in_app "landing" "/app/apps/landing/.next/standalone/apps/landing"
|
replace_urls_in_app "landing" "/app/apps/landing/.next/standalone/apps/landing"
|
||||||
replace_urls_in_app "wiki" "/app/apps/wiki/.next/standalone/apps/wiki"
|
replace_urls_in_app "wiki" "/app/apps/wiki/.next/standalone/apps/wiki"
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Generate URL Replacement Manifest
|
||||||
|
# This script runs at BUILD TIME to create a list of files that contain placeholder URLs
|
||||||
|
# This eliminates the need to scan all files at container startup
|
||||||
|
|
||||||
|
APP_NAME=$1
|
||||||
|
APP_DIR=$2
|
||||||
|
|
||||||
|
if [ -z "$APP_NAME" ] || [ -z "$APP_DIR" ]; then
|
||||||
|
echo "Usage: $0 <app_name> <app_dir>"
|
||||||
|
echo "Example: $0 web /app/apps/web"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "🔍 Generating URL manifest for $APP_NAME..."
|
||||||
|
|
||||||
|
# Define placeholder URLs that will be replaced at runtime
|
||||||
|
PLACEHOLDER_API="https://api.useplunk.com"
|
||||||
|
PLACEHOLDER_DASHBOARD="https://app.useplunk.com"
|
||||||
|
PLACEHOLDER_LANDING="https://www.useplunk.com"
|
||||||
|
PLACEHOLDER_WIKI="https://docs.useplunk.com"
|
||||||
|
|
||||||
|
# Output manifest file
|
||||||
|
MANIFEST_FILE="$APP_DIR/.next/url-manifest.txt"
|
||||||
|
|
||||||
|
# Find all files that contain placeholder URLs and save to manifest
|
||||||
|
# Search in .next directory for relevant file types
|
||||||
|
find "$APP_DIR/.next" -type f \( -name "*.js" -o -name "*.json" -o -name "*.html" -o -name "*.rsc" \) \
|
||||||
|
-exec grep -l -E "$PLACEHOLDER_API|$PLACEHOLDER_DASHBOARD|$PLACEHOLDER_LANDING|$PLACEHOLDER_WIKI" {} \; \
|
||||||
|
2>/dev/null > "$MANIFEST_FILE" || true
|
||||||
|
|
||||||
|
# Count files
|
||||||
|
FILE_COUNT=$(wc -l < "$MANIFEST_FILE" | tr -d ' ')
|
||||||
|
|
||||||
|
echo "✅ Generated manifest for $APP_NAME: $FILE_COUNT files need URL replacement"
|
||||||
|
echo " Manifest saved to: $MANIFEST_FILE"
|
||||||
|
|
||||||
|
# Also generate manifest for sitemap/robots files
|
||||||
|
SITEMAP_MANIFEST_FILE="$APP_DIR/.next/sitemap-manifest.txt"
|
||||||
|
find "$APP_DIR/public" -type f \( -name "sitemap*.xml" -o -name "robots.txt" \) 2>/dev/null > "$SITEMAP_MANIFEST_FILE" || true
|
||||||
|
SITEMAP_COUNT=$(wc -l < "$SITEMAP_MANIFEST_FILE" | tr -d ' ')
|
||||||
|
echo "✅ Generated sitemap manifest for $APP_NAME: $SITEMAP_COUNT files"
|
||||||
|
|
||||||
|
exit 0
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Optimized URL Replacement Script
|
||||||
|
# Uses pre-generated manifests to avoid expensive find+grep operations at runtime
|
||||||
|
|
||||||
|
replace_urls_in_app() {
|
||||||
|
local app=$1
|
||||||
|
local app_dir=$2
|
||||||
|
|
||||||
|
echo "📝 Replacing URLs in $app build files..."
|
||||||
|
|
||||||
|
# Define placeholder URLs (built into the app at compile time)
|
||||||
|
local PLACEHOLDER_API="https://api.useplunk.com"
|
||||||
|
local PLACEHOLDER_DASHBOARD="https://app.useplunk.com"
|
||||||
|
local PLACEHOLDER_LANDING="https://www.useplunk.com"
|
||||||
|
local PLACEHOLDER_WIKI="https://docs.useplunk.com"
|
||||||
|
|
||||||
|
# Use pre-generated manifest instead of scanning all files
|
||||||
|
local manifest_file="$app_dir/.next/url-manifest.txt"
|
||||||
|
|
||||||
|
if [ ! -f "$manifest_file" ]; then
|
||||||
|
echo " ⚠️ Warning: Manifest file not found at $manifest_file"
|
||||||
|
echo " This suggests the build process didn't complete correctly."
|
||||||
|
echo " Falling back to runtime file scanning (slower)..."
|
||||||
|
|
||||||
|
# Fallback to old method if manifest doesn't exist
|
||||||
|
local temp_file_list="/tmp/replace_urls_${app}.txt"
|
||||||
|
find "$app_dir/.next" -type f \( -name "*.js" -o -name "*.json" -o -name "*.html" -o -name "*.rsc" \) \
|
||||||
|
-exec grep -l -E "$PLACEHOLDER_API|$PLACEHOLDER_DASHBOARD|$PLACEHOLDER_LANDING|$PLACEHOLDER_WIKI" {} \; \
|
||||||
|
2>/dev/null > "$temp_file_list" || true
|
||||||
|
manifest_file="$temp_file_list"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Count files from manifest
|
||||||
|
local file_count=$(wc -l < "$manifest_file" | tr -d ' ')
|
||||||
|
echo " 📊 Processing $file_count files from manifest"
|
||||||
|
|
||||||
|
if [ "$file_count" -gt 0 ]; then
|
||||||
|
# Process files using xargs for better performance
|
||||||
|
# Use -P 4 to process up to 4 files in parallel
|
||||||
|
# This significantly speeds up processing of many files
|
||||||
|
cat "$manifest_file" | xargs -P 4 -I {} sh -c '
|
||||||
|
file="{}"
|
||||||
|
if [ -f "$file" ]; then
|
||||||
|
sed -e "s|'"$PLACEHOLDER_API"'|'"$API_URI"'|g" \
|
||||||
|
-e "s|'"$PLACEHOLDER_DASHBOARD"'|'"$DASHBOARD_URI"'|g" \
|
||||||
|
-e "s|'"$PLACEHOLDER_LANDING"'|'"$LANDING_URI"'|g" \
|
||||||
|
-e "s|'"$PLACEHOLDER_WIKI"'|'"$WIKI_URI"'|g" \
|
||||||
|
"$file" > "${file}.tmp" && mv "${file}.tmp" "$file"
|
||||||
|
fi
|
||||||
|
'
|
||||||
|
|
||||||
|
echo " ✅ Successfully replaced URLs in $file_count files"
|
||||||
|
else
|
||||||
|
echo " ℹ️ No files found with placeholder URLs"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Process sitemap and robots.txt from manifest
|
||||||
|
echo " 🗺️ Processing sitemap and robots.txt..."
|
||||||
|
local sitemap_manifest="$app_dir/.next/sitemap-manifest.txt"
|
||||||
|
|
||||||
|
if [ -f "$sitemap_manifest" ]; then
|
||||||
|
while IFS= read -r sitemap_file; do
|
||||||
|
if [ -f "$sitemap_file" ]; then
|
||||||
|
local rel_path="${sitemap_file#$app_dir/}"
|
||||||
|
sed -e "s|$PLACEHOLDER_API|$API_URI|g" \
|
||||||
|
-e "s|$PLACEHOLDER_DASHBOARD|$DASHBOARD_URI|g" \
|
||||||
|
-e "s|$PLACEHOLDER_LANDING|$LANDING_URI|g" \
|
||||||
|
-e "s|$PLACEHOLDER_WIKI|$WIKI_URI|g" \
|
||||||
|
"$sitemap_file" > "${sitemap_file}.tmp" && mv "${sitemap_file}.tmp" "$sitemap_file"
|
||||||
|
fi
|
||||||
|
done < "$sitemap_manifest"
|
||||||
|
else
|
||||||
|
# Fallback to finding sitemaps at runtime
|
||||||
|
find "$app_dir/public" -type f \( -name "sitemap*.xml" -o -name "robots.txt" \) 2>/dev/null | while IFS= read -r sitemap_file; do
|
||||||
|
if [ -f "$sitemap_file" ]; then
|
||||||
|
sed -e "s|$PLACEHOLDER_API|$API_URI|g" \
|
||||||
|
-e "s|$PLACEHOLDER_DASHBOARD|$DASHBOARD_URI|g" \
|
||||||
|
-e "s|$PLACEHOLDER_LANDING|$LANDING_URI|g" \
|
||||||
|
-e "s|$PLACEHOLDER_WIKI|$WIKI_URI|g" \
|
||||||
|
"$sitemap_file" > "${sitemap_file}.tmp" && mv "${sitemap_file}.tmp" "$sitemap_file"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Special handling for wiki: also replace URLs in openapi.local.json
|
||||||
|
if [ "$app" = "wiki" ]; then
|
||||||
|
local openapi_file="$app_dir/openapi.local.json"
|
||||||
|
if [ -f "$openapi_file" ]; then
|
||||||
|
echo " 🔄 Replacing URLs in openapi.local.json"
|
||||||
|
sed -e "s|$PLACEHOLDER_API|$API_URI|g" \
|
||||||
|
-e "s|$PLACEHOLDER_DASHBOARD|$DASHBOARD_URI|g" \
|
||||||
|
-e "s|$PLACEHOLDER_LANDING|$LANDING_URI|g" \
|
||||||
|
-e "s|$PLACEHOLDER_WIKI|$WIKI_URI|g" \
|
||||||
|
"$openapi_file" > "${openapi_file}.tmp" && mv "${openapi_file}.tmp" "$openapi_file"
|
||||||
|
echo " ✅ Updated OpenAPI spec with runtime URLs"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Generate .env file for server-side Next.js standalone
|
||||||
|
cat > "$app_dir/.env" << EOF
|
||||||
|
# Runtime environment configuration
|
||||||
|
# Generated at container startup from environment variables
|
||||||
|
API_URI=${API_URI}
|
||||||
|
DASHBOARD_URI=${DASHBOARD_URI}
|
||||||
|
LANDING_URI=${LANDING_URI}
|
||||||
|
WIKI_URI=${WIKI_URI}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "✅ URL replacement complete for $app"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Export the function so it can be sourced by other scripts
|
||||||
|
if [ "$1" != "" ]; then
|
||||||
|
# If called directly with arguments, execute the function
|
||||||
|
replace_urls_in_app "$1" "$2"
|
||||||
|
fi
|
||||||
Reference in New Issue
Block a user