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>

Related

Tools