ForgeTotal.js 5
fr

Total.js 5

Charger un module JavaScript depuis une URL avec IMPORT()

Total.js 5 · total5@0.0.19 modulesdownloaddependencies Exécutée avec Total.js 5

IMPORT(url, [callback]) télécharge un fichier JavaScript, l'enregistre dans le dossier tmp de l'application et renvoie ce que le fichier exporte (module.exports), comme le ferait require(). Avec un callback, c'est callback(err, module, response) ; sans callback, IMPORT() renvoie une promesse du module. L'adresse est mémorisée : appeler de nouveau IMPORT() avec la même adresse ne télécharge pas le fichier de nouveau, il charge celui de tmp (et le fichier reste là entre les redémarrages, mais la mémoire de « déjà téléchargé » non : après un redémarrage il est téléchargé de nouveau).

Cela exécute du code venant du réseau avec tous les droits de votre application. N'importez que depuis une adresse que vous contrôlez et que vous atteignez en https, jamais une adresse qu'un utilisateur vous a envoyée ou que quelqu'un d'autre peut modifier. Le fichier est un module CommonJS. L'état de la réponse n'est pas vérifié : une adresse qui répond 404 (ou une page d'erreur quelconque) est enregistrée comme si c'était le module, puis require() lève une SyntaxError à l'intérieur du téléchargement, si bien que dans total5 0.0.19 le callback n'est jamais appelé et la promesse ne se règle jamais. Donnez toujours à IMPORT() une limite de temps à vous, comme le fait la dernière route, et vérifiez l'adresse avant de dépendre d'elle.

Ici le fichier vient d'une route de la même application, de sorte que l'exemple n'a pas besoin de réseau. La route compte les téléchargements.

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 });
}