MonkeyLoader All articles
Infrastructure

The Wrapper, the Pin and the Kill Switch: Extending Vendor Loaders You Cannot Fork

MonkeyLoader
The Wrapper, the Pin and the Kill Switch: Extending Vendor Loaders You Cannot Fork

Photo: w_lemay, CC BY-SA 2.0, via Wikimedia Commons

A vendor sends you a snippet. It is 40 lines, minified, and it loads three other scripts you did not ask for. The support contract says you cannot fork it. The account manager says the next release will fix everything. The next release is in Q1.

This is the situation where monkey-patching gets a bad name. Done badly, it is a stack of private-method overrides held together by hope. Done well, it is a wrapper with a contract: a small piece of your code that sits between your page and the vendor, controls how the vendor loads, and gives you a way out when the vendor disappears. That is the version worth building.

Forking is a photocopy of someone else's problem

A fork feels satisfying for about a week. You own the code, you can change the code, and you can ship the fix. Then the vendor releases a security patch, or a browser changes something, or the vendor's API moves, and you are maintaining a parallel version of a product you do not control. For a two-person UK team, that is how weekends disappear.

A wrapper is different. You are not copying the vendor; you are bounding it. The vendor still owns its internals. You own the loading contract: when it loads, what config it receives, what happens when it fails, and how you turn it off. That is a much smaller surface to defend.

Proxy loaders: the least-worst option

A proxy loader is a small module that loads the vendor script and exposes a controlled interface to your app. It can rewrite config, add locale defaults, lazy-load the vendor only on the pages that need it, and enforce timeouts. It can also normalise errors so your monitoring does not drown in vendor-specific noise.

The trick is to wrap the public surface, not the private one. If the vendor exposes window.Vendor.init, wrap init. Do not reach into window.Vendor._internalThing unless you enjoy rebuilding the wrapper every minor release. If the public surface is not enough, ask the vendor for an API. If they will not give you one, treat that as a procurement signal.

A proxy loader also gives you a place to put UK-specific defaults: en-GB locale, VAT display rules, and consent gating. That is valuable, because it keeps those concerns out of a dozen page templates.

Feature detection beats version sniffing

Do not parse the user agent. Do not infer capability from a version string. Check for the function you actually need. If window.Vendor.init is a function, wrap it. If it is not, load your fallback and move on. That sounds obvious, but plenty of loader code still assumes that a vendor version means a feature exists.

Feature detection is also how you survive vendor auto-updates. If the vendor ships a new build overnight, your wrapper should either keep working or fail closed in a way you can see. The worst outcome is a silent half-load where the page looks fine but the basket integration is dead.

Pin versions, but not forever

Version pinning is a seatbelt, not a strategy. Pin the exact build you have tested, record it in your repo, and know how to move it. If the vendor lets you pin by URL, do that. If they push updates automatically, use subresource integrity where you can, and keep a canary page that exercises the integration.

A pin without a review date is just a slow-motion fork. Put a monthly reminder in the calendar: check the vendor changelog, run the canary, and decide whether to move the pin. In the UK supplier context, ask for deprecation notices in writing. A vendor that cannot tell you when an endpoint is changing is a vendor that will eventually change it on a Friday.

Kill switches and circuit breakers

Every wrapper needs a kill switch that a non-developer can flip. That might be a feature flag, a query parameter, or a config file on your own origin. The point is that when the vendor has a bad day, you do not need a deploy to stop the bleeding.

A circuit breaker is the automatic version. If the vendor fails three times in 60 seconds, stop calling it for ten minutes. Show the page without it. Log the failure. Let the on-call person decide whether to flip the manual switch. This is not over-engineering; it is the difference between a degraded page and a page that hangs on a third-party timeout.

The UK supplier accountability bit

UK teams often buy through a reseller, a framework, or a procurement process that makes the actual vendor feel very far away. That is exactly why the wrapper matters. It is your technical exit strategy.

Before you sign, ask three questions. Can we export our data? Can we host the script ourselves or pin it? What happens to the integration if the vendor is acquired or disappears? If the answers are vague, put them in the contract. A wrapper will not save you from a bad commercial deal, but it will buy you time.

Keep a local mock of the vendor in your test suite. Write down the removal path: which pages load it, which config keys matter, and what the fallback looks like. If the vendor disappears on a Tuesday, you should be able to ship a one-line change that turns the wrapper into a no-op.

A minimal wrapper pattern

Here is the shape I would start with. It is deliberately small.

const vendorLoader = {
  init(config) {
    if (!window.Vendor || typeof window.Vendor.init !== 'function') {
      return fallbackInit(config);
    }
    return window.Vendor.init({ ...config, locale: 'en-GB' });
  }
};

Then add the boring bits around it: a timeout, a circuit breaker, a kill switch, and a log line that tells you which vendor build actually loaded. That is the whole trick. You are not trying to outsmart the vendor. You are trying to make the vendor's behaviour legible, bounded and reversible.

Monkey-patching has a reputation problem because people use it to avoid conversations. The good version is the opposite: it is a conversation made concrete. It says we will use your loader, but on our terms, and we will keep a way out.

All Articles

Related Articles

The Long Weekend Release Drill: Ship on Friday, Sleep on Monday

The Long Weekend Release Drill: Ship on Friday, Sleep on Monday

Forty Lines and a Promise: Swapping a Tag Manager for a Consent-Aware Script Loader

Forty Lines and a Promise: Swapping a Tag Manager for a Consent-Aware Script Loader

Roll Your Own Feature Flags: A Two-Person Team's Case for Ditching the Flag SaaS

Roll Your Own Feature Flags: A Two-Person Team's Case for Ditching the Flag SaaS