UNPKG

browser-es-module-loader

Version:

Demonstrates ES module loading in the browser

1,078 lines (899 loc) 34.4 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global.BrowserESModuleLoader = factory()); }(this, function () { 'use strict'; /* * Environment */ var isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined'; var isNode = typeof process !== 'undefined' && process.versions && process.versions.node; var isWindows = typeof process !== 'undefined' && typeof process.platform === 'string' && process.platform.match(/^win/); var envGlobal = typeof self !== 'undefined' ? self : global; /* * Environment baseURI */ var baseURI; // environent baseURI detection if (typeof document != 'undefined' && document.getElementsByTagName) { baseURI = document.baseURI; if (!baseURI) { var bases = document.getElementsByTagName('base'); baseURI = bases[0] && bases[0].href || window.location.href; } } else if (typeof location != 'undefined') { baseURI = location.href; } // sanitize out the hash and querystring if (baseURI) { baseURI = baseURI.split('#')[0].split('?')[0]; baseURI = baseURI.substr(0, baseURI.lastIndexOf('/') + 1); } else if (typeof process != 'undefined' && process.cwd) { baseURI = 'file://' + (isWindows ? '/' : '') + process.cwd() + '/'; if (isWindows) baseURI = baseURI.replace(/\\/g, '/'); } else { throw new TypeError('No environment baseURI'); } /* * LoaderError with chaining for loader stacks */ var errArgs = new Error(0, '_').fileName == '_'; function LoaderError__Check_error_message_above_for_loader_stack(childErr, newMessage) { // Convert file:/// URLs to paths in Node if (!isBrowser) newMessage = newMessage.replace(isWindows ? /file:\/\/\//g : /file:\/\//g, ''); var message = (childErr.message || childErr) + '\n\t' + newMessage; var err; if (errArgs && childErr.fileName) err = new Error(message, childErr.fileName, childErr.lineNumber); else err = new Error(message); // node doesn't show the message otherwise if (isNode) err.stack = message; else err.stack = childErr.originalErr ? childErr.originalErr.stack : childErr.stack; err.originalErr = childErr.originalErr || childErr; return err; } /* * Simple Symbol() shim */ var hasSymbol = typeof Symbol !== 'undefined'; function createSymbol(name) { return hasSymbol ? Symbol() : '@@' + name; } /* * Simple Array values shim */ function arrayValues(arr) { if (arr.values) return arr.values(); if (typeof Symbol === 'undefined' || !Symbol.iterator) throw new Error('Cannot return values iterator unless Symbol.iterator is defined'); var iterable = {}; iterable[Symbol.iterator] = function() { var keys = Object.keys(arr); var keyIndex = 0; return { next: function() { if (keyIndex < keys.length) return { value: arr[keys[keyIndex++]], done: false }; else return { value: undefined, done: true }; } }; }; return iterable; } /* * 3. Reflect.Loader * * We skip the entire native internal pipeline, just providing the bare API */ // 3.1.1 function Loader(baseKey) { this.key = baseKey || baseURI; this.registry = new Registry(); // NB deprecate // evaluation flag to allow for tracing loaders this.execute = true; } // 3.3.1 Loader.prototype.constructor = Loader; // 3.3.2 Loader.prototype.import = function(key, parent) { if (typeof key !== 'string') throw new TypeError('Loader import method must be passed a module key string'); var execute = this.execute; return this.load(key, parent) .then(function(module) { // ensure evaluated if (execute) Module.evaluate(module); return module; }); }; // 3.3.3 var RESOLVE$1 = Loader.resolve = createSymbol('resolve'); // instantiate sets the namespace into the registry // it is up to implementations to ensure instantiate is debounced properly var INSTANTIATE = Loader.instantiate = createSymbol('instantiate'); Loader.prototype.resolve = function(key, parent) { return this[RESOLVE$1](key, parent) .catch(function(err) { throw LoaderError__Check_error_message_above_for_loader_stack(err, 'Resolving ' + key + (parent ? ' to ' + parent : '')); }); }; // 3.3.4 Loader.prototype.load = function(key, parent) { var loader = this; var resolvedKey; // there is the potential for an internal perf optimization to allow resolve to return { resolved, namespace } // but this needs to be done based on performance measurement return Promise.resolve(this[RESOLVE$1](key, parent || this.key)) .then(function(resolved) { var existingNamespace = loader.registry.get(resolved); if (existingNamespace) return Promise.resolve(existingNamespace); return loader[INSTANTIATE](resolved) .then(function(namespace) { // returning the namespace from instantiate can be considered a sort of perf optimization if (!namespace) namespace = loader.registry.get(resolvedKey); else if (!(namespace instanceof ModuleNamespace)) throw new TypeError('Instantiate did not resolve a Module Namespace'); return namespace; }); }) .catch(function(err) { throw LoaderError__Check_error_message_above_for_loader_stack(err, 'Loading ' + key + (resolvedKey ? ' as ' + resolvedKey : '') + (parent ? ' from ' + parent : '')); }); }; /* * 4. Registry * * Instead of structuring through a Map, just use a dictionary object * We throw for construction attempts so this doesn't affect the public API * * Registry has been adjusted to use Namespace objects over ModuleStatus objects * as part of simplifying loader API implementation */ var iteratorSupport = typeof Symbol !== 'undefined' && Symbol.iterator; function Registry() { this._registry = {}; } // 4.4.1 Registry.prototype.constructor = function() { throw new TypeError('Custom registries cannot be created.'); }; if (iteratorSupport) { // 4.4.2 Registry.prototype[Symbol.iterator] = function() { return this.entries()[Symbol.iterator](); }; // 4.4.3 Registry.prototype.entries = function() { var registry = this._registry; return arrayValues(Object.keys(registry).map(function(key) { return [key, registry[key]]; })); }; } // 4.4.4 Registry.prototype.keys = function() { return arrayValues(Object.keys(this._registry)); }; // 4.4.5 Registry.prototype.values = function() { var registry = this._registry; return arrayValues(Object.keys(registry).map(function(key) { return registry[key]; })); }; // 4.4.6 Registry.prototype.get = function(key) { return this._registry[key]; }; // 4.4.7 Registry.prototype.set = function(key, namespace) { if (!(namespace instanceof ModuleNamespace)) throw new Error('Registry must be set with an instance of Module Namespace'); this._registry[key] = namespace; return this; }; // 4.4.8 Registry.prototype.has = function(key) { return !!this._registry[key]; }; // 4.4.9 Registry.prototype.delete = function(key) { if (this._registry[key]) { //delete this._registry[key]; // much faster... this._registry[key] = undefined; return true; } return false; }; /* * Simple ModuleNamespace Exotic object based on a baseObject * We export this for allowing a fast-path for module namespace creation over Module descriptors */ function ModuleNamespace(baseObject, evaluate) { var ns = this; Object.keys(baseObject).forEach(function(key) { Object.defineProperty(ns, key, { configurable: false, enumerable: true, get: function () { return baseObject[key]; }, set: function() { throw new TypeError('Module exports cannot be changed externally.'); } }); }); if (evaluate) ns._evaluate = evaluate; } if (typeof Symbol !== 'undefined' && Symbol.toStringTag) ModuleNamespace.prototype[Symbol.toStringTag] = 'Module'; // 8.3.1 Reflect.Module function Module(descriptors, executor, evaluate) { if (typeof descriptors !== 'object') throw new TypeError('Expected descriptors object'); // instead of providing a mutator, just provide the base object var baseObject = {}; // 8.2.1 ParseExportsDescriptors Object.keys(descriptors).forEach(function(key) { var descriptor = descriptors[key]; if (!('value' in descriptor)) throw new TypeError('Error reading descriptor for "' + key + '" - module polyfill only supports value descriptors currently'); baseObject[key] = descriptor.value; }); var ns = new ModuleNamespace(baseObject, evaluate); if (executor) executor(baseObject, ns); return ns; }; // 8.4.2 Module.prototype = null; // 8.4.1 Module.evaluate Module.evaluate = function(ns) { if (!(ns instanceof ModuleNamespace)) throw new TypeError('Module.evaluate must be called on a Module Namespace'); if (ns._evaluate) { ns._evaluate(); ns._evaluate = undefined; } }; /* * Optimized URL normalization assuming a syntax-valid URL parent */ function resolveUrlToParentIfNotPlain(relUrl, parentUrl) { function throwResolveError() { throw new RangeError('Unable to resolve "' + relUrl + '" to ' + parentUrl); } var protocolIndex = relUrl.indexOf(':'); if (protocolIndex !== -1) { if (isNode) { // Windows filepath compatibility (unique to SystemJS, not in URL spec at all) // C:\x becomes file:///c:/x (we don't support C|\x) if (relUrl[1] === ':' && relUrl[2] === '\\' && relUrl[0].match(/[a-z]/i) && parentUrl.substr(0, 5) === 'file:') return 'file:///' + relUrl.replace(/\\/g, '/'); } return relUrl; } var parentProtocol = parentUrl && parentUrl.substr(0, parentUrl.indexOf(':') + 1); // protocol-relative if (relUrl[0] === '/' && relUrl[1] === '/') { if (!parentProtocol) throwResolveError(); return parentProtocol + relUrl; } // relative-url else if (relUrl[0] === '.' && (relUrl[1] === '/' || relUrl[1] === '.' && (relUrl[2] === '/' || relUrl.length === 2) || relUrl.length === 1) || relUrl[0] === '/') { var parentIsPlain = !parentProtocol || parentUrl[parentProtocol.length] !== '/'; // read pathname from parent if a URL // pathname taken to be part after leading "/" var pathname; if (parentIsPlain) { // resolving to a plain parent -> skip standard URL prefix, and treat entire parent as pathname if (parentUrl === undefined) throwResolveError(); pathname = parentUrl; } else if (parentUrl[parentProtocol.length + 1] === '/') { // resolving to a :// so we need to read out the auth and host if (parentProtocol !== 'file:') { pathname = parentUrl.substr(parentProtocol.length + 2); pathname = pathname.substr(pathname.indexOf('/') + 1); } else { pathname = parentUrl.substr(8); } } else { // resolving to :/ so pathname is the /... part pathname = parentUrl.substr(parentProtocol.length + 1); } if (relUrl[0] === '/') { if (parentIsPlain) throwResolveError(); else return parentUrl.substr(0, parentUrl.length - pathname.length - 1) + relUrl; } // join together and split for removal of .. and . segments // looping the string instead of anything fancy for perf reasons // '../../../../../z' resolved to 'x/y' is just 'z' regardless of parentIsPlain var segmented = pathname.substr(0, pathname.lastIndexOf('/') + 1) + relUrl; var output = []; var segmentIndex = undefined; for (var i = 0; i < segmented.length; i++) { // busy reading a segment - only terminate on '/' if (segmentIndex !== undefined) { if (segmented[i] === '/') { output.push(segmented.substr(segmentIndex, i - segmentIndex + 1)); segmentIndex = undefined; } continue; } // new segment - check if it is relative if (segmented[i] === '.') { // ../ segment if (segmented[i + 1] === '.' && (segmented[i + 2] === '/' || i === segmented.length - 2)) { output.pop(); i += 2; } // ./ segment else if (segmented[i + 1] === '/' || i === segmented.length - 1) { i += 1; } else { // the start of a new segment as below segmentIndex = i; continue; } // this is the plain URI backtracking error (../, package:x -> error) if (parentIsPlain && output.length === 0) throwResolveError(); // trailing . or .. segment if (i === segmented.length) output.push(''); continue; } // it is the start of a new segment segmentIndex = i; } // finish reading out the last segment if (segmentIndex !== undefined) output.push(segmented.substr(segmentIndex, segmented.length - segmentIndex)); return parentUrl.substr(0, parentUrl.length - pathname.length) + output.join(''); } // plain name -> return undefined } var emptyModule = new ModuleNamespace({}); /* * Register Loader * * Builds directly on top of loader polyfill to provide: * - loader.register support * - hookable higher-level normalize with metadata argument * - instantiate hook with metadata arugment returning a ModuleNamespace or undefined for es module loading * - loader error behaviour as in HTML and loader specs, clearing failed modules from registration cache synchronously * - build tracing support by providing a .trace=true and .loads object format */ function RegisterLoader(baseKey) { Loader.apply(this, arguments); // System.register registration cache this._registerCache = {}; // last anonymous System.register call this._registeredLastAnon = undefined; // in-flight es module load records this._registerRegistry = {}; // tracing this.trace = false; // trace load objects when tracing this.loads = {}; } RegisterLoader.prototype = Object.create(Loader.prototype); RegisterLoader.prototype.constructor = RegisterLoader; // these are implementation specific // this allows a v2 migration path into symbols so normalize and instantiate // aren't exposed to end-users RegisterLoader.normalize = 'normalize'; RegisterLoader.instantiate = 'instantiate'; RegisterLoader.createMetadata = 'createMetadata'; // default normalize is the WhatWG style normalizer RegisterLoader.prototype.normalize = function(key, parentKey, metadata) { return resolveUrlToParentIfNotPlain(key, parentKey); }; RegisterLoader.prototype.instantiate = function(key, metadata) {}; // this function is an optimization to allow loader extensions to // implement it to set the metadata object shape upfront to ensure // it can run as a single hidden class throughout the normalize // and instantiate pipeline hooks in the js engine RegisterLoader.prototype.createMetadata = function() { return {}; }; var RESOLVE = Loader.resolve; RegisterLoader.prototype[RESOLVE] = function(key, parentKey) { var loader = this; // normalization shortpath if already in the registry or loading if (key && (loader.registry.has(key) || loader._registerRegistry[key])) return Promise.resolve(key); var metadata = this.createMetadata(); return Promise.resolve(loader.normalize(key, parentKey, metadata)) .then(function(resolvedKey) { if (typeof resolvedKey !== 'string') { if (resolvedKey === undefined) throw new RangeError('No resolution normalizing "' + key + '" to ' + parentKey); // allow a non-string resolve for use cases like conditionals return resolvedKey; } // we create the in-progress load record already here to store the normalization metadata if (!loader.registry.has(resolvedKey)) getOrCreateLoadRecord(loader, resolvedKey, metadata); return resolvedKey; }); }; // provides instantiate promise cache // we need to first wait on instantiate which will tell us if it is ES or not // this record represents that waiting period, and when set, we then populate // the esLinkRecord record into this load record. // instantiate is a promise for a module namespace or undefined function getOrCreateLoadRecord(loader, key, metadata) { return loader._registerRegistry[key] || (loader._registerRegistry[key] = { key: key, metadata: metadata, instantiatePromise: undefined, module: undefined, // es-specific esLinkRecord: undefined, importerSetters: undefined }); } RegisterLoader.prototype[Loader.instantiate] = function(key) { var loader = this; return instantiate(this, key) .then(function(instantiated) { if (instantiated instanceof ModuleNamespace) return Promise.resolve(instantiated); return instantiateAllDeps(loader, instantiated, []) .then(function() { if (loader.execute) var err = ensureEvaluated(loader, instantiated, []); if (err) return Promise.reject(err); if (loader.trace) traceLoadRecord(loader, instantiated, []); return instantiated.module || emptyModule; }) .catch(function(err) { clearLoadErrors(loader, instantiated); throw err; }); }) }; // instantiates the given module name // returns the load record for es or the namespace object for dynamic // setting the dynamic namespace into the registry function instantiate(loader, key) { var load = loader._registerRegistry[key]; // this is impossible assuming resolve always runs before instantiate if (!load) throw new TypeError('Internal error, load record not created'); return load.instantiatePromise || (load.instantiatePromise = Promise.resolve(loader.instantiate(key, load.metadata)) .then(function(instantiation) { // dynamic module if (instantiation !== undefined) { loader.registry.set(key, instantiation); loader._registerRegistry[key] = undefined; return instantiation; } // run the cached loader.register declaration if there is one ensureRegisterLinkRecord.call(loader, load); // metadata no longer needed if (!loader.trace) load.metadata = undefined; return load; }) .catch(function(err) { err = LoaderError__Check_error_message_above_for_loader_stack(err, 'Instantiating ' + load.key); // immediately clear the load record for an instantiation error if (loader._registerRegistry[load.key] === load) loader._registerRegistry[load.key] = undefined; throw err; })); } // this only applies to load records with load.esLinkRecord set function instantiateAllDeps(loader, load, seen) { // skip if already linked if (load.module) return Promise.resolve(); var esLinkRecord = load.esLinkRecord; // no dependencies shortpath if (!esLinkRecord.dependencies.length) return Promise.resolve(); // assumes seen does not contain load already seen.push(load); var instantiateDepsPromises = Array(esLinkRecord.dependencies.length); // normalize dependencies for (var i = 0; i < esLinkRecord.dependencies.length; i++) (function(i) { // this resolve can potentially be cached on the link record, should be a measured optimization instantiateDepsPromises[i] = loader[RESOLVE](esLinkRecord.dependencies[i], load.key) .catch(function(err) { throw LoaderError__Check_error_message_above_for_loader_stack(err, 'Resolving ' + esLinkRecord.dependencies[i] + ' to ' + load.key); }) .then(function(resolvedDepKey) { var existingNamespace = loader.registry.get(resolvedDepKey); if (existingNamespace) { esLinkRecord.dependencyInstantiations[i] = existingNamespace; // run setter to reference the module if (esLinkRecord.setters[i]) esLinkRecord.setters[i](existingNamespace); return Promise.resolve(); } if (loader.trace) { esLinkRecord.depMap = esLinkRecord.depMap || {}; esLinkRecord.depMap[esLinkRecord.dependencies[i]] = resolvedDepKey; } return instantiate(loader, resolvedDepKey) .then(function(instantiation) { // instantiation is either a load record or a module namespace esLinkRecord.dependencyInstantiations[i] = instantiation; // dynamic module if (instantiation instanceof ModuleNamespace) { if (esLinkRecord.setters[i]) esLinkRecord.setters[i](instantiation); return Promise.resolve(); } // register setter with dependency instantiation.importerSetters.push(esLinkRecord.setters[i]); // run setter now to pick up the first bindings from the dependency if (esLinkRecord.setters[i]) esLinkRecord.setters[i](instantiation.esLinkRecord.moduleObj); // circular if (seen.indexOf(instantiation) !== -1) return Promise.resolve(); // es module load // if not already linked, instantiate dependencies if (instantiation.esLinkRecord) return instantiateAllDeps(loader, instantiation, seen); }); }) })(i); return Promise.all(instantiateDepsPromises) .catch(function(err) { err = LoaderError__Check_error_message_above_for_loader_stack(err, 'Loading ' + load.key); // throw up the instantiateAllDeps stack // loads are then synchonously cleared at the top-level through the helper below // this then ensures avoiding partially unloaded tree states esLinkRecord.error = err; throw err; }); } // clears an errored load and all its errored dependencies from the loads registry function clearLoadErrors(loader, load) { // clear from loads if (loader._registerRegistry[load.key] === load) loader._registerRegistry[load.key] = undefined; var esLinkRecord = load.esLinkRecord; if (!esLinkRecord) return; esLinkRecord.dependencyInstantiations.forEach(function(depLoad, index) { if (!depLoad || depLoad instanceof ModuleNamespace) return; if (depLoad.esLinkRecord && depLoad.esLinkRecord.error) { // unregister setters for es dependency load records var setterIndex = depLoad.importerSetters.indexOf(esLinkRecord.setters[index]); depLoad.importerSetters.splice(setterIndex, 1); // provides a circular reference check if (loader._registerRegistry[depLoad.key] === depLoad) clearLoadErrors(loader, depLoad); } }); } function createESLinkRecord(dependencies, setters, module, moduleObj, execute) { return { dependencies: dependencies, error: undefined, // will be the dependency ES load record, or a module namespace dependencyInstantiations: Array(dependencies.length), setters: setters, module: module, moduleObj: moduleObj, execute: execute }; } /* * System.register * Places the status into the registry and a load into the loads list */ RegisterLoader.prototype.register = function(key, deps, declare) { // anonymous modules get stored as lastAnon if (declare === undefined) this._registeredLastAnon = [key, deps]; // everything else registers into the register cache else this._registerCache[key] = [deps, declare]; }; RegisterLoader.prototype.processRegisterContext = function(contextKey) { if (!this._registeredLastAnon) return; this._registerCache[contextKey] = this._registeredLastAnon; this._registeredLastAnon = undefined; }; function ensureRegisterLinkRecord(load) { // ensure we already have a link record if (load.esLinkRecord) return; var key = load.key; var registrationPair = this._registerCache[key]; if (!registrationPair) throw new TypeError('Module instantiation did not call an anonymous or correctly named System.register'); this._registerCache[key] = undefined; var importerSetters = []; var moduleObj = {}; var locked = false; var declared = registrationPair[1].call(envGlobal, function(name, value) { // export setter propogation with locking to avoid cycles if (locked) return; if (typeof name == 'object') { for (var p in name) moduleObj[p] = name[p]; } else { moduleObj[name] = value; } if (importerSetters.length) { locked = true; for (var i = 0; i < importerSetters.length; i++) // this object should be a defined module object // but in order to do that we need the exports returned by declare // for now we assume no exports in the implementation importerSetters[i](moduleObj); locked = false; } return value; }, new ContextualLoader(this, key)); var setters, execute; if (typeof declared !== 'function') { setters = declared.setters; execute = declared.execute; } else { setters = [], execute = declared; } // TODO, pass module when we can create it here already via exports load.importerSetters = importerSetters; load.esLinkRecord = createESLinkRecord(registrationPair[0], setters, undefined, moduleObj, execute); } // ContextualLoader class // backwards-compatible with previous System.register context argument by exposing .id function ContextualLoader(loader, key) { this.loader = loader; this.key = this.id = key; } ContextualLoader.prototype.constructor = function() { throw new TypeError('Cannot subclass the contextual loader only Reflect.Loader.'); }; ContextualLoader.prototype.import = function(key) { return this.loader.import(key, this.key) }; ContextualLoader.prototype.resolve = function(key) { return this.loader[Loader.resolve](key, this.key); }; ContextualLoader.prototype.load = function(key) { return this.loader.load(key, this.key); }; // ensures the given es load is evaluated // returns the error if any function ensureEvaluated(loader, load, seen) { var esLinkRecord = load.esLinkRecord; // no esLinkRecord means evaluated if (!esLinkRecord) return; // assumes seen does not contain load already seen.push(load); var err, depLoad; for (var i = 0; i < esLinkRecord.dependencies.length; i++) { depLoad = esLinkRecord.dependencyInstantiations[i]; // non ES load // it is the responsibility of the executor to remove the module from the registry on failure if (depLoad instanceof ModuleNamespace) err = namespaceEvaluate(depLoad); // ES load else if (seen.indexOf(depLoad) === -1) err = ensureEvaluated(loader, depLoad, seen); if (err) return LoaderError__Check_error_message_above_for_loader_stack(err, 'Evaluating ' + load.key); } // es load record evaluation err = esEvaluate(esLinkRecord); if (err) { loader.registry.delete(load.key); if (loader._registerRegistry[load.key] === load) loader._registerRegistry[load.key] = undefined; return LoaderError__Check_error_message_above_for_loader_stack(err, 'Evaluating ' + load.key); } load.module = new ModuleNamespace(esLinkRecord.moduleObj); loader.registry.set(load.key, load.module); // can clear link record now if (!loader.trace) load.esLinkRecord = undefined; } function esEvaluate(esLinkRecord) { try { // {} is the closest we can get to call(undefined) // this should really be blocked earlier though esLinkRecord.execute.call({}); } catch(err) { return err; } } function namespaceEvaluate(namespace) { try { Module.evaluate(namespace); } catch(err) { return err; } } function traceLoadRecord(loader, load, seen) { // its up to dynamic instantiate layers to ensure their own traces are present if (load instanceof ModuleNamespace) return; seen.push(load); if (!load.esLinkRecord || load.esLinkRecord.dependencies.length && !load.esLinkRecord.depMap) throw new Error('Tracing error, ensure loader.trace is set before loading begins'); loader.loads[load.key] = { key: load.key, dependencies: load.esLinkRecord.dependencies, depMap: load.esLinkRecord.depMap || {}, metadata: load.metadata }; load.esLinkRecord.dependencyInstantiations.forEach(function(dep) { if (seen.indexOf(dep) === -1) traceLoadRecord(loader, dep, seen); }); } if (!window.babel || !window.babelPluginTransformES2015ModulesSystemJS) throw new Error('babel-browser-build.js must be loaded first'); var loader; // <script type="module"> support var anonSources = {}; if (typeof document != 'undefined' && document.getElementsByTagName) { function ready() { document.removeEventListener('DOMContentLoaded', ready, false ); var anonCnt = 0; var scripts = document.getElementsByTagName('script'); for (var i = 0; i < scripts.length; i++) { var script = scripts[i]; if (script.type == 'module' && !script.loaded) { script.loaded = true; if (script.src) { loader.import(script.src); } // anonymous modules supported via a custom naming scheme and registry else { var anonName = resolveUrlToParentIfNotPlain('./<anon' + ++anonCnt + '>', baseURI); anonSources[anonName] = script.innerHTML; loader.import(anonName); } } } } // simple DOM ready if (document.readyState === 'complete') setTimeout(ready); else document.addEventListener('DOMContentLoaded', ready, false); } function BrowserESModuleLoader(baseKey) { baseKey = baseKey ? resolveUrlToParentIfNotPlain(baseKey, baseURI) || baseKey : baseURI; RegisterLoader.call(this, baseKey); var loader = this; // ensure System.register is available envGlobal.System = envGlobal.System || {}; if (typeof envGlobal.System.register == 'function') var prevRegister = envGlobal.System.register; envGlobal.System.register = function() { loader.register.apply(loader, arguments); if (prevRegister) prevRegister.apply(this, arguments); }; } BrowserESModuleLoader.prototype = Object.create(RegisterLoader.prototype); // normalize is never given a relative name like "./x", that part is already handled BrowserESModuleLoader.prototype.normalize = function(key, parent, metadata) { var resolved = RegisterLoader.prototype.normalize.call(this, key, parent, metadata) || key; if (!resolved) throw new RangeError('ES module loader does not resolve plain module names, resolving "' + key + '" to ' + parent); return resolved; }; function xhrFetch(url, resolve, reject) { var xhr = new XMLHttpRequest(); function load(source) { resolve(xhr.responseText); } function error() { reject(new Error('XHR error' + (xhr.status ? ' (' + xhr.status + (xhr.statusText ? ' ' + xhr.statusText : '') + ')' : '') + ' loading ' + url)); } xhr.onreadystatechange = function () { if (xhr.readyState === 4) { // in Chrome on file:/// URLs, status is 0 if (xhr.status == 0) { if (xhr.responseText) { load(); } else { // when responseText is empty, wait for load or error event // to inform if it is a 404 or empty file xhr.addEventListener('error', error); xhr.addEventListener('load', load); } } else if (xhr.status === 200) { load(); } else { error(); } } }; xhr.open("GET", url, true); xhr.send(null); } // instantiate just needs to run System.register // so we fetch the source, convert into the Babel System module format, then evaluate it BrowserESModuleLoader.prototype.instantiate = function(key, metadata) { var loader = this; // load as ES with Babel converting into System.register return new Promise(function(resolve, reject) { // anonymous module if (anonSources[key]) { resolve(anonSources[key]) anonSources[key] = undefined; } // otherwise we fetch else { xhrFetch(key, resolve, reject); } }) .then(function(source) { // transform source with Babel var output = babel.transform(source, { compact: false, filename: key + '!transpiled', sourceFileName: key, moduleIds: false, sourceMaps: 'inline', plugins: [babelPluginTransformES2015ModulesSystemJS] }); // evaluate without require, exports and module variables // we leave module in for now to allow module.require access (0, eval)(output.code + '\n//# sourceURL=' + key + '!transpiled'); loader.processRegisterContext(key); }); }; // create a default loader instance in the browser if (isBrowser) loader = new BrowserESModuleLoader(); return BrowserESModuleLoader; }));