Skip to content

Instantly share code, notes, and snippets.

@termosa
Created June 23, 2019 12:13
Show Gist options
  • Save termosa/7ae91971c45d517efa7a3658791a95a1 to your computer and use it in GitHub Desktop.
Save termosa/7ae91971c45d517efa7a3658791a95a1 to your computer and use it in GitHub Desktop.
Asynchronously load JavaScript modules from web
;((root, name, factory) => {
if (typeof define === 'function' && define.amd)
define([], () => (root[name] = factory()))
else if (typeof module === 'object' && module.exports)
module.exports = factory()
else
root[name] = factory()
})(typeof self !== 'undefined' ? self : this, 'loadModule', () => {
const cache = {}
const basePath = `${location.origin}${location.pathname}/`
const joinPath = (...paths) => paths.reduce((addr, path) => {
const hasSeparator = addr.endsWith('/') || path.startsWith('/')
return `${addr}${hasSeparator ? '' : '/'}${path}`
})
const normalizeAddress = address => {
const [protocol, rest] = address.split('://')
if (!~rest.indexOf('/'))
return address
const pathStart = rest.indexOf('/') + protocol.length + 3
let path = address.slice(pathStart)
path = path.replace(/\/\.\//g, '/').replace(/\/+/g, '/')
let oldPath
do {
oldPath = path
path = path.replace(/\/[^\/]+\/\.\.\//g, '/')
} while (oldPath !== path)
return address.slice(0, pathStart) + path
}
const resolve = (path, base) => {
if (~path.indexOf('://'))
return path
if (path.startsWith('/'))
return `${(new URL(location.href)).origin}${path}`
const address = joinPath(base, path)
return normalizeAddress(address)
}
const load = (base, path) => {
if (Array.isArray(path))
return Promise.all(path.map(load.bind(null, base)))
const id = resolve(path, base && base.slice(0, base.lastIndexOf('/')))
if (cache[id])
return cache[id].content
cache[id] = {
module: {
exports: {}
}
}
return cache[id].content = fetch(id)
.then(response => response.text())
.then(script => new Function('module', 'exports', 'load', script))
.then(fun => fun(cache[id].module, cache[id].module.exports, load.bind(null, id)))
.then(() => cache[id].module.exports)
}
return path => load(basePath, path)
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment