Vanilla JS ~17 KB Zero Dependencies MIT License

ResourceLoader.js

A lightweight library for dynamically loading any web resource through one unified Promise-based API — scripts, stylesheets, JSON, fonts, images, audio, video, and binary files.

The Problem

Loading resources programmatically in the browser is surprisingly messy. The platform gives you several different mechanisms depending on resource type — each with its own quirks around load events, error handling, and caching:

// A script
const s = document.createElement('script');
s.src = url; s.onload = resolve; s.onerror = reject;
document.head.appendChild(s);

// A stylesheet
const l = document.createElement('link');
l.rel = 'stylesheet'; l.href = url;
document.head.appendChild(l);

// JSON data
const data = await fetch(url).then(r => r.json());

// A font
const font = new FontFace('MyFont', `url(${url})`);
await font.load();
document.fonts.add(font);

Then add retries, timeouts, deduplication, and concurrency limits. You're writing the same boilerplate on every project. ResourceLoader.js solves all of it with one call:

await ResourceLoader.include([
  'https://example.com/app.css',
  'https://example.com/app.js',
  'https://api.example.com/config.json',
]);
// All three loaded. Start your app.

Retries & Timeouts

Transient failures are handled automatically. Configure retries, delay between attempts, and a per-attempt timeout — each retry gets its own fresh clock.

ResourceLoader.include([url], {
  retries: 3,
  retryDelay: 2000,
  timeout: 5000,
});

Concurrency & Priority

Limit simultaneous loads to avoid saturating the browser's connection pool. When queue slots are limited, higher-priority resources load first.

// Critical font loads first
ResourceLoader.include([font], { priority: 10 });
ResourceLoader.include([img], {
  priority: 1,
  maxConcurrency: 4,
});

State & Deduplication

An internal registry tracks every URL. Requesting something already loaded or loading returns the existing Promise — no duplicate network requests, ever.

ResourceLoader.getResourceState('app.js');
// → 'loading' | 'loaded' | 'unloaded'

Structured Errors

Every failure surfaces as a typed error object so you always know exactly what went wrong and why — not an opaque DOM event or a raw network rejection.

try {
  await ResourceLoader.include([urls]);
} catch (err) {
  // err.type: 'network' | 'timeout'
  //          | 'abort' | 'unsupported'
  // err.results — per-URL breakdown
}

Universal Resource Support

Extension detection picks the right loading mechanism automatically. No configuration needed.

Category Extensions Loaded via
Scripts .js <script> element
Stylesheets .css <link> element
JSON data .json fetch() + response.json()
Images .jpg .png .gif .svg .webp <img> element
Fonts .woff .woff2 FontFace API
Audio .mp3 .ogg .wav fetch() + response.blob()
Video .mp4 .avi .webm fetch() + response.blob()
Binary / PDF .pdf .zip .bin fetch() + response.blob()

API Reference

The entire public API. After inclusion, everything lives on window.ResourceLoader.

Method Description
include(urls, opts?) Load one or more resources. Returns a Promise that resolves when all succeed or rejects with a structured aggregate error.
getResourceState(url) Returns 'loading', 'loaded', or 'unloaded'.
cancelResource(url) Abort an in-flight load.
cancelAll() Abort all pending loads at once.
unloadResource(url) Remove a loaded resource from the DOM and clear it from the state registry.
setLoggingLevel(level) Set global log verbosity: 'silent', 'warn', or 'verbose'.

Options

Pass an options object as the second argument to include().

Option Default Description
retries 0 Number of additional attempts after a network or timeout failure.
retryDelay 0 Milliseconds to wait between retry attempts.
timeout 0 Per-attempt timeout in ms. 0 means no limit.
maxConcurrency 3 Maximum simultaneous loads.
priority 0 Queue priority — higher numbers load first when slots are limited.
cacheBusting false Append a timestamp query string to prevent stale cache hits.
cacheBustingTypes ['js','css'] Which extensions to apply cache-busting to.
restrictCacheBustingToLocal true Only bust same-origin URLs.
onSuccess Callback fired for each successful load: (data, url) => void.
onError Callback fired for each failure: (error, url) => void.
logLevel 'warn' 'silent', 'warn', or 'verbose'.

Installation

No bundler required. Pick the delivery method that fits your workflow.

CDN — pinned version (recommended for production)

<script src="https://cdn.jsdelivr.net/npm/resourceloader-js@1.0.2/resourceLoader.js"></script>

CDN — always latest

<script src="https://cdn.jsdelivr.net/npm/resourceloader-js/resourceLoader.js"></script>
<script src="https://unpkg.com/resourceloader-js/resourceLoader.js"></script>

npm

npm install resourceloader-js
// CommonJS
const ResourceLoader = require('resourceloader-js');

// ESM
import ResourceLoader from 'resourceloader-js';

After inclusion the library is available as window.ResourceLoader in browser environments. It is not designed for server-side use — it targets browser APIs (document, FontFace, fetch, DOM elements).

Full Example

Everything running together — parallel loads, retries, callbacks, and error handling.

<!DOCTYPE html>
<html>
<head>
  <script src="https://cdn.jsdelivr.net/npm/resourceloader-js/resourceLoader.js"></script>
</head>
<body>
  <script>
    ResourceLoader.include([
      'https://cdn.example.com/theme.css',
      'https://cdn.example.com/vendor.js',
      'https://api.example.com/config.json',
    ], {
      retries: 2,
      timeout: 8000,
      logLevel: 'verbose',
      onSuccess: (data, url) => console.log('Ready:', url),
      onError: (err, url) => console.warn('Failed:', url, err.message),
    })
    .then(() => {
      initApp(); // all resources ready
    })
    .catch((err) => {
      console.error('Load failed:', err);
    });
  </script>
</body>
</html>