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 🙏

© 2024 – Pkg Stats / Ryan Hefner

requirees

v1.0.23

Published

Simple AMD module loader with version support

Downloads

926

Readme

codecov

Require-es

A microfrontend module loader Installation Migration from RequireJs Register a package Require a package Override amd dependencies Require.when - ONLY load after explicit define/register Define a package RequireEs options RequireEs events WebPack / Rollup bundling for RequireEs Custom elements support

A microfrontend module loader

Require-es will:

  • allow micro-frontends to share dependencies
  • help finding compatible package-versions

The project will be structured in 3 parts:

  • provide a module loader which:
    • loads amd modules
    • loads multiple filetypes: js / json / xml / txt / html / css / wasm
    • registers multiple versions of a single package
    • can set default-versions
    • easily migrates from RequireJs
    • emits events to allow usage monitoring
  • create a require-es-server, where:
    • packages can be registered
    • usage of package-version can be tracked
    • module loading can become predictable
    • predictive http2-pushes are possible
  • create a webpack/rollup loader

Installation

Add the package to your project

npm install requirees --save

Serve the file in node_modules/requirees/build/requirees.js in the header of your webpage (9Kb Gzipped)

<!DOCTYPE html>
<html>
    <head>
        <title>Pagetitle</title>
        <script src="scripts/requirees.js"></script>
    </head>
    <body></body>
</html>

Migration from RequireJs

RequireEs allows a soft transition from RequireJs. This means that most syntax of RequireJs, is also supported in RequireEs:

  • define(packageName, [dependencies], factory);
  • define([dependencies], factory);
  • require(['packageName'], packageInstance => {});
  • requirejs(['packageName'], packageInstance => {});
  • require('packageName');
  • requirejs.config({paths});

In a later version, require.config({shim}) will be supported as well.

More info on RequireJs: https://requirejs.org/

Register a package

Usage

require.register({
    packageName1(@)(version)(.filetype)(-default): [
        url(.filetype),
        url(.filetype),
        url(.filetype),
        ...
    ],
    packageName2(@)(version)(.filetype)(-default): {
        versions, 
        url, 
        urls
    }
});

Key | Description --- | --- PackageName | the name of the package Version | the version-number in string format: major.minor(.patch)(.build)(-releaseCandidate) Filetype | the file-extension - js/css/txt/xml/json/html/wasm/tag Default | indicates the default version Versions | array of versions to fill out in the URL (use placeholder ${version} in the url-string) Url | single url string Urls | multiple urls for 1 package

Note - Determining the version number, happens in this order:

  • Is a 'versions' attribute present in the package-value
  • Is '@version' present in the package-name
  • Is a version present in the url (cdnjs.com/17.0.2/package.js)

Samples

//register react, version '17.0.2'
require.register({
    react: 'https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js'
});

//register react, versions '0.14.9', '15.6.2', '15.7.0', '16.14.0' (set as default), '17.0.2'
require.register({
    react: {
        versions: ['0.14.9', '15.6.2', '15.7.0'],
        url: 'https://cdnjs.cloudflare.com/ajax/libs/react/${version}/react.min.js'
    },
    '[email protected]': 'https://cdnjs.cloudflare.com/ajax/libs/react/16.14.0/umd/react.production.min.js',
    '[email protected]': 'https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js'
});

//register react, versions '15.7.0', '16.14.0', '17.0.2'
require.register({
    react: [
        'https://cdnjs.cloudflare.com/ajax/libs/react/15.7.0/react.min.js',
        'https://cdnjs.cloudflare.com/ajax/libs/react/16.14.0/umd/react.production.min.js',
        'https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js',
    ]
});

//register bootstrap, both css and js
require.register({
    bootstrap: [
        "https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js",
        "https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.css",
        "https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.0/js/bootstrap.bundle.min.js",
        "https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.0/css/bootstrap.min.css"
    ]
});

Require a package

Usage

//async await
const packageInstance = await require('packageName(@)(^)(~)(*)(version)(.filetype)');
//mulitple packages
const [pckg1, packg2] = await require([
    'pckg1(@)(^)(~)(*)(version)(.filetype)',
    'pckg2(@)(^)(~)(*)(version)(.filetype)'
]);

//cjs style (only works when a package is already loaded once, or in a defined factory)
const packageInstance = require('packageName(@)(^)(~)(*)(version)(.filetype)');

