Skip to content

Instantly share code, notes, and snippets.

@mixxorz
Last active March 6, 2025 10:03
Show Gist options
  • Save mixxorz/e7cacd75af3cc6b4f1446613abce033a to your computer and use it in GitHub Desktop.
Save mixxorz/e7cacd75af3cc6b4f1446613abce033a to your computer and use it in GitHub Desktop.
Tampermonkey script that allows you to test your CSS/JS on staging/production sites without a deployment

Local Dev Redirector

Redirect requests for specific JS/CSS files to your local versions for development.

I sometimes find myself needing to test my local development JS/CSS files on staging/production without actually comitting the file and making a deployment. This can be because staging/production has specific content that you can't replicate locally, or if one or more of your front-end components need to execute on the correct domain.

So I (cough ChatGPT) wrote this script that replaces the URLs in the <script> and tags that you specify. More than that, it can also redirect requests for specific endpoints to your local development server for further testing flexibility.

Usage

To use this script, you need to install Tampermonkey (or equivalent for your browser). Then:

  1. Add the script to Tampermonkey (you can just copy paste the script)
  2. Update the @namespace and @match configuration to match the domain where you want the script to be active
  3. Update the config object. The key is the URL you want to replace and the value is the URL you want to replace it with.
  4. Save the script
  5. Enable it in Tampermonkey

Caveats

CORS and CSP settings on your site may block your local scripts from running on your page. You may need to use additional browser extensions to temporarily disable CORS or CSP.

// ==UserScript==
// @name Local Dev Redirector
// @namespace https://your.domain/
// @version 0.1
// @description Redirect requests for specific JS/CSS files to your local versions for development.
// @author Mitchel Cabuloy
// @match https://your.domain/*
// @grant none
// @run-at document-start
// ==/UserScript==
(function() {
'use strict';
// Configuration: map production URL substrings to local development URLs.
// Example: When a script's src includes '/assets/app.js', it will be replaced by your local server URL.
const config = {
"/static/js/main.ae60a36dedc8.js": "http://localhost:3000/static/js/main.js",
"/static/css/main.3d458c00f642.css": "http://localhost:3000/static/css/main.css"
// Add more mappings as needed.
};
// Helper function: if URL contains any key in config, return the corresponding local URL.
function getRedirectUrl(url) {
for (const key in config) {
if (url.includes(key)) {
console.log(`Redirecting "${url}" to "${config[key]}"`);
return config[key];
}
}
return url;
}
// --- DOM Mutation Observer ---
// Observe added script and link elements and update their src/href if needed.
function processElement(el) {
if (el.tagName === 'SCRIPT' && el.src) {
el.src = getRedirectUrl(el.src);
} else if (el.tagName === 'LINK' && el.href) {
el.href = getRedirectUrl(el.href);
}
}
// Process any already existing elements.
document.querySelectorAll('script[src], link[href]').forEach(processElement);
// Observe future DOM changes.
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
mutation.addedNodes.forEach(node => {
if (node.nodeType === Node.ELEMENT_NODE) {
processElement(node);
// Also process any descendant script or link elements.
node.querySelectorAll && node.querySelectorAll('script[src], link[href]').forEach(processElement);
}
});
});
});
observer.observe(document.documentElement, { childList: true, subtree: true });
// --- Fetch API Override ---
const originalFetch = window.fetch;
window.fetch = function(...args) {
if (typeof args[0] === 'string') {
args[0] = getRedirectUrl(args[0]);
} else if (args[0] && args[0].url) {
// If the Request object is passed
args[0] = new Request(getRedirectUrl(args[0].url), args[0]);
}
return originalFetch.apply(this, args);
};
// --- XMLHttpRequest Override ---
const originalXHROpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, url, ...rest) {
const newUrl = getRedirectUrl(url);
return originalXHROpen.call(this, method, newUrl, ...rest);
};
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment