diff --git a/Dockerfile b/Dockerfile index 4da0eb6..a6812e6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,6 +11,11 @@ RUN printf '{"version":"%s","buildDate":"%s"}\n' "${VERSION}" "${BUILD_DATE}" > COPY index.html /usr/share/nginx/html/ COPY src/ /usr/share/nginx/html/src/ +# Copy and run cache busting script (bash/sed - no external dependencies needed) +COPY build-cache-bust.sh /tmp/build-cache-bust.sh +RUN chmod +x /tmp/build-cache-bust.sh && \ + /tmp/build-cache-bust.sh "${VERSION}" /usr/share/nginx/html + # Copy nginx configuration COPY nginx.conf /etc/nginx/conf.d/default.conf diff --git a/build-cache-bust.sh b/build-cache-bust.sh new file mode 100755 index 0000000..ecac517 --- /dev/null +++ b/build-cache-bust.sh @@ -0,0 +1,46 @@ +#!/bin/sh +# Simple cache busting script - adds version query params to all JS imports +# Only runs during Docker build, not during local development +# This keeps development simple (no tools needed) while ensuring production cache busting + +VERSION="${1:-dev}" +SRC_DIR="${2:-/usr/share/nginx/html}" + +echo "Adding cache busting (v=${VERSION}) to JS imports in ${SRC_DIR}/src..." + +# Find all JS files and add version query param to relative imports +find "$SRC_DIR/src" -type f -name "*.js" | while read -r file; do + # Skip if file doesn't exist + [ ! -f "$file" ] && continue + + # Process file with sed to add version query params + # Pattern: from './path.js' or from "../path.js" or import('./path.js') + # Only match relative imports (./ or ../) ending in .js + # Skip if already has query params (contains ?) + + # Handle single quote imports: from './path.js' + sed -i.bak \ + -e "s|from '\\(\\.[./][^']*\\.js\\)'|from '\\1?v=${VERSION}'|g" \ + -e "s|from '\\(\\.[./][^']*\\.js\\)?[^']*'|from '\\1?v=${VERSION}'|g" \ + "$file" + + # Handle double quote imports: from "./path.js" + sed -i.bak \ + -e "s|from \"\\(\\.[./][^\"]*\\.js\\)\"|from \"\\1?v=${VERSION}\"|g" \ + -e "s|from \"\\(\\.[./][^\"]*\\.js\\)?[^\"]*\"|from \"\\1?v=${VERSION}\"|g" \ + "$file" + + # Handle dynamic imports: import('./path.js') + sed -i.bak \ + -e "s|import('\\(\\.[./][^']*\\.js\\)')|import('\\1?v=${VERSION}')|g" \ + -e "s|import('\\(\\.[./][^']*\\.js\\)?[^']*')|import('\\1?v=${VERSION}')|g" \ + -e "s|import(\"\\(\\.[./][^\"]*\\.js\\)\")|import(\"\\1?v=${VERSION}\")|g" \ + -e "s|import(\"\\(\\.[./][^\"]*\\.js\\)?[^\"]*\")|import(\"\\1?v=${VERSION}\")|g" \ + "$file" + + # Remove backup file + rm -f "${file}.bak" +done + +echo "Cache busting complete! All JS imports now include ?v=${VERSION}" + diff --git a/nginx.conf b/nginx.conf index eee0bb3..b7b147e 100644 --- a/nginx.conf +++ b/nginx.conf @@ -9,11 +9,19 @@ server { try_files $uri $uri/ =404; } - # Prevent caching of JavaScript files and version.json - location ~* \.(js|mjs)$ { - add_header Cache-Control "no-cache, no-store, must-revalidate"; - add_header Pragma "no-cache"; - add_header Expires "0"; + # Cache JavaScript files with version query params for 1 year (immutable) + # Files without version params are not cached + location ~* \.(js|mjs)(\?v=[^&]+)?$ { + if ($args ~ "v=") { + # Has version param - cache for 1 year (immutable) + add_header Cache-Control "public, max-age=31536000, immutable"; + } + if ($args !~ "v=") { + # No version param - don't cache + add_header Cache-Control "no-cache, no-store, must-revalidate"; + add_header Pragma "no-cache"; + add_header Expires "0"; + } add_header Vary "Accept-Encoding"; }