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

assets-dynamic-import

v3.0.0

Published

Static Assets loader

Downloads

1,293

Readme

assets-dynamic-import

Build Status Coverage Status npm version npm downloads GitHub license

Simple way to dynamicly import some external assets in the runtime.

Installation

npm install --save assets-dynamic-import

Usage

import { importScript } from 'assets-dynamic-import';

const processSomeData = async data => {
  const { someFnFromMyLib } = await importScript(
    '//some.path.to/script.js',
    () => global.someGlobalLibraryName
  );

  return someFnFromMyLib(data);
}
import { importScript, importStyle } from 'assets-dynamic-import';

export interface Recurly {
  token(form: HTMLFormElement, cb: (err: Error | null, token: string) => void): void;
}

export default () => Promise.all([
    () => importScript('https://js.recurly.com/v4/recurly.js'),
    () => importStyle('https://js.recurly.com/v4/recurly.css'),
])
  .then(() => {
    const recurly = (window as any).recurly as Recurly;
    return {
      token: (form: HTMLFormElement): Promise<string> => new Promise(
        (resolve, reject) => recurly.token(form, (err: Error | null, token: string) => (
          err == null ? resolve(token) : reject(err)
        )
      )),
    };
  });

Motivation

The main idea of the library to provide users with minimal tool set that allows to work with external (to application bundle) assets.

The library is developed considering following use cases:

  1. to use extrnal libraries in single-page appliction preventing excess loading of not-used of them for major of pages (aka recurly, stripe, pdf.js etc.)

  2. integrate separetelly deployed SPA's to one large single page application.

import React from 'react';
import { importScript } from 'assets-dynamic-import';
import { BrowserRouter, Switch, Route } from 'react-router-dom';
import { CDN } from './config';

const ViewerApplication = React.lazy(
  () => importScript(
    `${CDN}/viewer.bundle.js`, 
    () => global.viewerLib.default,
  )
);

const MyAccountApplication = React.lazy(
  () => importScript(
    `${CDN}/myaccount.bundle.js`,
    () => global.accountLib.default,
  )
);

const App = () => (
  <BrowserRouter>
    <Switch>
      <Route path="/viewer" component={ViewerApplication} />
      <Route component={MyAccountApplication}> />
    </Switch>
  </BrowserRouter>
);

export default App;

Specification

The library exports the following functions:

| Function | Target | Child | Cache | Description | |:--------------:|:------:|:--------:|:-----:|:----------------------------------------------------------| | importScript | body | script | yes | Imports javascript-assets and caches such imports | | appendScript | body | script | no | Creates a script-node and appends it to the document body that initiats resourse loading | | importStyle | head | link | yes | Imports CSS-assets and caches such imports | | appendStyle | head | link | no | Creates a link-node and appends it to the document head that initiats resource loading | | createElement | n/a | n/a | no | Creates DOMNode and assigns its properties | | appendNodeAsync | any | any | no | Assigns onload and onerror event lesteners of the Child and appends it to the Target | | cacheAll | n/a | n/a | n/a | Memoization function decorator |


importScript(src[, nodeProps][, resolveCallback]): Promise

Creates <script> node assigns it with src, type attributes from nodeProps and then appends it to the document <body>.

Function returns promise.

importScript could be safely called several times with the same src. Each further call of importScript results with the same promise as the first call.

Arguments:

| Argument | Type | Mandatory | Description | |:---------:|:--------:|:---------:|:------------------------| | src | string | yes | url to load javascript from | | nodeProps | WritableAttribures<HTMLScriptElement> | no | object with attributes of <script> element | | resolveCallback | () => T | no | callback to resolve some js interface after script is loaded |

Return value:

  • Promise<T> - that resolves with result of resolveCallback (if specified otherwise with undefined) or rejects with Error and message: 'Couldn't load script by '.

Example 1. "Recurly":

./recurly.ts

import { importScript, importStyle } from 'assets-dynamic-import';

export interface Recurly {
  token(form: HTMLFormElement, cb: (err: Error | null, token: string) => void): void;
}

export default () => Promise.all([
    () => importScript('https://js.recurly.com/v4/recurly.js'),
    () => importStyle('https://js.recurly.com/v4/recurly.css'),
])
  .then(() => {
    const recurly = (window as any).recurly as Recurly;
    return {
      token: (form: HTMLFormElement): Promise<string> => new Promise(
        (resolve, reject) => recurly.token(form, (err: Error | null, token: string) => (
          err == null ? resolve(token) : reject(err)
        )
      )),
    };
  });

And then we can easily import recurly where we need and call promisified token method

import importRecurly from './recurly.ts';

const getToken = (form: HTMLFormElement) => importRecurly()
  .then(
    recurly => recurly.token(form)
  )
;

Example 2."Integrity and Credential policy"

    importScript(
      'https://some-domain.come/some-script.js',
      {
        integrity: 'sha256-4+XzXVhsDmqanXGHaHvgh1gMQKX40OUvDEBTu8JcmNs=',
        crossOrigin: 'anonymous'
      },
      () => global.jQuery
    ),

appendScript(src[, nodeProps][, resolveCallback]): Promise

