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

lowloader

v1.0.0

Published

A module loader built for microfrontends. Give it a URL, it will return a Promise that will resolve when the module is available.

Downloads

6

Readme

Low Loader

An unremarkable script loader built for Microfrontends. Give it a URL, it will download the JavaScript from the location and resolve a promise when it's done.

Very simple, zero config, single purpose, tiny. No tooling required, it just works.

Designed for loading code from a CDN into a Browser. Entirely agnostic of build tool. Use Webpack, Rollup, Grunt, Browserify, etc, etc. Use any library, framework or language.

Basic Usage

import loader from 'lowloader';

const url = 'http://www.cdn.com/myapp.js'
loader.load(url).then((myApp) => {
  myApp.bootstrap();
)

Built for Microfrontends

Microfrontends let you manage legacy. Older code can be siloed and gradually replaced. Newer features can be built with newer kit. This makes it easier to attract and retain talent since devs get to use the most interesting tools, and it means you are not locked into decisions made five years ago that may no longer make sense.

This increases productivity since apps are kept small and never get too complex to understand. Smaller apps are faster to build and debug. Individual apps can be removed or replaced without throwing away the entire codebase. Legacy code can be put in a box. As long as it still works, it can go on serving customers.

LowLoader is a Framework/build tool agnostic low-touch script loader built for micro-frontends.

  1. Build your app in whatever framework/tool you like. eg. create-react-app, Angular, AngularJS, Vue, Backbone, ES6, Typescript, JQuery, Webpack, Rollup, etc. etc.
  2. lowloader.export your code.
  3. Deploy your code to some web-accessible location. In production, this will be a CDN. For local dev, this might be a live-server, Apache webroot, IIS, etc.
  4. lowloader.import your code from any web accessible URL.

Note that if you cannot lowloader.export (for example if you are loading a standard dependency) you can simply import and use a global. More on this later.

Works well with Single Spa

To orchestrate code loading based on routing, I recommend Single-Spa. https://github.com/CanopyTax/single-spa

You can find a complete demo here, featuring:

  • Vanilla React
  • Create React App
  • Vanilla ES6 App
  • Legacy AngularJS App
  • Pushstate Routing
  • Dynamic dependency Loading

Work in progress:

https://github.com/nicholas-johnson/lowloader-singlespa-microfrontends-example

Export arbitrary code from a web location and import it on demand

Microfrontends work best if you can build your apps independently, put them on a CDN, and load them into your SPA on demand. If your user is not viewing the settings page, just don't load it. If the user is not on a dashboard, don't load the code. Load the code you need on-demand as the user navigates your app.

Create a js file and put it on a CDN (http://mycdn.com/my-app.js):

import lowloader from 'lowloader';

// You can export anything you like
const app = {
  sayHello: () => console.log('hello');
}

// When the code is downloaded, the exported value 
// will be made available to the import Promise resolve function.
lowloader.export(app);

Now from another js file, you can dynamically import it.

import lowloader from 'lowloader';

lowloader.import('http://mycdn.com/my-app.js)
  .then((myApp) => myApp.sayHello());

Dynamically load shared dependencies using promises

Say you have several microfrontends that use the same libraries, eg. React and ReactDom. You can load them using lowLoader before loading your app. If another app has already loaded them, they will be cached, and will not be loaded again.

const react = 'http://www.cdn.com/react.js'
const reactDOM = 'http://www.cdn.com/react-dom.js'
const app = 'http://www.cdn.com/my-app.js'

loader.load(react)
  .then(() => { loader.load(reactDom) )
  .then(() => { loader.load(app) )
  .then(() => { app.init() )

Also works with async await

const init = async () => {
  await loader.load(dependency_1)
  await loader.load(dependency_2)
  await loader.load(dependency_3)
}

Globals and Shared Dependencies

It is not always practical to lowloader.export(code). You may be downloading a library from a CDN. Maybe React or Highcharts. In this case, you can simply use a global.

Most libraries that are exported from a CDN will create a global. React creates window.React. JQuery creates window.$.

Here we download React and ReactDom.

const cdn = 'https://unpkg.com'
const reactUrl = `${cdn}/react@16/umd/react.development.js`;
const reactDomUrl = `${cdn}react-dom@16/umd/react-dom.development.js`

loader.load(reactUrl)
  .then(() => {loader.load(reactDomUrl)})
  .then(() => {
    ReactDOM.render(
      React.createElement('div', null, 'Hello World'),
      document.getElementById('root')
    );
  })

If you want to load dependencies this way, and you find yourself relying on global values of React in your microapps, you can tell Webpack to treat React as an external. This will tell React to look for window.react instead of bundling React into the app. This will allow you to share a common version of React between multiple microapps.

Local caching

Lowloader automatically caches by URL. You won't download the same code more than once, no matter how many times you import it or from which file or codebase. Lowloader's cache is a browser singleton so you can import wherever you like and Lowloader will handle it. If the code is already loaded, import will return a resolved promise.

Comparison with SystemJS

Because SystemJS is implemented with tooling, it requires a good deal of setup, and can be a pain to integrate into older apps.

Lowloader takes a zero config approach. It does one thing, it loads code into the browser. There's nothing to think about and nothing to go wrong. Your existing build pipeline can remain unchanged.

How it works

It's actually incredibly simple.

There are two ways to download and run code from the Internet.

  • A Script tag
  • AJAX plus eval

The second option gives you greater flexibility but breaks all the debugging tools in Chrome. LowLoader loads code from the Internet by dynamically adding script tags to the head of the page, then managing onLoad and onError.

onLoad the promise resolves. onError it rejects. Export simply squirrels the object into a temporary cache location. Import retrieves it.