Frontend Development 10 min read

Why Your Updated Frontend Code Isn’t Showing & How to Fix Cache Issues

This article explains why newly deployed front‑end pages often still display old content due to browser, Nginx, or CDN caching, and provides a three‑step method—including proper cache‑control headers, hash‑named assets, and version‑based fallback—to ensure users always see the latest version.

JD Tech Talk
JD Tech Talk
JD Tech Talk
Why Your Updated Frontend Code Isn’t Showing & How to Fix Cache Issues

Introduction: Why Your Code Updates Are Ignored

Developers often wonder why a newly deployed version still shows the old page. The cause is usually browser and server caching, not missing uploads.

1. How Cache Tricks the Browser

1.1 Typical Symptoms

User reports page malfunction while local tests pass.

After refreshing, the index.html still references old JS/CSS files.

Network requests return 304 Not Modified or 200 OK from memory cache.

1.2 Main Culprits

Suspect

Method

Typical Quote

Browser cache

Keeps old file copies

"I just got this JS last week!"

Nginx default config

Missing proper cache headers

"I followed the rules, blame me?"

CDN cache

Global node sync delay

"Hold on, let me finish my tea"

2. Cache‑Control Response Headers

2.1 Strong vs Negotiated Cache

Strong cache : Browser uses local copy without contacting server.

Cache-Control: max-age=31536000  # cache for one year

Negotiated cache : Browser asks server if resource changed.

Last-Modified: Wed, 20 May 2024 08:00:00 GMT
ETag: "abc123"

2.2 Core Principles

HTML files : Disable cache, always fetch fresh version.

Static assets with hash : Use long‑term cache with hash in filename.

Static assets without hash : Use short‑term cache.

# Build output example
/dist/index.html
/dist/logo.png
/dist/assets/main.3f7a8b.js
/dist/assets/style.abcd12.css
/dist/assets/hello.ac2314.png

3. Three‑Step Solution

3.1 Step 1 – Precise Nginx Configuration

server {
    listen 80;
    server_name your-domain.com;
    root /path/to/your/dist;

    # 1. Long‑term cache for /assets/ (hashed files)
    location ^~ /assets/ {
        expires 1y;
        add_header Cache-Control "public, max-age=31536000, immutable";
        add_header X-Content-Type-Options "nosniff";
        try_files $uri =404;
    }

    # 2. Short‑term cache for other static files
    location ~* \.(js|css|png|jpg|gif|svg|webp|woff2?|ttf|eot|mp4|mp3|json|xml|txt|csv|wasm)$ {
        if ($request_uri ~ "^/assets/") { break; }
        add_header Cache-Control "public, max-age=3600, must-revalidate";
        add_header X-Content-Type-Options "nosniff";
        try_files $uri =404;
    }

    # 3. Disable cache for front‑end routes
    location / {
        add_header Cache-Control "no-store, no-cache, must-revalidate";
        add_header Pragma "no-cache";
        add_header Expires 0;
        try_files $uri $uri/ @fallback;
    }

    # 4. Fallback to index.html
    location @fallback {
        rewrite ^ /index.html last;
    }
}

3.2 Step 2 – Build Hash‑Named Files

Configure the build tool to append a hash to filenames (e.g., main.

hash

.js). When the file content changes, the hash changes, automatically invalidating the cache.

# Example output
/dist/assets/main.3f7a8b.js
/dist/assets/style.abcd12.css

3.3 Step 3 – Version‑Number Fallback

Inject a version timestamp into HTML and generate version.json . At runtime, fetch the JSON and compare with the embedded version; if they differ, prompt the user to refresh. <code>/* checkVersion.ts (simplified) */ export const checkVersion = async () => { const metaTag = document.querySelector('meta[name="version-time"]'); const localVersion = metaTag?.getAttribute('content') ?? ''; const response = await fetch(`/version.json?t=${Date.now()}`, { cache: 'no-store' }); const { versionTime: latestVersion } = await response.json(); if (localVersion && latestVersion && localVersion !== latestVersion) { ElMessage('New version detected, click to refresh for a better experience.'); } };</code>

4. Verify Your Configuration

4.1 Quick Validation Commands

# HTML/route response (should disable cache)
curl -I https://your-domain.com/about
# Expected: Cache-Control: no-store, no-cache, must-revalidate

# Hashed static asset (should have long‑term cache)
curl -I https://your-domain.com/assets/main.3f7a8b.js
# Expected: Cache-Control: public, max-age=31536000, immutable

# Non‑hashed static asset (should have short‑term cache)
curl -I https://your-domain.com/logo.png
# Expected: Cache-Control: public, max-age=3600, must-revalidate

4.2 Common Pitfalls

Forgot to reload Nginx after changes.

Mismatch between /assets/ path and actual build output.

CDN still serving stale copies.

Service workers interfering with cache.

5. Advanced Topics

5.1 Cache Isolation for API Proxy

location /api {
    proxy_pass http://backend-server/api;
    add_header Cache-Control "no-store";
    add_header Access-Control-Allow-Origin "https://your-frontend-domain.com";
    add_header Access-Control-Allow-Credentials "true";
}

5.2 Security Headers

add_header X-Content-Type-Options "nosniff";  # Prevent MIME sniffing

6. Summary

Proper cache management turns a performance boost into a reliable user experience; misuse leaves users stuck on outdated pages.

Respect cache, use versioning, and monitor alerts for safe deployments.
图片
图片
frontendDeploymentCachingNginxHashcache-control
JD Tech Talk
Written by

JD Tech Talk

Official JD Tech public account delivering best practices and technology innovation.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.