Skip to content

Instantly share code, notes, and snippets.

@michielgerritsen
Last active April 17, 2025 05:44
Show Gist options
  • Save michielgerritsen/306c0d2f6dd75d8f6b1d6c397ccb2aa0 to your computer and use it in GitHub Desktop.
Save michielgerritsen/306c0d2f6dd75d8f6b1d6c397ccb2aa0 to your computer and use it in GitHub Desktop.
Find old Luma code so you can convert it to Hyvä Alpine.js code

Introduction

The goal of this script is to help you migrate you old Magento Luma code to Hyvä compliant code. Luma used to rely on Require.js to manage it's javascript components. Hyvä relies on Alpine.js for this. For a lot of modules there are already compatibility modules available. Custom code you have to convert yourself.

Usage

There are several ways to use this code:

  • Using Tampermonkey (Chrome) or Greasemonkey (Firefox). If you have that installed just click on "Raw" by the requirejs-finder.user.js file.
  • (Temporary) By injecting it into Magento's head. Open the admin and navigate to Content -> Design -> Click your theme -> HTML -> Head -> Add <script></script> and place the code above between the two script tags.

Please note: This code is only for development purposes. Do not, I repeat, do not run this in production.

Use case

Q: These errors are logged in your console by default, why would you want to use an extension for this? A: Good question. While developing these errors are sometimes hard to spot. You might have your product page ready for your new Hyvä theme, but what about more obscure pages, like some CMS or customer account pages? This module will give you a big warning when you forget to upgrade code somehwere.

About

This extension has been developed by Control Alt Delete. We are a company with deep knowledge about Hyvä and especially the Hyvä Checkout. Need help with your project? Feel free to contact us.

Newsletter

Do you like little script like these that makes your life easier and want to stay in the loop about what is happing around Magento? Then you should subscribe to MageDispatch.com. This is a developer-focussed newsletter around Magento.

