npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

resource-injector

v1.5.0

Published

The ResourceInjector class dynamically loads JavaScript and CSS into the webpage, ensuring each resource is loaded only once, with error handling and optional load timeouts.

Downloads

9

Readme

npm GitHub package version NPM Downloads

0.7kB gzipped

Install

$ yarn add resource-injector
# or
$ npm i resource-injector

Import

import ResourceInjector from 'resource-injector';

Quick Start

const injector = new ResourceInjector();

// 1. Load a JavaScript file into <head> (automatically deferred)
await injector.loadResource({
  url: 'https://cdn.example.com/analytics.js',
  type: 'script',
  injectTo: 'head', // <‑‑ new!
});

// 2. Load a CSS file
await injector.loadResource({
  url: 'https://cdn.example.com/theme.css',
  type: 'style',
  appendTimestamp: true, // <‑‑ bust browser cache when needed
});

API

injector.loadResource(config): Promise<void>

| Option (required bold) | Type | Default | Description | |:----------------------------------|:---------------------------------------------------------|:------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | url | string | — | Absolute or relative path to the resource. | | type | 'script' \| 'style' | — | Resource kind. | | options | Partial<HTMLScriptElement> \| Partial<HTMLLinkElement> | {} | Any valid attributes for the underlying element e.g. async, defer, id, type="module" … | | timeout | number | 10000 | Milliseconds to wait before the Promise rejects. | | forceReload | boolean | false | Remove the existing element (if any) and fetch again. | | appendTimestamp | boolean | false | Adds ?t={Date.now()} to the network URL for easy cache‑busting.For internal caching the original URL (without query) is still used, so repeated calls with different timestamps are treated as one resource. | | injectTo script‑only | 'head' \| 'body' | 'body' | Where to insert the <script> tag.'head' starts download earlier; 'body' preserves historical behaviour. | | container | HTMLElement | undefined | Explicit parent element; overrides injectTo. |

Automatic defer
When injectTo: 'head' and you did not supply async/defer, the injector sets defer=true so scripts do not block parsing and execute after DOMContentLoaded.

Return value

Promise<void> – resolved on load, rejected on error or timeout.

Examples

Cache‑bust & reload

await injector.loadResource({
  url: '/build/app.js',
  type: 'script',
  appendTimestamp: true,
  forceReload: true,
});

Inject into a custom container

const shadowRoot = document.getElementById('widget')!.shadowRoot!;
await injector.loadResource({
  url: 'https://cdn.example.com/widget.js',
  type: 'script',
  container: shadowRoot, // overrides injectTo
});

Parallel loading

await Promise.all([
  injector.loadResource({ url: '/a.js', type: 'script' }),
  injector.loadResource({ url: '/b.css', type: 'style' }),
]);
console.log('Everything ready');

Advanced behaviour

  • Single‑flight cache – Internally a Map stores Promises keyed by the base URL (query string stripped).
    Two calls for the same file will share one network request.
  • Timeout Guard – Individual loadResource calls can specify their own timeout (defaults to 10 s).
  • Force Reload – Set forceReload to true to delete any previously injected node and restart download.

License

MIT