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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@webhandle/external-resource-manager

v1.0.3

Published

Coordinates which external resources like scripts and css get put on a page.

Readme

@webhandle/external-resource-manager

Coordinates which external resources like scripts and css get put on a page.

Install

npm install @webhandle/external-resource-manager

Purpose

Integrating components written by different people at different times is messy.

One approach is the one Wordpress uses: every component includes its own css files and scripts and there's a dependency system to make sure dependencies get loaded and get loaded before the dependents. This is kinda complicated and results in every page having a million little files that the browser has to fetch.

Another approach is to use Webpack or Browserify to compile all the small files into one larger file, and just have the page load that. This also works, but now the complication is that you have to figure out all of the files to be compiled and if a compoment adds a file, now the page is broken.

External Resource Manager represents a third approach, allowing the component flexibility to include what it wants and the ability to combine files for performance.

Usage

The two main setup functions are:

externalResourceManager.includeResource({
	mimeType: type
	, url: url
})

and

externalResourceManager.provideResource({
	mimeType: type
	, url: url
	, name: name
	, resourceType: subType
})

includeResource is a directive to include a resource in the page. It will result in a link element or script element or whatever is appropriate for its type.

provideResource lets components state that a resource is available for use, if somebody wants to use it. It does not necessarily result in anything getting loaded by the browser.

Components all given a chance to call these function with middleware that they add to the express routers.

Later, when html for the page is being created, externalResourceManager.render() can be called, which creates html to include the resource. It's safe to call render multiple times because subsequent calls will only create html for resources added since the last call to render. This means templates themselves can include resesources on the page, so long as those resources can tolerate being included in the body.

To specify the additional attributes that are sometimes used with elements, you can call like:

externalResourceManager.includeResource({
	mimeType: 'application/javascript'
	, url: '/js/pages.mjs'
	, attributes: {
		defer: undefined
	}
	, cachable: false
})

Any attribute with a null or undefined value will/should be rendered to the page as an attribute without a value like:

<script src="/js/pages.mjs" defer ></script>

As you can see in the example above, resources may also have a cachable attribute, which is true by default. Whether or not this resource ever actually has cache headers or version url parameters applied to it depends on the renderers being used. The attribute just signifies this resource is eligible to be used with whatever caching mechanism the site is using and isn't some sort of url which resolves to dynamic code and only looks like a file URL.

How does this help with dependencies?

ExternalResourceManager guarantees that it will not include a url twice, so any component is free to explicitly add a resource or call a function from the dependency which adds a resource without fear that it will be included multiple times. Resources are rendered in the order added, so as long as a component includes its dependencies first, everything should work out. This avoids having named resources and a dependency tree at the small cost of having code which should understand its dependencies call a function on them.

Further, ExternalResourceManager makes use of javascript modules and importmap scripts. This allows a component to provide functionality to the page which will get loaded ONLY if it's needed. To provide a module to a page, we call like:

externalResourceManager.provideResource({
	url: '/js/one.js'
	, mimeType: 'application/javascript'
	, resourceType: 'module'
	, name: '@webhandle/moduleone'
})

This will produce an entry in an importmap so that any javascript which makes a call like:

import myImportantFunction from "@webhandle/moduleone"

will cause the browser to load the module from the server. In this way you can add substantial libraries of modules to the page with a performance hit since they're only loaded at need. Additionally, because the importmap is parsed by the browser before any of the modules are actually loaded, it doesn't matter what order the modules are added via provideResource.

A note: at the time of this writing, Firefox does not support multiple importmaps, so if possible, components which provide resources should try to do so before rendering starts. Since providing a resource does not result in any extra requests to the server, this should be safe to do in middle for any request which might even potentially make use of the component.

How does this get rid of the million requests problem?

Inlcuded resources are able to say that they "satisfy" other included URLs. For instance, let's say individual components have included css files that they need.

externalResourceManager.includeResource({
	mimeType: 'text/css'
	, url: '/small/package/level.css'
})

externalResourceManager.includeResource({
	mimeType: 'text/css'
	, url: '/small/package/level-too.css'
})

We can at any time, either before those components include their resources or after, have code like the following:

externalResourceManager.includeResource({
	mimeType: 'text/css'
	, url: '/css/compiled.css'
	, satisfies: [
		'/small/package/level.css'
		, '/small/package/level-too.css'
	]
})

This will cause /css/compiled.css to get included on the page while /small/package/level.css and /small/package/level-too.css will not.

This is "satisfies" instead of "contains" because /css/compiled.css may not actually have the code from level.css in it at all. However, it claims to be functionally equivalent. This lets us replace styles we don't like with styles we do like, as well as just bundling thing up for performance reasons.

This works so long as all these call are made before render is called.

In this way, we can get the best of both worlds for very little cost. We can add a new component to the site and just have it work. After adding too many new components, we can set up builds to combine those small files and just have those loaded (and not even have to worry about trying to tell the component not to load its resources). And when we add a new component, no problem, this small dependencies will get added to the page until we include them in the build.

Usage in Webhandle

In Webhandle, every response has its own ExternalResourceManager at res.locals.externalResourceManager

That's kind of a weird place to put it, I know, but this allows any template to include a resource and allows any template to call render.

Resource Type Support

Currently there's code to include mime types application/javascript and text/css. There's also code to create an importmap based on mime type application/javascript with resource type module. ExternalResourceManager works internally by having code registered to handle different mime types, so extensability is really easy if you wanted to add meta element or title element handling (or something).

Data URLs

It's also possible to pass data as part of the provided resource. This is good if you need a configuration for the javascript on the page. Be careful with this though because it can result in some really big pages.

externalResourceManager.provideResource({
	mimeType: 'application/javascript'
	, resourceType: 'module'
	, name: '@webhandle/moduleone/configuration'
	, data: {url: '/something/here'}
})

It results in an importmap entry like:

"@webhandle/module-one/configuration":"data:text/javascript,export default {\"url\":\"/something/here\"}"

Integration

As you'd expect, this can be integrated into webhandle by calling:

import setup from "@webhandle/external-resource-manager/initialize-webhandle-component.mjs"
await setup(myWebhandleInstance, options)