first ideas for nodejs implementation
This commit is contained in:
parent
7850b0eaa9
commit
9b04a90b53
24
browser.js
24
browser.js
@ -110,15 +110,15 @@ const Mimicry = (function privateMimicryClosure () {
|
|||||||
*
|
*
|
||||||
* @param {Array<String>} dependencies - list of module names that this module depends on
|
* @param {Array<String>} dependencies - list of module names that this module depends on
|
||||||
* @param {Function} [callback] - module body that will be executed as soon all dependencies are resolved
|
* @param {Function} [callback] - module body that will be executed as soon all dependencies are resolved
|
||||||
|
* @param {HTMLScriptElement} [script] - script element launching this module (you don't need to pass it, it's automatic)
|
||||||
*/
|
*/
|
||||||
module (dependencies, callback) {
|
module (dependencies, callback, script) {
|
||||||
console.log(document.currentScript);
|
|
||||||
if (!ready) {
|
if (!ready) {
|
||||||
this._deferred.push(["module", dependencies, callback]);
|
this._deferred.push(["module", dependencies, callback, document.currentScript]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const href = getCurrentHref();
|
const href = getCurrentHref(script);
|
||||||
if (!href.length)
|
if (!href.length)
|
||||||
throw new Error("Couldn't understand module path");
|
throw new Error("Couldn't understand module path");
|
||||||
|
|
||||||
@ -139,7 +139,7 @@ const Mimicry = (function privateMimicryClosure () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (module.allDependenciesResolved)
|
if (module.allDependenciesResolved)
|
||||||
module.execute(this);
|
module.execute(this, window);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -316,7 +316,7 @@ const Mimicry = (function privateMimicryClosure () {
|
|||||||
if (callback instanceof Function) {
|
if (callback instanceof Function) {
|
||||||
const module = this._modules.get(originalName);
|
const module = this._modules.get(originalName);
|
||||||
if (module) {
|
if (module) {
|
||||||
module.addCallback(callback);
|
module.addCallback(callback, window);
|
||||||
} else {
|
} else {
|
||||||
const asset = this._loadedAssets.get(originalName);
|
const asset = this._loadedAssets.get(originalName);
|
||||||
if (asset)
|
if (asset)
|
||||||
@ -572,8 +572,12 @@ const Mimicry = (function privateMimicryClosure () {
|
|||||||
xhr.send();
|
xhr.send();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCurrentHref() {
|
function getCurrentHref(src) {
|
||||||
const script = document.currentScript || launcher;
|
let possible = document.currentScript;
|
||||||
|
if (src instanceof HTMLScriptElement)
|
||||||
|
possible = src;
|
||||||
|
|
||||||
|
const script = possible || launcher;
|
||||||
if (script instanceof HTMLScriptElement)
|
if (script instanceof HTMLScriptElement)
|
||||||
return script.attributes.src.value;
|
return script.attributes.src.value;
|
||||||
else
|
else
|
||||||
@ -583,9 +587,9 @@ const Mimicry = (function privateMimicryClosure () {
|
|||||||
function loadedFileForModule (/*Module*/requester, /*String*/fileName) {
|
function loadedFileForModule (/*Module*/requester, /*String*/fileName) {
|
||||||
const dep = this._modules.get(fileName);
|
const dep = this._modules.get(fileName);
|
||||||
if (dep)
|
if (dep)
|
||||||
dep.addCallback(requester.incrementDependency.bind(requester, this));
|
dep.addCallback(requester.incrementDependency.bind(requester, this, window), window);
|
||||||
else
|
else
|
||||||
requester.incrementDependency(this);
|
requester.incrementDependency(this, window);
|
||||||
}
|
}
|
||||||
|
|
||||||
const launcher = document.currentScript;
|
const launcher = document.currentScript;
|
||||||
|
@ -132,7 +132,7 @@
|
|||||||
" doesn't start with baseUrl " + baseUrl +
|
" doesn't start with baseUrl " + baseUrl +
|
||||||
", this is probably an error");
|
", this is probably an error");
|
||||||
else
|
else
|
||||||
href = href.slice(baseUrl.length + 1);
|
href = href.slice(baseUrl.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
let foundAmongLibs = false;
|
let foundAmongLibs = false;
|
||||||
|
17
module.js
17
module.js
@ -41,11 +41,12 @@
|
|||||||
*
|
*
|
||||||
* @param {Mimicry} mimicry - Mimicry instance that was loading this module,
|
* @param {Mimicry} mimicry - Mimicry instance that was loading this module,
|
||||||
* it is needed for calling "execute" if the dependencies are resolved
|
* it is needed for calling "execute" if the dependencies are resolved
|
||||||
|
* @param {any} global - a global object for current platform
|
||||||
* */
|
* */
|
||||||
incrementDependency (mimicry) {
|
incrementDependency (mimicry, global) {
|
||||||
++this._loaded
|
++this._loaded
|
||||||
if (this.allDependenciesResolved)
|
if (this.allDependenciesResolved)
|
||||||
this.execute(mimicry);
|
this.execute(mimicry, global);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* If the modules is executed - calls the callback immediately
|
* If the modules is executed - calls the callback immediately
|
||||||
@ -57,10 +58,11 @@
|
|||||||
* second: the value of this module
|
* second: the value of this module
|
||||||
*
|
*
|
||||||
* @param {Function} callback - a callback to call
|
* @param {Function} callback - a callback to call
|
||||||
|
* @param {any} global - a global object for current platform
|
||||||
* */
|
* */
|
||||||
addCallback (/*Function*/callback) {
|
addCallback (/*Function*/callback, global) {
|
||||||
if (this._executed)
|
if (this._executed)
|
||||||
callback.call(null, window, this._value);
|
callback.call(null, global, this._value);
|
||||||
else
|
else
|
||||||
this._callbacks.push(callback);
|
this._callbacks.push(callback);
|
||||||
}
|
}
|
||||||
@ -70,8 +72,9 @@
|
|||||||
*
|
*
|
||||||
* @param {Mimicry} mimicry - an instance of Mimicry that was loading this module
|
* @param {Mimicry} mimicry - an instance of Mimicry that was loading this module
|
||||||
* It is needed to acquire values of dependencies
|
* It is needed to acquire values of dependencies
|
||||||
|
* @param {any} global - a global object for current platform
|
||||||
* */
|
* */
|
||||||
execute (mimicry) {
|
execute (mimicry, global) {
|
||||||
if (this.executed)
|
if (this.executed)
|
||||||
throw new Error("An attempt to execute a module for the second time");
|
throw new Error("An attempt to execute a module for the second time");
|
||||||
|
|
||||||
@ -81,7 +84,7 @@
|
|||||||
const name = this._dependencies[i].name;
|
const name = this._dependencies[i].name;
|
||||||
values.push(mimicry.getModule(name) || mimicry.getAsset(name));
|
values.push(mimicry.getModule(name) || mimicry.getAsset(name));
|
||||||
}
|
}
|
||||||
this._value = this._body.call(null, window, values);
|
this._value = this._body.call(null, global, values);
|
||||||
} else {
|
} else {
|
||||||
this._value = null;
|
this._value = null;
|
||||||
}
|
}
|
||||||
@ -91,7 +94,7 @@
|
|||||||
delete this._dependencies;
|
delete this._dependencies;
|
||||||
|
|
||||||
for (let i = 0; i < callbacks.length; ++i)
|
for (let i = 0; i < callbacks.length; ++i)
|
||||||
callbacks[i].call(null, window, this._value);
|
callbacks[i].call(null, global, this._value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
531
node.js
Normal file
531
node.js
Normal file
@ -0,0 +1,531 @@
|
|||||||
|
"use strict";
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const {BasicError, LoadError, FileError} = require("./errors")
|
||||||
|
const LoadingFile = require("./loadingFile");
|
||||||
|
const Queue = require("./queue");
|
||||||
|
const Dependency = require("./dependency");
|
||||||
|
const Type = Dependency.Type;
|
||||||
|
const Module = require("./module");
|
||||||
|
class Mimicry {
|
||||||
|
/**
|
||||||
|
* Creates an instance of the Mimicry.
|
||||||
|
*
|
||||||
|
* @param {Object} [config] - configuration of the Mimicry.
|
||||||
|
* @param {Number} [config.maxParallelLoadings] - amount of files that are loaded in parallel.
|
||||||
|
* @param {String} [config.baseUrl] - URL prefix that will be added to every.
|
||||||
|
* @param {String} [config.seed] - request optional component allowing to drop user cached files.
|
||||||
|
*/
|
||||||
|
constructor (config) {
|
||||||
|
instances.push(this);
|
||||||
|
|
||||||
|
this._queue = new Queue();
|
||||||
|
this._loadedFiles = new Set();
|
||||||
|
this._config = Object.create(null);
|
||||||
|
this._loadingFiles = new Map();
|
||||||
|
this._plannedFiles = Object.create(null);
|
||||||
|
this._modules = new Map();
|
||||||
|
this._typePaths = new Map();
|
||||||
|
this._loadedAssets = new Map();
|
||||||
|
this._libs = new Map();
|
||||||
|
this._errors = new Map();
|
||||||
|
this._moduleErrors = [];
|
||||||
|
this._errorHandlers = [];
|
||||||
|
this._progressHandlers = [];
|
||||||
|
|
||||||
|
Object.assign(this._config, defaultOptions, config);
|
||||||
|
|
||||||
|
this._baseUrl = this._config.baseUrl;
|
||||||
|
if (this._baseUrl && !this._baseUrl.endsWith("/"))
|
||||||
|
this._baseUrl += "/";
|
||||||
|
|
||||||
|
this._globalErrorHandler = onGlobalError.bind(this);
|
||||||
|
//window.addEventListener("error", this._globalErrorHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finalizes Mimicry, clears as much memory as it can, forgets all the handlers and contexts
|
||||||
|
* */
|
||||||
|
destructor () {
|
||||||
|
//window.off("error", this._globalErrorHandler);
|
||||||
|
|
||||||
|
const index = instances.indexOf(this);
|
||||||
|
instances.splice(index, 1);
|
||||||
|
|
||||||
|
delete this._queue;
|
||||||
|
delete this._loadedFiles;
|
||||||
|
delete this._config;
|
||||||
|
delete this._loadingFiles;
|
||||||
|
delete this._plannedFiles;
|
||||||
|
delete this._modules;
|
||||||
|
delete this._typePaths;
|
||||||
|
delete this._loadedAssets;
|
||||||
|
delete this._libs;
|
||||||
|
delete this._errors;
|
||||||
|
delete this._moduleErrors;
|
||||||
|
delete this._errorHandlers;
|
||||||
|
delete this._progressHandlers;
|
||||||
|
delete this._globalErrorHandler;
|
||||||
|
delete this._baseUrl;
|
||||||
|
|
||||||
|
this.destroyed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a file, calls the callback if it has loaded successfully,
|
||||||
|
* calls error callback if there was any sort of error
|
||||||
|
*
|
||||||
|
* @param {String} path - path to the module
|
||||||
|
* @param {Function} [callback=contentType] - a callback that is called after module is loaded
|
||||||
|
* @param {Function} [error=contentType] - a callback that is called if there was an error
|
||||||
|
* @param {Mimicry.Type} [contentType=Mimicry.Type.js] - type of the content to load
|
||||||
|
*/
|
||||||
|
load (path, callback, error, contentType) {
|
||||||
|
if (!(error instanceof Function) && contentType === undefined) {
|
||||||
|
contentType = error;
|
||||||
|
error = undefined;
|
||||||
|
}
|
||||||
|
if (!(callback instanceof Function) && contentType === undefined) {
|
||||||
|
contentType = callback;
|
||||||
|
callback = undefined;
|
||||||
|
}
|
||||||
|
if (!contentType)
|
||||||
|
contentType = Type.js;
|
||||||
|
|
||||||
|
scheduleLoad.call(this,
|
||||||
|
Dependency.refinePath(path, contentType, this._baseUrl, this._typePaths, this._libs),
|
||||||
|
callback, error, contentType, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Declares a module.
|
||||||
|
* The mainstream way to use Mimicry is to declare modules.
|
||||||
|
* It's best If you declare one module per file.
|
||||||
|
*
|
||||||
|
* The best way to export anything from the module is to return it from the callback
|
||||||
|
*
|
||||||
|
* @param {Array<String>} dependencies - list of module names that this module depends on
|
||||||
|
* @param {Function} [callback] - module body that will be executed as soon all dependencies are resolved
|
||||||
|
*/
|
||||||
|
module (dependencies, callback) {
|
||||||
|
const href = getCurrentHref();
|
||||||
|
if (!href.length)
|
||||||
|
throw new Error("Couldn't understand module path");
|
||||||
|
|
||||||
|
const moduleName = Dependency.nameFromHref(href, this._baseUrl, this._typePaths, this._libs);
|
||||||
|
if (this._modules.has(moduleName))
|
||||||
|
throw new Error("An attempt to declare more than one module per file (" + moduleName + ")");
|
||||||
|
|
||||||
|
const {deps, body} = Dependency.refineModuleArguments(dependencies, callback);
|
||||||
|
const module = new Module(deps, body);
|
||||||
|
this._modules.set(moduleName, module);
|
||||||
|
|
||||||
|
for (let i = 0; i < deps.length; ++i) {
|
||||||
|
const element = deps[i];
|
||||||
|
const contentType = element.contentType;
|
||||||
|
const elName = element.name;
|
||||||
|
|
||||||
|
this.load(elName, loadedFileForModule.bind(this, module, elName), contentType);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (module.allDependenciesResolved)
|
||||||
|
module.execute(this, global);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Synchronously returns the module value if it was
|
||||||
|
* already loaded and executed, returns undefined otherwise
|
||||||
|
* */
|
||||||
|
getModule(/*String*/moduleName) {
|
||||||
|
const module = this._modules.get(moduleName);
|
||||||
|
if (module && module.executed)
|
||||||
|
return module.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Synchronously returns the asses if it was already loaded, returns undefined otherwise
|
||||||
|
* */
|
||||||
|
getAsset(/*String*/assetName) {
|
||||||
|
const asset = this._loadedAssets.get(assetName);
|
||||||
|
if (asset)
|
||||||
|
return asset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If you wish to keep all files of some types in a designated folder of your project
|
||||||
|
* you can declare it using this function.
|
||||||
|
*
|
||||||
|
* Say, you want to have all JSON files in "json" folder, and all CSS files in "styles/css" folder.
|
||||||
|
* After calling "mimicry.setTypePath(Mimicry.Type.json, 'json')" and
|
||||||
|
* "mimicry.setTypePath(Mimicry.Type.css, 'styles/css')" you can access files from those folders
|
||||||
|
* in a following manner
|
||||||
|
*
|
||||||
|
* "mimicry.load('json/config/main', () => {}, Mimicry.Type.json)" changes to
|
||||||
|
* "mimicry.load('config/main', () => {}, Mimicry.Type.json)", and
|
||||||
|
*
|
||||||
|
* "mimicry.load('styles/css/basic', () => {}, Mimicry.Type.css)" to
|
||||||
|
* "mimicry.load('basic', () => {}, Mimicry.Type.css)"
|
||||||
|
* */
|
||||||
|
setTypePath (/*Type*/type, /*String*/path) {
|
||||||
|
if (path && !path.endsWith("/"))
|
||||||
|
path += "/";
|
||||||
|
|
||||||
|
this._typePaths.set(type, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* You might want to include other projects in your project. I will call those imported subprojects libraries
|
||||||
|
* In mimicry there is a way to hide actual path behind library name.
|
||||||
|
*
|
||||||
|
* Say you included a library called "flame", and placed in "libs/external/flame".
|
||||||
|
* After calling "mimicry.setLibPath('flame', 'libs/external/flame')" you can access files from those libraries
|
||||||
|
* in a following manner
|
||||||
|
*
|
||||||
|
* "mimicry.load('libs/external/flame/index', () => {})" changes to
|
||||||
|
* "mimicry.load('@flame/index', () => {})"
|
||||||
|
* */
|
||||||
|
setLibPath (/*String*/libraryName, /*String*/libraryPath) {
|
||||||
|
const path = this._libs.get(libraryName);
|
||||||
|
if (path && path !== libraryPath)
|
||||||
|
throw new Error("Mimicry error: library " + libraryName + " already had a path " + path +
|
||||||
|
", assigning new path " + libraryPath + " would probably break everything");
|
||||||
|
|
||||||
|
this._libs.set(libraryName, libraryPath);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Adds a handler for you to handle errors that this instance of mimicry
|
||||||
|
* faces loading and evaluating files.
|
||||||
|
*
|
||||||
|
* These handlers get called after (if there was any) error callbacks passed to load operations.
|
||||||
|
*
|
||||||
|
* @param {Function} handler - a handler that would be called in case of error
|
||||||
|
*
|
||||||
|
* Handler is called with a single argument of error, which can one of the following types:
|
||||||
|
* - Mimicry.FileError - if there was an error on file evaluation
|
||||||
|
* - Mimicry.LoadError - if mimicry could not load a file
|
||||||
|
* */
|
||||||
|
addErrorHandler (handler) {
|
||||||
|
this._errorHandlers.push(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method provides you information about the progress of your loads.
|
||||||
|
* Sometimes when you load lots of files in bulk you wish to show a progress indicator.
|
||||||
|
*
|
||||||
|
* @param {Function} handler - a handler which is called when the progress changes
|
||||||
|
* Passed handler is called with following arguments:
|
||||||
|
* {Number} loaded - how many files mimicry have loaded so far
|
||||||
|
* {Number} pending - how many files are currently loading or in a queue
|
||||||
|
* {Number} total - how many files does mimicry even know about
|
||||||
|
* */
|
||||||
|
addProgressHandler (handler) {
|
||||||
|
this._progressHandlers.push(handler);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* If you use Mimicry in a script file included right after mimicry
|
||||||
|
* it might not be able to work yet: it doesn't yet have some classes for normal work.
|
||||||
|
* In this "unready" state you can not
|
||||||
|
* - access Mimicry.FileError nad Mimicry.LoadError classes
|
||||||
|
* - access Mimicry.Type enum.
|
||||||
|
*
|
||||||
|
* You can, however, perform default (meaning Mimicry.type.js) loads, declare modules,
|
||||||
|
* set up paths, and subscribe to handlers.
|
||||||
|
*
|
||||||
|
* @returns {Boolean} - if the instance is ready to be used
|
||||||
|
* */
|
||||||
|
get ready () {return true;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Number} - amount of files that are currently loading or in a queue
|
||||||
|
* */
|
||||||
|
get pendingFilesAmount () {return this._loadingFiles.size + this._queue.length;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Number} - amount of files mimicry have loaded until this moment
|
||||||
|
* */
|
||||||
|
get loadedFilesAmount () {return this._loadedFiles.size;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Object} - default mimicry options object
|
||||||
|
* */
|
||||||
|
static get defaultOptions () {return defaultOptions;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If you use Mimicry in a script file included right after mimicry
|
||||||
|
* it might not be able to work yet: it doesn't yet have some classes for normal work.
|
||||||
|
* In this "unready" state you can not
|
||||||
|
* - access Mimicry.FileError nad Mimicry.LoadError classes
|
||||||
|
* - access Mimicry.Type enum.
|
||||||
|
*
|
||||||
|
* You can, however, perform default (meaning Mimicry.type.js) loads, declare modules,
|
||||||
|
* set up paths, and subscribe to handlers.
|
||||||
|
*
|
||||||
|
* This state is on the static level: once all necessary files are loaded all mimicry instances are
|
||||||
|
* ready and don't need to be waited on
|
||||||
|
*
|
||||||
|
* @returns {Boolean} - if the Mimicry system is ready to be used
|
||||||
|
* */
|
||||||
|
static get ready () {return true;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normally mimicry loads .js files, but you can also load other stuff like json, or css, or binary
|
||||||
|
* I expect you to pass values from this enum to specify what exactly you are loading if it is not a
|
||||||
|
* JavaScript file
|
||||||
|
*
|
||||||
|
* @returns {Mimicry.Type} - type of content
|
||||||
|
* */
|
||||||
|
static get Type () {return Type;}
|
||||||
|
static get FileError() {return FileError;}
|
||||||
|
static get LoadError() {return LoadError;}
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultOptions = {
|
||||||
|
maxParallelLoadings: 10,
|
||||||
|
baseUrl: "",
|
||||||
|
seed: ""
|
||||||
|
};
|
||||||
|
Object.freeze(defaultOptions)
|
||||||
|
|
||||||
|
function callCallback(/*Function*/callback, /*String*/originalName) {
|
||||||
|
if (callback instanceof Function) {
|
||||||
|
const module = this._modules.get(originalName);
|
||||||
|
if (module) {
|
||||||
|
module.addCallback(callback, global);
|
||||||
|
} else {
|
||||||
|
const asset = this._loadedAssets.get(originalName);
|
||||||
|
if (asset)
|
||||||
|
callback(asset);
|
||||||
|
else
|
||||||
|
callback(global);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {String} path
|
||||||
|
* @param {Function} callback
|
||||||
|
* @param {Function} error
|
||||||
|
* @param {Type} contentType
|
||||||
|
* @param {String} originalName
|
||||||
|
* */
|
||||||
|
function scheduleLoad (path, callback, error, contentType, originalName) {
|
||||||
|
if (this._loadedFiles.has(path))
|
||||||
|
return callCallback.call(this, callback, originalName);
|
||||||
|
|
||||||
|
let loadingFile = this._loadingFiles.get(path);
|
||||||
|
if (loadingFile === undefined)
|
||||||
|
loadingFile = this._plannedFiles[path];
|
||||||
|
|
||||||
|
if (loadingFile) {
|
||||||
|
Dependency.checkContentType(loadingFile.contentType, contentType, path);
|
||||||
|
loadingFile.addSuccessHandler(callback);
|
||||||
|
loadingFile.addErrorHandler(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
loadingFile = new LoadingFile(contentType, originalName, callback, error);
|
||||||
|
if (this._loadingFiles.size < this._config.maxParallelLoadings) {
|
||||||
|
executeLoad.call(this, path, loadingFile);
|
||||||
|
} else {
|
||||||
|
this._queue.push(path);
|
||||||
|
this._plannedFiles[path] = loadingFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyProgressSubscribers.call(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
function executeLoad (/*String*/path, /*LoadingFile*/loadingFile) {
|
||||||
|
this._loadingFiles.set(path, loadingFile);
|
||||||
|
|
||||||
|
const boundLoad = onLoaded.bind(this, path);
|
||||||
|
const boundError = onError.bind(this, path);
|
||||||
|
switch (loadingFile.contentType) {
|
||||||
|
case Type.js:
|
||||||
|
try {
|
||||||
|
require("./" + path);
|
||||||
|
this._loadedFiles.add(path);
|
||||||
|
setTimeout(boundLoad, 0);
|
||||||
|
} catch (e) {
|
||||||
|
this._errors.set(path, e);
|
||||||
|
setTimeout(boundError, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Type.css:
|
||||||
|
setTimeout(boundLoad, 0); //todo just for now, don't know what to do yet with css here
|
||||||
|
//getStylesheetWithTag(path, boundLoad, boundError, this._config.seed);
|
||||||
|
break;
|
||||||
|
case Type.json:
|
||||||
|
//getByXHR(path, boundLoad, boundError, "json", this._config.seed);
|
||||||
|
break;
|
||||||
|
case Type.binary:
|
||||||
|
//getByXHR(path, boundLoad, boundError, "arraybuffer", this._config.seed);
|
||||||
|
break;
|
||||||
|
case Type.text:
|
||||||
|
//getByXHR(path, boundLoad, boundError, "text", this._config.seed);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function notifyProgressSubscribers() {
|
||||||
|
const pending = this.pendingFilesAmount;
|
||||||
|
const loaded = this.loadedFilesAmount;
|
||||||
|
for (let i = 0; i < this._progressHandlers.length; ++i) {
|
||||||
|
const handler = this._progressHandlers[i];
|
||||||
|
handler(loaded, pending, loaded + pending);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onLoaded(/*String*/path, /*HTMLScriptElement*/event) {
|
||||||
|
if (this._moduleErrors.length)
|
||||||
|
return onModuleError.call(this, path, event);
|
||||||
|
|
||||||
|
const loading = this._loadingFiles.get(path);
|
||||||
|
this._loadedFiles.add(path);
|
||||||
|
switch (loading.contentType) {
|
||||||
|
case Type.json:
|
||||||
|
case Type.binary:
|
||||||
|
case Type.text:
|
||||||
|
this._loadedAssets.set(loading.originalName, event.target.response);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
loading.callSuccessHandlers(callCallback, this);
|
||||||
|
cleanUp.call(this, path);
|
||||||
|
checkNextElement.call(this);
|
||||||
|
notifyProgressSubscribers.call(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onError (/*String*/path) {
|
||||||
|
const loading = this._loadingFiles.get(path);
|
||||||
|
let error = this._errors.get(path);
|
||||||
|
if (!(error instanceof BasicError))
|
||||||
|
error = new LoadError(path, loading.originalName);
|
||||||
|
|
||||||
|
loading.callErrorHandlers(error);
|
||||||
|
for (let i = 0; i < this._errorHandlers.length; ++i)
|
||||||
|
this._errorHandlers[i](error);
|
||||||
|
|
||||||
|
cleanUp.call(this, path);
|
||||||
|
checkNextElement.call(this);
|
||||||
|
notifyProgressSubscribers.call(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onModuleError (/*String*/path) {
|
||||||
|
for (let i = 0; i < this._moduleErrors.length; ++i) {
|
||||||
|
const error = this._moduleErrors[i];
|
||||||
|
error.path = path;
|
||||||
|
|
||||||
|
for (let i = 0; i < this._errorHandlers.length; ++i)
|
||||||
|
this._errorHandlers[i](error)
|
||||||
|
}
|
||||||
|
this._moduleErrors = [];
|
||||||
|
cleanUp.call(this, path);
|
||||||
|
checkNextElement.call(this);
|
||||||
|
notifyProgressSubscribers.call(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanUp (/*String*/path) {
|
||||||
|
const loading = this._loadingFiles.get(path);
|
||||||
|
this._loadingFiles.delete(path);
|
||||||
|
this._errors.delete(path);
|
||||||
|
switch (loading.contentType) {
|
||||||
|
case Type.js:
|
||||||
|
//todo don't know yet
|
||||||
|
break;
|
||||||
|
case Type.css:
|
||||||
|
//todo don't know yet
|
||||||
|
break;
|
||||||
|
case Type.json:
|
||||||
|
case Type.binary:
|
||||||
|
case Type.text:
|
||||||
|
//todo dont know yet
|
||||||
|
break
|
||||||
|
}
|
||||||
|
loading.destructor();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onGlobalError (event, url, line, col, errorObj) {
|
||||||
|
let message;
|
||||||
|
if (event instanceof ErrorEvent) {
|
||||||
|
url = event.filename;
|
||||||
|
line = event.lineno;
|
||||||
|
col = event.colno;
|
||||||
|
errorObj = event.error;
|
||||||
|
message = event.message;
|
||||||
|
} else {
|
||||||
|
message = event;
|
||||||
|
}
|
||||||
|
if (url && url.indexOf(location.origin) === 0)
|
||||||
|
url = url.slice(location.origin.length);
|
||||||
|
|
||||||
|
if (!setFileError(url, message, line, col, errorObj)) {
|
||||||
|
let href = getCurrentHref();
|
||||||
|
const index = url.lastIndexOf(href);
|
||||||
|
if (href.length && index === url.length - href.length)
|
||||||
|
setFileError(href, message, line, col, errorObj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setFileError(name, message, line, col, errorObj) {
|
||||||
|
let result = true;
|
||||||
|
let loading = this._loadingFiles.get(name);
|
||||||
|
if (loading instanceof LoadingFile)
|
||||||
|
this._errors.set(name, new FileError(name, loading.originalName, message, line, col, errorObj));
|
||||||
|
else
|
||||||
|
result = false;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkNextElement () {
|
||||||
|
while (!this._queue.empty && (this._loadingFiles.size < this._config.maxParallelLoadings)) {
|
||||||
|
const path = this._queue.pop();
|
||||||
|
const loadingFile = this._plannedFiles[path];
|
||||||
|
delete this._plannedFiles[path];
|
||||||
|
executeLoad.call(this, path, loadingFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCurrentHref() {
|
||||||
|
return path.relative(__dirname, _getCallerFile());
|
||||||
|
}
|
||||||
|
|
||||||
|
function _getCallerFile() {
|
||||||
|
let caller;
|
||||||
|
try {
|
||||||
|
const err = new Catcher();
|
||||||
|
let current = err.stack.shift().getFileName();
|
||||||
|
|
||||||
|
while (err.stack.length) {
|
||||||
|
caller = err.stack.shift().getFileName();
|
||||||
|
|
||||||
|
if (current !== caller)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
|
return caller;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Catcher {
|
||||||
|
constructor(...args) {
|
||||||
|
const err = new Error(args);
|
||||||
|
Error.prepareStackTrace = Catcher.prepareStackTrace;
|
||||||
|
this._stack = err.stack;
|
||||||
|
Error.prepareStackTrace = defaultPrepareStackTrace;
|
||||||
|
}
|
||||||
|
get stack () {return this._stack;}
|
||||||
|
static prepareStackTrace (err, stack) {return stack;}
|
||||||
|
}
|
||||||
|
const defaultPrepareStackTrace = Error.prepareStackTrace;
|
||||||
|
|
||||||
|
function loadedFileForModule (/*Module*/requester, /*String*/fileName) {
|
||||||
|
const dep = this._modules.get(fileName);
|
||||||
|
if (dep)
|
||||||
|
dep.addCallback(requester.incrementDependency.bind(requester, this, global), global);
|
||||||
|
else
|
||||||
|
requester.incrementDependency(this, global);
|
||||||
|
}
|
||||||
|
|
||||||
|
const instances = [];
|
||||||
|
|
||||||
|
module.exports = Mimicry;
|
@ -5,7 +5,7 @@
|
|||||||
<title>Title</title>
|
<title>Title</title>
|
||||||
|
|
||||||
<script src="../browser.js"></script>
|
<script src="../browser.js"></script>
|
||||||
<script src="index.js" defer></script>
|
<script src="main.js" defer></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
Initial page
|
Initial page
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
const Mimicry = require("../node");
|
||||||
|
|
||||||
test();
|
test();
|
||||||
function test () {
|
function test () {
|
||||||
if (!Mimicry) {
|
if (!Mimicry) {
|
||||||
@ -12,8 +14,11 @@ function test () {
|
|||||||
|
|
||||||
let mimicry;
|
let mimicry;
|
||||||
try {
|
try {
|
||||||
mimicry = new Mimicry();
|
mimicry = new Mimicry({
|
||||||
window.mimicry = mimicry;
|
baseUrl: "test"
|
||||||
|
});
|
||||||
|
global.mimicry = mimicry;
|
||||||
|
global.Mimicry = Mimicry;
|
||||||
log("Mimicry was successfully instantiated");
|
log("Mimicry was successfully instantiated");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log("Error instantiating Mimicry");
|
log("Error instantiating Mimicry");
|
||||||
@ -37,8 +42,5 @@ function test () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function log (message) {
|
function log (message) {
|
||||||
const node = document.createTextNode(message);
|
console.log(message);
|
||||||
const br = document.createElement("br");
|
|
||||||
document.body.appendChild(node);
|
|
||||||
document.body.appendChild(br);
|
|
||||||
}
|
}
|
@ -4,7 +4,7 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Title</title>
|
<title>Title</title>
|
||||||
|
|
||||||
<script src="../browser.js" data-main="index.js"></script>
|
<script src="../browser.js" data-main="main.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
Initial page
|
Initial page
|
||||||
|
44
test/main.js
Normal file
44
test/main.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
test();
|
||||||
|
function test () {
|
||||||
|
if (!Mimicry) {
|
||||||
|
log("Mimicry class was not loaded");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log("Mimicry class is loaded");
|
||||||
|
log("Mimicry ready: " + Mimicry.ready);
|
||||||
|
|
||||||
|
let mimicry;
|
||||||
|
try {
|
||||||
|
mimicry = new Mimicry();
|
||||||
|
window.mimicry = mimicry;
|
||||||
|
log("Mimicry was successfully instantiated");
|
||||||
|
} catch (e) {
|
||||||
|
log("Error instantiating Mimicry");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
mimicry.module(["module"], function (global, [module]) {
|
||||||
|
log("Mimicry empty module successfully resolved");
|
||||||
|
log("The background now is supposed to be bluish if you're testing in browser")
|
||||||
|
if (module === true)
|
||||||
|
log("Value returned from additional module is correct");
|
||||||
|
else
|
||||||
|
log("Value returned from additional module is \"" + module + "\", which is incorrect");
|
||||||
|
});
|
||||||
|
log("Successfully launched Mimicry empty module");
|
||||||
|
} catch (e) {
|
||||||
|
log("Error launching Mimicry empty module");
|
||||||
|
//return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function log (message) {
|
||||||
|
const node = document.createTextNode(message);
|
||||||
|
const br = document.createElement("br");
|
||||||
|
document.body.appendChild(node);
|
||||||
|
document.body.appendChild(br);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user