• Skip to main content
  • Skip to secondary navigation
  • Skip to footer

recoveryArea

Content Management for Everyone!

  • About me
  • Blog
  • AB Testing
  • WordPress
  • Portfolio

Geen categorie

Building a Developer-Friendly Chrome Extension: Script Redirector with Live Reload

5 June 2025 By iPasqualito

As a developer working on conversion rate optimization (CRO) projects, I often found myself needing to test locally built JavaScript against live production websites. The traditional approach of constantly uploading files or modifying production code was both slow and risky. That’s when I decided to build MintMinds RequestLite — a Chrome extension that solves this problem elegantly.

The Problem

When developing JavaScript for live websites, you typically face these challenges:

  1. Testing locally built scripts against production environments
  2. Rapid iteration without constant file uploads
  3. Live reload functionality for instant feedback
  4. Simple management of multiple redirect rules

The Solution

The extension provides two core features:

1. Script Redirection

Instead of loading scripts from https://cdn.example.com/script.js, the extension can redirect requests to http://localhost:4173/script.js — allowing you to test your local development server’s output against live sites.

2. Live Reload Integration

A WebSocket-based live reload system that automatically refreshes pages when your development server signals changes.

Technical Architecture

Manifest V3 Foundation

{
  "manifest_version": 3,
  "permissions": [
    "declarativeNetRequest",
    "storage", 
    "activeTab",
    "scripting"
  ],
  "host_permissions": ["<all_urls>"]
}

The extension uses modern Chrome APIs:

  • declarativeNetRequest for intercepting and redirecting network requests
  • scripting for dynamic content script injection
  • storage for persisting user preferences

Rule-Based Configuration

Rules are stored in a simple JSON format:

{
  "id": "my-script",
  "name": "My Development Script",
  "enabled": false,
  "match": "https://cdn.example.com/script.js",
  "redirect": "http://localhost:4173/script.js"
}

Dynamic Rule Management

The extension converts string-based rule IDs to numeric hashes (required by Chrome’s API) while maintaining collision detection:

export function stringToHashCode(str) {
  let hash = 0;
  for (let i = 0; i < str.length; i++) {
    const char = str.charCodeAt(i);
    hash = ((hash << 5) - hash) + char;
    hash |= 0;
  }
  return Math.abs(hash % 2147483647) + 1;
}

Live Reload Implementation

The live reload feature uses dynamic content script registration:

// Register content script when enabled
await chrome.scripting.registerContentScripts([{
  id: "livereload-script",
  matches: ["<all_urls>"],
  js: ["src/content/livereload.js"],
  runAt: "document_start"
}]);

The injected script establishes a WebSocket connection:

try {
  const socket = new WebSocket("ws://localhost:5678");
  socket.addEventListener("message", (event) => {
    if (event.data === "reload") {
      console.log("🔁 reload triggered by dev server");
      location.reload();
    }
  });
} catch (error) {
  console.warn("Error setting up LiveReload listener:", error);
}

User Experience

Clean Interface

The popup provides an intuitive interface with:

  • LiveReload toggle at the top for quick access
  • Individual rule toggles for granular control
  • Visual separation between different feature sets

Persistent State

All settings persist across browser sessions using Chrome’s storage API, so your development environment stays configured exactly how you left it.

Development Benefits

Faster Iteration

No more manual file uploads or cache clearing. Changes in your local development server are instantly reflected on live sites.

Risk Reduction

Test thoroughly in production-like environments without touching actual production files.

Multiple Project Support

Manage different redirect rules for various projects, enabling or disabling them as needed.

Key Learnings

Manifest V3 Considerations

  • Content scripts must be registered dynamically rather than declared in manifest
  • Service workers replace background pages, requiring careful state management
  • declarativeNetRequest is more restrictive but more performant than webRequest

Chrome Extension Gotchas

  • Rule IDs must be numeric for declarativeNetRequest API
  • Hash collision detection is crucial for string-to-numeric ID conversion
  • Error handling is essential for graceful degradation