//using promises
requirees('packageName(@)(^)(~)(*)(version)(.filetype)').then(packageInstance);
//multiple packages
requirees([
    'pckg1(@)(^)(~)(*)(version)(.filetype)',
    'pckg2(@)(^)(~)(*)(version)(.filetype)'
]).then(
    ([pckg1, pckg2]) => {}
 );

//using callbacks
require(['packageName(@)(^)(~)(*)(version)(.filetype)'], package => {});
//multiple packages
require([
    'pckg1(@)(^)(~)(*)(version)(.filetype)',
    'pckg2(@)(^)(~)(*)(version)(.filetype)'
], (pckg1, pckg2) => {});

//without registration
await require(url);

Key | Description --- | --- PackageName | the name of the package Version | the version-number in string format: major.minor(.patch)(.build)(-releaseCandidate) Filetype | the file-extension - js/css/txt/xml/json/html/wasm/tag; if no filetype is specified ALL filetypes will be loaded

  • | load highest version ^ | load highest minor-version ~ | load highest patch-version

Note - Determining the version number happens in this order

  • Find best version match, if any versionnumber is specified
  • Find the default, if no versionnumber is specified
  • Take the highest version number if no default, nor versionnumber are specified

Note - If no filetype is specified all registered filetypes will be loaded

Samples

//register bootstrap
require.register({
    bootstrap: [
        "https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js",
        "https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.css",
        "https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.0/js/bootstrap.bundle.min.js",
        "https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.0/css/bootstrap.min.css"
    ]
})

//load both css & js from the highest available version (4.6.0)
//4.6.0 will be the default (no default is set)
const bootstrap = await require('bootstrap');
//4.6.0 is the highest registered version
const bootstrap = await require('bootstrap@*');

//load only the css tag from version 3.4.1
const bootstrapCssTag = await require('[email protected]'); //fixed version number

//load only the js tag from version 3.x
const bootstrapJs = await require('bootstrap.js@^3.0.0'); //find highest minor

//try to load bootstrap 3.4.2
const bootstrap = await require('[email protected]');
//will result in a console.warn("package not found");
//version 3.4.2 was not registered using define(), require.register, nor require.config({paths})

//download without registration
const bootstrap = await require('https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.0/js/bootstrap.bundle.min.js')

Override amd dependencies

Require-es provides more flexibility on loading multiple versions of a given package. Unfortunately some amd/umd-packages include predefined dependencies. These can lead to unwanted / unexpected behavior.

###Example: react-dom + react Let's take a look at the conflict below: react 16 + react 18

require.register({
    'react': [
        'https://cdnjs.cloudflare.com/ajax/libs/react/16.14.0/umd/react.production.min.js',
        'https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.0.0/umd/react-dom.production.min.js'
    ],
    'react-dom': [
        'https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.14.0/umd/react-dom.production.min.js',
        'https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.0.0/umd/react-dom.production.min.js'
    ]
});
const ReactDom = await require('react-dom@^16.0.0');
//react-dom     version 16.14.0 will download/initialize (it's the highest match within major 16)
//react         version 18.0.0 will download/initialize...
//this happens because react-dom has a dependency on 'react' baked into the module itself: define(['react'], factoryReactDom(React){})
//see code-snippet below

Why did react 18.0.0 initialize, when react-dom 16.x is required? The answer can be found in the react-dom source-code itself: https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.14.0/umd/react-dom.production.min.js

...nction"===typeof define&&define.amd?define(["exports","react"],ea):(I=I||self,ea(I.ReactDOM={},...

Pay close attention to the dependencies set by the react-dom definition: define(["exports","react"]). This instructs require-es to load "react" (without version number specified) before the "react-dom" factory runs. If no "react" version is specified, the default version will be loaded (if no default is specified, the highest version becomes the default)

Fix hardcoded amd-dependencies

To avoid mixing up versions, require-es allows dependency overrides.

This is done by providing the dependencyOverrides object while registering an amd module.

Syntax

require.register({
  packageName: {
    url: 'urlToDownloadTheAmdModule',
    dependencyOverrides: {
          dependencyName: 'newDependencyName(@version)'
    }
  }
})

Example:

require.register({
    'react-dom': [
        {
            url: 'https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.0.0/umd/react-dom.production.min.js',
            dependencyOverrides: { react: '[email protected]' }
        },
        {
            url: 'https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.14.0/umd/react-dom.production.min.js',
            dependencyOverrides: { react: '[email protected]' }
        }
    ],
    'react': [
        'https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.0.0/umd/react-dom.production.min.js',
        'https://cdnjs.cloudflare.com/ajax/libs/react/16.14.0/umd/react.production.min.js'
    ]
});

