Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

requirees

Package Overview
Dependencies
Maintainers
1
Versions
23
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

requirees

Simple AMD module loader with version support

  • 1.0.21
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
315
increased by1.61%
Maintainers
1
Weekly downloads
 
Created
Source

codecov

Require-es

A microfrontend module loader
Installation
Migration from RequireJs
Register a package
Require a package
Override amd dependencies
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
    }
});
KeyDescription
PackageNamethe name of the package
Versionthe version-number in string format: major.minor(.patch)(.build)(-releaseCandidate)
Filetypethe file-extension - js/css/txt/xml/json/html/wasm/tag
Defaultindicates the default version
Versionsarray of versions to fill out in the URL (use placeholder ${version} in the url-string)
Urlsingle url string
Urlsmultiple 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'
    },
    'react@16.14.0-default': 'https://cdnjs.cloudflare.com/ajax/libs/react/16.14.0/umd/react.production.min.js',
    'react@17.0.2': '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);
KeyDescription
PackageNamethe name of the package
Versionthe version-number in string format: major.minor(.patch)(.build)(-releaseCandidate)
Filetypethe 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('bootstrap.css@3.4.1'); //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('bootstrap@3.4.2');
//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: 'react@18.0.0' }
        },
        {
            url: 'https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.14.0/umd/react-dom.production.min.js',
            dependencyOverrides: { react: 'react@16.14.0' }
        }
    ],
    '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 "react@18.0.0" (or "react@16.14.0") 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","react@16.14.0"],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","react@18.0.0"],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);
KeyDescription
PackageNamethe name of the package
Versionthe version-number in string format: major.minor(.patch)(.build)(-releaseCandidate)
Filetypethe file extension - js/css/txt/xml/json/html/wasm/tag
Defaultindicates the default version
Dependenciespackage names (or urls) on which this package is dependent
Factoryfunction / 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('hello.css@1.0.0', [], '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('react@17.0.2', react1702FactoryFn);

RequireEs options

require.config({
    allowRedefine: false,
    invokeNonMatchedDefines: true
});
KeyDescription
allowRedefinedefault: 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
invokeNonMatchedDefinesdefault: 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

EventTrigger
requirees.pre-definewhen define gets called, but the factory is not stored into the registry yet
requirees.definewhen a package factory was added to the registry
requirees.pre-registerwhen require.register or require.config({paths}) are called, but the package it not added to the registry yet
requirees.registerwhen a package was added to the registry
requirees.pre-file-loadbefore an actual file/factory load is happening
requirees.file-loadwhen a file/factory load has completed
requirees.wiretapson all events
requirees.scripttag.preaddtriggers before requirees appends a script-tag to the dom
requirees.scripttag.addedtiggers after requirees appended a script-tag to the dom
requirees.styletag.preaddtriggers before requirees appends a script-tag to the dom
requirees.styletag.addedtiggers 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)

Keywords

FAQs

Package last updated on 29 Dec 2022

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc