zwernemann/magento2-minresolver

Fixes intermittent *.min.js 404 errors (e.g. globals.js) caused by stale baseUrl and double-wrapping of the RequireJS min-resolver in Magento 2.

Maintainers

Package info

github.com/Zwernemann/magento2-minResolver

Type:magento2-module

pkg:composer/zwernemann/magento2-minresolver

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

1.0.0 2026-03-24 13:32 UTC

This package is auto-updated.

Last update: 2026-03-27 15:54:01 UTC


README

A drop-in patch for Magento 2 that fixes intermittent 404 errors caused by RequireJS loading plain .js files instead of .min.js when JavaScript minification is enabled in the Admin panel.

Tested on Magento 2.4.7-p9.

The Problem

What you see

With Minify JavaScript Files enabled (Admin → Stores → Config → Advanced → Developer → JavaScript Settings), Magento Admin works fine most of the time. But after navigating back and forth several times — for example between Sales → Orders and Create Order — the browser console suddenly shows:

GET /static/version.../adminhtml/.../mage/adminhtml/globals.js
    net::ERR_ABORTED 404 (Not Found)

The page may partially break: grids don’t load, buttons stop responding, or JavaScript errors cascade. A hard reload fixes it temporarily — until it happens again.

Why is it intermittent?

The bug does not appear on the first page load. It surfaces only after several AJAX navigations within the same browser session. A single smoke test is unlikely to catch it.

Root Causes

Magento ships a small script called requirejs-min-resolver.min.js that is injected into every Admin page. Its job is to force RequireJS to always request .min.js URLs. The original implementation contains two defects.

Defect 1 — Stale baseUrl closure

// Original Magento code
(function() {
    var ctx = require.s.contexts._,
        origNameToUrl = ctx.nameToUrl,
        baseUrl = ctx.config.baseUrl;  // captured ONCE at script-load time

    ctx.nameToUrl = function() {
        var url = origNameToUrl.apply(ctx, arguments);
        if (url.indexOf(baseUrl) === 0   // compared against the stale value
            && !url.match(/\/hugerte\//)
            && !url.match(/\/v1\/songbird/)) {
            url = url.replace(/(\.min)?\.js$/, '.min.js');
        }
        return url;
    };
}());

baseUrl is captured once when the script first runs. During AJAX navigation Magento can reconfigure RequireJS. After reconfiguration ctx.config.baseUrl has a new value, but the closed-over baseUrl variable is still the old one. The indexOf check fails for every URL, the .min.js rewrite is skipped, and the browser requests the plain .js file — which does not exist — resulting in a 404.

Defect 2 — Double-wrapping on re-evaluation

On AJAX navigation the Admin can re-inject and re-evaluate requirejs-min-resolver.min.js. Each evaluation runs ctx.nameToUrl = function() { ... origNameToUrl ... } where origNameToUrl was captured from the current ctx.nameToUrl — which is already the patched version from the previous evaluation. The result is a growing chain:

patch3( patch2( patch1( original ) ) )

With no idempotency guard, each additional wrapper can alter the URL differently, potentially producing wrong paths or double-suffixed filenames like globals.min.min.js.

The Fix

A single self-contained IIFE that closes both gaps:

(function(){

  function patchCtx(c){
    if(!c||c.__mRF)return;   // idempotency guard — never patch twice
    c.__mRF=true;
    var p=c.nameToUrl;
    c.nameToUrl=function(){
      // baseUrl read dynamically on every call — never goes stale
      var u=p.apply(c,arguments),b=c.config&&c.config.baseUrl;
      if(b&&u.indexOf(b)===0
        &&!/\.min\.js$/.test(u)
        &&!/\/hugerte\//.test(u)
        &&!/\/v1\/songbird/.test(u)){
        u=u.replace(/\.js$/,'.min.js');
      }
      return u;
    };
  }

  // Layer 1 — patch every context that exists right now (including _)
  var ctxs=require.s.contexts;
  for(var n in ctxs){
    if(Object.prototype.hasOwnProperty.call(ctxs,n))patchCtx(ctxs[n]);
  }

  // Layer 2 — patch every context created from this point on
  if(!require.s.__mNCF){
    require.s.__mNCF=true;
    var oNC=require.s.newContext;
    require.s.newContext=function(){
      var c=oNC.apply(this,arguments);
      patchCtx(c);
      return c;
    };
  }

  // Layer 3 — rewrite the URL at the last possible moment before the XHR fires
  if(!require.__mRL){
    require.__mRL=true;
    var ol=require.load;
    require.load=function(c,m,u){
      var b=c&&c.config&&c.config.baseUrl;
      if(b&&u&&u.indexOf(b)===0
        &&/\.js$/.test(u)&&!/\.min\.js$/.test(u)
        &&!/\/hugerte\//.test(u)&&!/\/v1\/songbird/.test(u)){
        u=u.replace(/\.js$/,'.min.js');
      }
      return ol.call(this,c,m,u);
    };
  }

  console.info('[rjsFix] v6 active');
}());

How each defect is addressed

Defect Original Fix
Stale baseUrl Captured once in outer closure Read as c.config.baseUrl inside the function on every call
Double-wrapping No guard __mRF flag on each context prevents patching more than once

Additional layers

Layer What it covers
Context loop at load time All RequireJS contexts already present, including _
newContext hook Every new named context created after the script runs
require.load hook Last-resort safety net — rewrites the URL just before the XHR fires
__mNCF / __mRL flags Ensure the newContext and load hooks are installed exactly once

Exclusions

hugerte and v1/songbird are third-party libraries that ship only as unminified JS and must not be rewritten.

Compatibility

  • Magento 2.4.x (tested on 2.4.7-p9)
  • Only active when Minify JavaScript Files is enabled; has no effect otherwise

Confirmed Magento Core Issues

Issue Description
#38829 JS Minification & RequireJS loading in production 2.4.7 — both .min and non-min files are requested simultaneously
#38117 requirejs-min-resolver.min.js not generated on setup:static-content:deploy — navigation fails after first page load

Installation

Via Composer

composer require zwernemann/magento2-minresolver
bin/magento module:enable Zwernemann_MinResolver
bin/magento setup:upgrade
bin/magento setup:static-content:deploy
bin/magento cache:flush

Manually

Copy app/code/Zwernemann/MinResolver to your Magento installation, then:

bin/magento module:enable Zwernemann_MinResolver
bin/magento setup:upgrade
bin/magento setup:static-content:deploy
bin/magento cache:flush

Compatibility

  • Magento 2.3.x, 2.4.x
  • PHP 7.4+

License

MIT

Contact

Zwernemann Medienentwicklung
Martin Zwernemann
79730 Murg, Germany

To the website

If you have questions, problems, or ideas for new features – feel free to get in touch.