Creates <script> node assigns it with src, type attributes from nodeProps and then appends it to the document <body>.

Function returns promise.

Each call of appendScript results in a new <script> tag appended to the body, so it initiates script loading and running each time.

The main reason to expose this function is to allows library users to customise memoization for that in their own way tailored to their tasks.

Actaully importScript is a momoized version of appenScript that caches its calls by src.

Arguments:

| Argument | Type | Mandatory | Description | |:---------:|:--------:|:---------:|:------------------------| | src | string | yes | url to load javascript from | | nodeProps | WritableAttribures<HTMLScriptElement> | no | object with attributes of <script> element. nodeProps.src overrides value of src | | resolveCallback | () => T | no | callback to resolve some js interface after script is loaded |

Return value:

  • Promise<T> - that resolves with result of resolveCallback (if specified otherwise with undefined) or rejects with Error and message: 'Couldn't load script by '.

Example:

./cached-import.ts

import { appendScript, appendStyle } from 'assets-dynamic-import';


global.__moduleCache = (global.__moduleCache  as Map<string, any>)
  || new Map<string, any>();

const memoize = <A extends any[], R>(fn: (key: string, ...args: A) => R) 
  => (key: string, ...args: A): R => {
    if (global.__moduleCache.has(key)) return global.__moduleCache.get(key);
  
  const result = fn(key, ...args);
  global.__moduleCache.set(key, result);

  return result;
}

export const importScript = memoize(appendScript);
export const importStyle = memoize(appendStyle);

And then we can use new memoized importing function in any bundle that works in the same browser tab.

import { importScript, importStyle } from './cached-import.ts';

// ...

importStyle(href[, nodeProps][, resolveCallback]): Promise

Creates <link> node assigns it with href, rel, attributes from nodeProps and then appends it to the document <head>.

Function returns promise.

importStyle could be safely called several times with the same href. Each further call of importStyle results with the same promise as the first call.

Arguments:

| Argument | Type | Mandatory | Description | |:---------:|:--------:|:---------:|:------------------------| | href | string | yes | url to load styles from | | nodeProps | WritableAttribures<HTMLLinkElement> | no | object with attributes of <link> element. nodeProp.href overrides href | | resolveCallback | () => T | no | callback to resolve some js interface after styles are loaded |

Return value:

  • Promise<T> - that resolves with result of resolveCallback (if specified otherwise with undefined) or rejects with Error and message: 'Couldn't load stylesheet by '

How to import:

import { importStyle } from 'assets-dynamic-import';

appendStyle(href[, nodeProps][, resolveCallback]): Promise

Creates <link> node assigns it with href, rel, attributes from nodeProps and then appends it to the document <head>.

Function returns promise.

Each call of appendStyle results in a new <link> tag appended to the head, so it initiates style loading each time.

The main reason to expose this function is to allows library users to customise memoization for it in their own way tailored to their tasks.

Actaully importStyle is a momoized version of appenStyle that caches its calls by href.

Arguments:

| Argument | Type | Mandatory | Description | |:---------:|:--------:|:---------:|:------------------------| | href | string | yes | url to load styles from | | nodeProps | WritableAttribures<HTMLLinkElement> | no | object with attributes of <link> element | | resolveCallback | () => T | no | callback to resolve some js interface after styles are loaded |

Return value:

  • Promise<T> - that resolves with result of resolveCallback (if specified otherwise with undefined) or rejects with Error and message: 'Couldn't load stylesheet by '

How to import:

import { appendStyle } from 'assets-dynamic-import';

createElement(tag, nodeProps): HTMLElement

Creates a DOM node with tag and assigns its props, specified as nodeProps:

Arguments:

| Argument | Type | Mandatory | Description | |:---------:|:--------:|:---------:|:------------------------| | tag | string | yes | the html tag to create DOM node with | | nodeProps | WritableAttribures<HTMLElement[tag]> | no | object with attributes of element |

Returns

  • HTNLElement[tag] - created DOM node.

How to import:

import { createElement } from 'assets-dynamic-import';

appendNode(target, node[, resolveCallback]): Promise

Assigns loading hooks of node (onload and onerror) and appends it to the target. If node has some content to be loaded, the function returns Promise that will be resolved after the content will be loaded.

Arguments:

| Argument | Type | Mandatory | Description | |:---------:|:--------:|:---------:|:------------------------| | target | HTMLElement | yes | the DOM node to append node as its child | | node | HTMLElement | no | the DOM node to be appended to the target node | | resolveCallback | () => T | no | callback to resolve some js interface after node will be appended and its content will be loaded |

Returns

  • Promise<T> - that resolves with result of resolveCallback (if specified otherwise with undefined) or rejects with Error.

How to import:

import { appendNodeAsync } from 'assets-dynamic-import';

cacheAll(fn [, getKey]): Function

type Fn<A extends any[], R> = (...args: A) => R;

export function cacheAll<A extends any[], R, K>(
	fn: Fn<A, R>, 
	getCacheKey?: Fn<A, K>
): Fn<A, R> & { force: Fn<A, R>}

How to import:

import { cacheAll } from 'assets-dynamic-import';