This will override any hardcoded dependency on "react" to "[email protected]" (or "[email protected]") in both react-dom packages. The react-dom factory will now receive a matching react-version.

Looking back at the react-dom source code:

https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.14.0/umd/react-dom.production.min.js

...nction"===typeof define&&define.amd?define(["exports","react"],ea):(I=I||self,ea(I.ReactDOM={},...
//will become
...nction"===typeof define&&define.amd?define(["exports","[email protected]"],ea):(I=I||self,ea(I.ReactDOM={},...

https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.0.0/umd/react-dom.production.min.js

...nction"===typeof define&&define.amd?define(["exports","react"],eb):(M=M||self,eb(M.ReactDOM={},...
//will become
...nction"===typeof define&&define.amd?define(["exports","[email protected]"],eb):(M=M||self,eb(M.ReactDOM={},...

Require.when() - only return explicitly defined/registered packages

By default requirees will always try to download a package, even when no registration/definition is available.

Example

require('myUnkownPackage')
//tries to download './myUnkownPackage.js'. 

Require.when() ensures the requested package are explicitly defined/registered! If the requested package is not defined/registered yet, require.when will wait for an explicit define/register.

Usage

//wait for a single package to get defined/registered
require.when('packageName(@)(^)(~)(*)(version)(.filetype)').then(packageInstance => {});
//wait for multiple packages to get defined/registered
require.when([
  'pckg1(@)(^)(~)(*)(version)(.filetype)',
  'pckg2(@)(^)(~)(*)(version)(.filetype)'
]).then((pckg1, pckg2) => {});
//using callbacks instead of promises
require.when('packageName(@)(^)(~)(*)(version)(.filetype)', callback, failCallback)

Samples

require.when('myUnkownPackage')
        .then(p => console.log('my unknown package is defined now', p))
//waits until someone explicitly defines the package
//the promise above will resolve with the 'myUnknownPackage'-exports after 5 seconds
setTimeout(
    () => define('myUnkownPackage', () => exports),
    5000
);
require.when('three@^0.100.0')
        .then(three => console.log('three is registered and usable now', three))
//waits until someone explicitly registers the package
//
setTimeout(
    () => require.register({
        three: "https://cdnjs.cloudflare.com/ajax/libs/three.js/0.148.0/three.min.js"
    }),
    5000
);

Define a package

Usage (follows AMD-pattern)

//named define
define(packageName(@)(version)(.filetype)(-default), [dependencies], factory);
//anonymous define
define([dependencies], factory);

Key | Description --- | --- PackageName | the name of the package Version | the version-number in string format: major.minor(.patch)(.build)(-releaseCandidate) Filetype | the file extension - js/css/txt/xml/json/html/wasm/tag Default | indicates the default version Dependencies | package names (or urls) on which this package is dependent Factory | function / json / text / HTMLElement / xml / ...

Note - The dependency naming rules are equal to the require naming rules: packageName(@)(^)(~)(*)(version)(.filetype)

Note - The datatype of the factory can be different, depending on the filetype:

  • js: function
  • json: json-text (gets converted to JSON) / json-object
  • css: css-text (gets converted to a script-tag)
  • txt: text
  • xml: text
  • html: html-text (gets converted to an HTMLElement) / HTMLElement-object

Samples

//define an amd module
define('hello.js', ['react@^16.0.0'], (react) => {
   function fn1(){}
   return {fn1} 
});

//define a CJS module
define('hello.js', [], () => {
    const react = require('react');
    function fn1(){}
    module.exports = {fn1};
});

//define a json object
define('hello.json', [], '{"foo": "bar"}');

//define css
define('hello.css', [], 'body{background-color: red}');

//define a specific version of hello.css
define('[email protected]', [], 'body{background-color: red}');

//define an html fragment
//gets converted to an HTMLElement when required + will automatically add the CSS to the page
define('hello.html', ['hello.css@^1.0.0'], '<div>bla</div>');
//alternative
define('hello.html', [], document.createElement('div'));

//define r.js style
define('react', reactFactoryFn);
//using version number
define('[email protected]', react1702FactoryFn);

RequireEs options

require.config({
    allowRedefine: false,
    invokeNonMatchedDefines: true
});

Key | Description --- | --- allowRedefine | default: false;false: you cannot change the factory, for a given package (after it gets required for the first time)true: the factory can be changed at any time, next require will use the new factory invokeNonMatchedDefines | default: false; automatically invoke anonymous defines which could not be matched to any package in the RequireEs register.

RequireEs events

Usage

//subscribe to an event
require.on(evtName, callback);
//require.subscribe is a synonym for require.on
require.subscribe(evtName, callback);

//publish an event
require.publish(evtName, payload);

//spy on all events
require.addWireTap(callback);

Predefined events

Event | Trigger --- | --- requirees.pre-define | when define gets called, but the factory is not stored into the registry yet requirees.define | when a package factory was added to the registry requirees.pre-register | when require.register or require.config({paths}) are called, but the package it not added to the registry yet requirees.register | when a package was added to the registry requirees.pre-file-load | before an actual file/factory load is happening requirees.file-load | when a file/factory load has completed requirees.wiretaps | on all events requirees.scripttag.preadd | triggers before requirees appends a script-tag to the dom requirees.scripttag.added | tiggers after requirees appended a script-tag to the dom requirees.styletag.preadd | triggers before requirees appends a script-tag to the dom requirees.styletag.added | tiggers after requirees appended a style-tag to the dom

Samples

//listen to all files being loaded
requirees.subscribe('requirees.pre-file-load', ({package}) => {
    console.log(`start loading package: ${package.name}`);
})

//listen to all events being triggered
requirees.addWireTap(console.log);
//alternative:
requirees.subscribe('requirees.wiretaps', console.log);

//create custom events
requirees.subscribe('hendrik.sayHello', data => {
    console.log('hello!!', data)
});
requirees.publish('hendrik.sayHello', {foo: 'bar'});

WebPack / Rollup bundling for RequireEs

Intro

In the examples below project-dependencies 'jquery', 'react' and 'lodash' will be removed from your bundle and loaded using RequireEs.

To make this happen:

  • Add RequireEs to the top of your HTML-document
  • Register your dependencies on the document (This will happen automatically using RequireEs-server, coming soon)
  • Load your AMD (/UMD) bundle through RequireEs (recommended), or using a script-tag

Samples for Webpack and Rollup bundling can be found in the sections below.

//require the AMD module
require.register({
    jquery: 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js',
    react: [
        'https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js',
        'https://cdnjs.cloudflare.com/ajax/libs/react/16.14.0/umd/react.production.min.js',
        'https://cdnjs.cloudflare.com/ajax/libs/react/16.10.1/umd/react.production.min.js'
    ],
    lodash: [
        'https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js',
        'https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.min.js'
    ]
});

//require the application package
await require('/scripts/myLib.amd.js');

If your package is added through a script-tag, call require.config({invokeNonMatchedDefines: true}) to invoke the factory immediately:

<script>
    requirees.config({
        invokeNonMatchedDefines: true
    })
</script>
<script src="/scripts/myLib.amd.js"></script>

Build your bundle AMD style

Webpack

module.exports = {
    //...
    output: {
        libraryTarget: 'amd',
        filename: 'scripts/myLib.amd.js'
    },
    //...
    externals: {
      jquery: 'jquery@*',
      react: 'react@^17.0.0',
      lodash: 'lodash@^4.17.0'
    },
};

Rollup

export default {
    //...
    output: {
        format: 'amd',
        file: 'scripts/myLib.amd.js',
        external: ['react', 'jquery', 'lodash'],
        paths: {
            react: 'react@^17.0.0',
            jquery: 'jquery@*',
            lodash: 'lodash@^4.17.0'
        }
    },
    //...
};

Build your bundle UMD style

Webpack

module.exports = {
    //...
    output: {
        libraryTarget: 'umd',
        filename: 'scripts/myLib.amd.js',
        library: 'myLib'
    },
    //...
    externals: {
      jquery: {
          root: '$',
          amd: 'jquery@*',
          commonjs: 'jquery',
          commonjs2: 'jquery'
      },
      react: {
          root: 'React',
          amd: 'react@^17.0.0',
          commonjs: 'react',
          commonjs2: 'react'
      },
      lodash: {
          root: '_',
          amd: 'lodash@^4.17.0',
          commonjs: 'lodash',
          commonjs2: 'lodash'
      }
    },
};

Rollup

export default {
    //...
    output: {
        format: 'umd',
        file: 'scripts/myLib.amd.js',
        name: 'myLib',
        external: ['react', 'jquery', 'lodash'],
        paths: {
            react: 'react@^17.0.0',
            jquery: 'jquery@*',
            lodash: 'lodash@^4.17.0'
        },
        globals: {
            react: 'React',
            jquery: '$',
            lodash: '_'
        }
    },
    //...
};

Custom elements support (coming soon)