All files script-loader.js

87.18% Statements 34/39
33.33% Branches 5/15
100% Functions 9/9
86.49% Lines 32/37
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128                                        22x 22x   22x   22x                   22x   22x       22x   22x 30x     22x                       30x 30x   30x   30x 30x   30x 30x   30x 28x               28x 28x   28x 29x                             29x       30x 2x 2x   2x                     3x     30x 30x     32x      
/**
 * © 2014 Liferay, Inc. <https://liferay.com>
 *
 * SPDX-License-Identifier: LGPL-3.0-or-later
 */
 
import URLBuilder from './url-builder';
 
/* eslint-disable no-console */
 
/**
 * A class responsible for loading the script resources that contain modules
 * from the server.
 */
export default class ScriptLoader {
	/**
	 * @param {object} document DOM document object to use
	 * @param {Config} config
	 */
	constructor(document, config) {
		this._document = document;
		this._config = config;
 
		this._urlBuilder = new URLBuilder(config);
 
		this._injectedScripts = {};
	}
 
	/**
	 * Loads list of modules
	 * @param {Array} moduleNames List of modules to be loaded.
	 * @return {Promise} Promise which will be resolved as soon as all modules
	 * 						have been loaded.
	 */
	loadModules(moduleNames) {
		const urlBuilder = this._urlBuilder;
 
		Iif (moduleNames.length == 0) {
			return Promise.resolve();
		}
 
		const modulesURLs = urlBuilder.build(moduleNames);
 
		const promises = modulesURLs.map(modulesURL =>
			this._loadScript(modulesURL)
		);
 
		return Promise.all(promises);
	}
 
	/**
	 * Places a script element on the page and waits for it to load.
	 * @param {object} modulesURL an object with two properties:
	 * 					- modules: list of the modules which should be loaded
	 * 					- url: the URL from which the modules should be loaded
	 * @return {Promise} a Promise which will be resolved as soon as the script
	 * 						is loaded
	 */
	_loadScript(modulesURL) {
		const config = this._config;
		const modules = config.getModules(modulesURL.modules);
 
		let script = this._injectedScripts[modulesURL.url];
 
		Eif (!script) {
			script = this._document.createElement('script');
 
			script.src = modulesURL.url;
			script.async = false;
 
			script.onload = script.onreadystatechange = () => {
				Iif (
					this.readyState &&
					this.readyState !== 'complete' &&
					this.readyState !== 'load'
				) {
					return;
				}
 
				script.onload = script.onreadystatechange = null;
				script.onerror = null;
 
				modules.forEach(module => {
					Iif (module.fetch.fulfilled) {
						if (config.showWarnings) {
							console.warn(
								`Liferay AMD Loader: Module '${module.name}' ` +
									`is being fetched from\n${script.src}\n` +
									`but was already fetched from\n` +
									(module.fetch.resolved
										? module.fetch.resolution.src
										: module.fetch.rejection.script.src)
							);
						}
 
						return;
					}
 
					module.fetch.resolve(script);
				});
			};
 
			script.onerror = () => {
				script.onload = script.onreadystatechange = null;
				script.onerror = null;
 
				const error = Object.assign(
					new Error(
						`Unable to load script from URL ${modulesURL.url}`
					),
					{
						url: modulesURL.url,
						modules: modulesURL.modules,
						script,
					}
				);
 
				modules.forEach(module => module.fetch.reject(error));
			};
 
			this._injectedScripts[modulesURL.url] = script;
			this._document.head.appendChild(script);
		}
 
		return Promise.all(modules.map(module => module.fetch));
	}
}