// ==UserScript==
// @name Require.js Warning
// @namespace https://www.controlaltdelete.dev/
// @author Michiel Gerritsen
// @version 1.0
// @description Warn about require.js usage
// @match *://*/*
// @run-at document-start
// @grant none
// ==/UserScript==
(function() {
// Private variables in closure
let cssInjected = false;
const attemptedModules = new Set();
let requireCallCount = 0;
// Store any existing require/define functions
const originalRequire = window.require;
const originalDefine = window.define;
// Create a function that returns undefined for detection attempts
function createProxyFunction(name, implementation) {
return function(...args) {
// Check if this is likely a detection attempt
const stack = new Error().stack || '';
const isDetectionAttempt = stack.includes('eval') ||
stack.includes('Function(') ||
args.length === 0;
if (isDetectionAttempt) {
// Make it appear as if require/define don't exist
return undefined;
}
// Otherwise run the warning implementation
return implementation.apply(this, args);
};
}
// Private functions in closure
function injectCSS() {
if (cssInjected) return;
cssInjected = true;
const style = document.createElement('style');
style.textContent = `
.require-warning-banner {
background-color: #dc3545;
color: white;
padding: 16px;
margin: 8px 0;
border-radius: 4px;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
font-size: 16px;
line-height: 1.5;
font-weight: bold;
text-align: center;
}
.require-warning {
background-color: #fff3cd;
color: #856404;
padding: 12px;
margin: 8px 0;
border: 1px solid #ffeeba;
border-radius: 4px;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
font-size: 14px;
line-height: 1.5;
}
.require-warning-stack {
margin-top: 8px;
font-family: monospace;
font-size: 12px;
color: #666;
white-space: pre-wrap;
}
.require-warning-stack a {
color: #0366d6;
text-decoration: none;
}
.require-warning-stack a:hover {
text-decoration: underline;
}`;
document.head.appendChild(style);
}
function createBanner() {
const banner = document.createElement('div');
banner.className = 'require-warning-banner';
banner.innerHTML = `Require.js is still being called! (<span class="require-call-count">${requireCallCount}</span> times) If you want to update your site to Hyvä you should migrate this javascript to Alpine.js`;
const maincontent = document.querySelector('#maincontent');
if (maincontent) {
maincontent.insertBefore(banner, maincontent.firstChild);
}
}
function updateCallCount() {
const countElement = document.querySelector('.require-call-count');
if (countElement) {
countElement.textContent = requireCallCount;
}
}
function getStackTrace() {
const error = new Error();
return error.stack
?.split('\n')
.filter(line => !line.includes('at window.require'))
.slice(3) // Skip Error, getStackTrace, and warnAboutModule
.map(line => line.trim())
.join('\n');
}
function createWarning(message, stackTrace) {
injectCSS();
// Only create banner once when first warning appears
if (!document.querySelector('.require-warning-banner')) {
createBanner();
}
const warning = document.createElement('div');
warning.className = 'require-warning';
const messageDiv = document.createElement('div');
messageDiv.textContent = message;
warning.appendChild(messageDiv);
if (stackTrace) {
const stackDiv = document.createElement('div');
stackDiv.className = 'require-warning-stack';
const formattedStack = stackTrace;
stackDiv.innerHTML = formattedStack;
warning.appendChild(stackDiv);
}
const maincontent = document.querySelector('#maincontent');
if (maincontent) {
maincontent.insertBefore(warning, maincontent.querySelector('.require-warning-banner').nextSibling);
}
}
function warnAboutModule(modules) {
const stackTrace = getStackTrace();
if (typeof modules === 'string') {
if (attemptedModules.has(modules)) return;
attemptedModules.add(modules);
createWarning(
`Warning: Attempted to load "${modules}" via require.js, which is no longer supported.`,
stackTrace
);
} else if (Array.isArray(modules)) {
const newModules = modules.filter(m => !attemptedModules.has(m));
if (newModules.length === 0) return;
newModules.forEach(m => attemptedModules.add(m));
createWarning(
`Warning: Attempted to load modules via require.js, which is no longer supported:\n` +
newModules.map(m => `• ${m}`).join('\n'),
stackTrace
);
}
}
function logConsoleWarning() {
// Only log once
if (window._requireWarningLogged) return;
window._requireWarningLogged = true;
console.warn(
'%c⚠️ Require.js Usage Detected! ⚠️\n' +
'%cIf you want to update your site to Hyvä you should migrate this javascript to Alpine.js',
'font-size: 20px; font-weight: bold; color: #dc3545;',
'font-size: 16px; color: #856404;'
);
}
// Main require implementation
const requireImplementation = function(modules, callback) {
requireCallCount++;
const originalError = new Error(`Require.js usage detected: ${Array.isArray(modules) ? modules.join(', ') : modules}`);
logConsoleWarning();
console.warn(
'%cRequire.js module(s) requested: %c' + (Array.isArray(modules) ? modules.join(', ') : modules) +
'\n%cTotal calls: %c' + requireCallCount,
'color: #856404; font-weight: bold;',
'color: #dc3545; font-weight: bold;',
'color: #856404; font-weight: bold;',
'color: #dc3545; font-weight: bold;',
'\n',
originalError
);
warnAboutModule(modules);
updateCallCount();
if (typeof callback === 'function') {
const mockModules = Array.isArray(modules)
? modules.map(() => ({}))
: [{}];
callback.apply(null, mockModules);
}
};
// Main define implementation
const defineImplementation = function(name, deps, callback) {
requireCallCount++;
const originalError = new Error('Define call detected' +
(typeof name === 'string' ? `: ${name}` : ''));
logConsoleWarning();
console.warn(
'%cRequire.js define called: %c' + (typeof name === 'string' ? name : 'anonymous module') +
'\n%cTotal calls: %c' + requireCallCount,
'color: #856404; font-weight: bold;',
'color: #dc3545; font-weight: bold;',
'color: #856404; font-weight: bold;',
'color: #dc3545; font-weight: bold;',
'\n',
originalError
);
if (Array.isArray(name)) {
deps = name;
name = undefined;
}
if (Array.isArray(deps)) {
warnAboutModule(deps);
}
updateCallCount();
};
// Only set up our proxies if require/define don't already exist
if (!originalRequire) {
window.require = createProxyFunction('require', requireImplementation);
}
if (!originalDefine) {
window.define = createProxyFunction('define', defineImplementation);
// Still maintain AMD compatibility for actual usage attempts
window.define.amd = {};
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment