D
P
0

WordPress & JavaScript

Editing a Theme's Source JS Changes Nothing in the Browser? The Enqueue Silently Loads a Stale `.min.js` From `dist`

June 29, 2026·4 min read
Editing a Theme's Source JS Changes Nothing in the Browser? The Enqueue Silently Loads a Stale `.min.js` From `dist`

The task that afternoon was trivial: fix the mobile nav menu behavior on a client's membership site. I opened assets/js/src/nav.js, changed a few lines, saved, uploaded. Hard refresh in the browser. No change. Refreshed again holding Shift. Still nothing. I bumped the ?ver= on the enqueue, purged the page cache, opened an incognito window, even tested from my phone on cellular data. The menu kept behaving exactly as it did before my edit, as if my change had never existed.

My first instinct, as always, was to blame cache. Surely there was one more layer I had not purged: an object cache, a CDN, some stubborn browser cache. But after the ?ver= bump, the page cache purge, and incognito all still showed the old behavior, the cache theory stopped holding together. If the cache is busted and the result is identical, maybe the server is genuinely still shipping the old file.

So I did what I should have done in the first minute: check which file the browser was actually loading. DevTools, Network tab, filter by JS, refresh. And there was the answer. The browser never loaded nav.js at all. It loaded nav.min.js, out of the dist folder. I clicked into the file and searched for the name of the new function I had just written. Zero hits. The file I was editing and the file being shipped to visitors were two different files.

Why this happens

The theme has an enqueue helper built on a very common pattern: if a built, minified version exists in the dist folder, use it; otherwise fall back to the source. Roughly this:

function theme_enqueue_nav_script() {
    $src_rel = '/assets/js/src/nav.js';
    $min_rel = '/assets/js/dist/nav.min.js';
 
    $rel = file_exists( get_template_directory() . $min_rel )
        ? $min_rel
        : $src_rel;
 
    wp_enqueue_script(
        'theme-nav',
        get_template_directory_uri() . $rel,
        array(),
        '1.4.2',
        true
    );
}
add_action( 'wp_enqueue_scripts', 'theme_enqueue_nav_script' );

The file_exists( $min ) ? $min : $src pattern is well-intentioned: production always gets the small, optimized file. But buried inside it is a hidden assumption that the dist file is always in sync with the source. The moment I forgot to run the build after editing, dist went stale, file_exists stayed true, and the helper faithfully served that old minified file. My edits in src never had a path to the browser at all.

The most misleading part was the ?ver= bump. Raising the version on the enqueue genuinely worked: the browser re-downloaded the file, the cache-bust succeeded. But what it re-downloaded was the exact same stale minified bytes. So every symptom looked like a caching problem, and every "cache fix" I applied really did run while changing nothing, because the actual problem sat one step earlier: in the build step.

The fix

The immediate fix is simple: run the build so dist regenerates from the fresh source.

npm run build

The moment the new nav.min.js existed and got deployed, my change showed up instantly. And since the helper prefers the dist file, that file is what production actually consumes, so the build output has to be committed too, not just the source.

Longer term, I did not want to rely on remembering "edit means build". WordPress already ships the escape hatch: the SCRIPT_DEBUG constant, designed precisely to force the un-minified version during development. Enable it in your local wp-config.php:

define( 'SCRIPT_DEBUG', true );

Then teach the helper to respect it:

$use_min = file_exists( get_template_directory() . $min_rel )
    && ! ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG );
 
$rel = $use_min ? $min_rel : $src_rel;

With that in place, the local browser always loads the source file directly, so every edit is live without a build. In production, SCRIPT_DEBUG is undefined, and visitors keep getting the minified file as they should.

The checklist

When a JavaScript edit appears to "do nothing", check these before blaming cache:

  • Confirm which file the browser actually loaded: DevTools, Network tab, open the JS file, and search inside it for your new code. If your new code is not in that file, the problem is not cache.
  • Know your theme's enqueue helper. If there is a .min.js preference pointing at dist, edits to the source will never reach the browser without a build.
  • Make the build part of the loop: every JS edit is followed by npm run build, and the dist file gets committed.
  • Enable SCRIPT_DEBUG in your local wp-config.php so development always serves the source, never a stale build artifact.

Since that day, "cache" has been demoted to the last suspect I question, not the first. My opening question is now always the same: which file actually reached the browser?