User Experience Design

  • Visual separation of features prevents confusion
  • Consistent toggle patterns create intuitive interactions
  • Status feedback helps users understand what’s happening

Future Enhancements

The extension could be extended with:

  • Custom script injection with user-defined code
  • Request headers modification for advanced testing scenarios
  • Multiple environment support (staging, preview, etc.)
  • Import/export functionality for team sharing

Conclusion

Building this Chrome extension taught me valuable lessons about modern web extension development, user experience design, and developer tooling. The combination of script redirection and live reload has significantly improved my CRO development workflow.

The extension demonstrates how a focused tool solving a specific developer pain point can have outsized impact on productivity. Sometimes the best solutions are the simple ones that just work.


The extension uses Chrome Extension Manifest V3 and modern JavaScript modules. Full source code demonstrates clean separation of concerns between background scripts, content scripts, and popup UI management.

Filed Under: Geen categorie

How To List User Defined Window Globals with Javascript

17 March 2023 By iPasqualito

There might be occasions where you want to inspect what is defined on the Window object, for instance is jQuery or Google Analytics loaded, or are there third party scripts that pollute your global Window scope?

In that case this script might come in handy. If you run it in your browsers console, it will create an object containing all user defined globals, nicely subdivided by type.

Wrap your code in an IIFE so we don’t do any polluting ourselves.

It works as follows: first, we declare 2 arrays, one empty called ‘filteredPropKeys’ and one that hold all the property names from the globals on Window called ‘allWindowPropKeys’. What we also need is an empty object that will hold all the user defined globals, let’s call it ‘customProperties’.

// create an iframe and append to body to load a clean window object
let filteredPropKeys,
	allWindowPropKeys = Object.getOwnPropertyNames(win),
	customProperties = {
		array: {},
		object: {}
	},
	iframe = doc.createElement("iframe");
// hide it just to be sure
iframe.style.display = "none";
// and append to the body
doc.body.append(iframe);

It then creates an iFrame element so we have a clean reference Window object. The iFrame is appended to body, so we can compare the original Window object with the iFrame Window object. Everything that is not defined on the iFrame window object will be added to the ‘filteredPropKeys’ array.

// filter the list against the properties that exist in the iframe
filteredPropKeys = allWindowPropKeys.filter(windowPropKeys => !iframe.contentWindow.hasOwnProperty(windowPropKeys));

When that is done, the cool part happens: We loop through the ‘filteredPropKeys’ array, check the type of the property against Window, and then add it to a corresponding property type on our customProperty object.

// now loop through the keys and make one big object containing all the custom properties
filteredPropKeys.forEach(key => {
	const customPropKey = win[key];
	const type = typeof customPropKey;
	
	if (type === "object") {
		// arrays are objects, too... so a special test is required
		if (Array.isArray(customPropKey)) customProperties.array[key] = customPropKey;
		else customProperties.object[key] = customPropKey;
	} else {
		// make a property for the remaining types
		if (customProperties[`${type}`] === undefined) customProperties[`${type}`] = {};
		customProperties[`${type}`][key] = customPropKey;
	}
});

Finally, we log out the result with some added extra’s, the total number of Window globals, the total number of user defined globals, and the user defined globals themselves.

// write the result to the console.
con.log({
	numWindowProps: allWindowPropKeys.length,
	numCustomProps: filteredPropKeys.length,
	customProperties
});

On this website, this will log out something like you see below. Pretty nice, right?

Here they are, all your user defined globals, nicely divided by type, in a clear overview!

Finally, to keep things clean, we remove the iFrame we just created. And that’s all there is to it!

// clean up
iframe.remove();

Happy coding 😘

Filed Under: Geen categorie

Footer

Office

recoveryArea
Nijverheidstraat 11-1
7511 JM Enschede

KvK: 65594940

Goals

Let's make a more elegant, easy to use internet, accessible for everyone. Let's move forward to an empathic, secular, sustainable future, enabled through science and technology.

Read my full profile

Get in touch

  • GitHub
  • LinkedIn
  • Twitter

Copyright © 2025 · From recoveryArea with