ForgeTotal.js 5
en

Total.js 5

Load a JavaScript module from a URL with IMPORT()

Total.js 5 · total5@0.0.19 modulesdownloaddependencies Executed against Total.js 5

IMPORT(url, [callback]) downloads a JavaScript file, saves it in the tmp folder of the application and returns what the file exports (module.exports), as require() would. With a callback it is callback(err, module, response); without it, IMPORT() returns a promise for the module. The address is remembered: calling IMPORT() again with the same address does not download the file again, it requires the one in tmp (and the file stays there between restarts, but the memory of "already downloaded" does not: after a restart it is downloaded again).

This runs code that comes from the network with all the rights of your application. Import only from an address that you control and that you reach with https, never one that a user sent you or that anyone else can change. The file is a CommonJS module. The status of the answer is not checked: an address that answers 404 (or any error page) is saved as if it were the module, and require() then throws a SyntaxError inside the download, so in total5 0.0.19 the callback is never called and the promise never settles. Always give IMPORT() a limit of time of your own, as the last route does, and check the address before you depend on it.

Here the file comes from a route of the same application, so that the example needs no network. The route counts the downloads.

controllers/import.js
exports.install = function() {
	ROUTE('GET /lib/tax/', lib);
	ROUTE('POST /use/', use);
	ROUTE('POST /use-twice/', use_twice);
	ROUTE('POST /missing/', missing);
	ROUTE('GET /downloads/', downloads);
};

let count = 0;

function lib($) {
	count++;
	$.plain('module.exports = { vat: function(price) { return Math.round(price * 121) / 100; } };');
}

function downloads($) {
	$.json({ downloads: count });
}

function base() {
	return 'http://127.0.0.1:' + CONF.$port;
}

async function use($) {
	const tax = await IMPORT(base() + '/lib/tax/');
	$.json({ price: tax.vat(100) });
}

function use_twice($) {
	IMPORT(base() + '/lib/tax/', function(err, tax) {
		$.json({ err: err ? err.toString() : null, price: tax ? tax.vat(200) : null });
	});
}

async function missing($) {
	// the address does not exist: the answer is the 404 page of the application
	const winner = await Promise.race([
		IMPORT(base() + '/lib/missing/').then(() => 'answered', () => 'answered'),
		new Promise(resolve => setTimeout(() => resolve('no answer'), 1500))
	]);
	$.json({ result: winner });
}