# Laad een JavaScript-module vanaf een URL met IMPORT()

> Download een bestand met JavaScript van een adres, bewaar het in de map tmp, laad het met require en gebruik wat het exporteert; de tweede aanroep downloadt het niet opnieuw.

Framework: total5
Product: Total.js 5 (total5@0.0.19)
Language: nl
Content-SHA256: 5d6264423fa1d783fc7f6845cebe16538262810351a8b63dcc7bbae7987bf469
Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c
Sources: total5-installed@total5@0.0.19
Review: not-recorded

`IMPORT(url, [callback])` downloadt een JavaScript-bestand, slaat het op in de map `tmp` van de applicatie en geeft terug wat het bestand exporteert (`module.exports`), zoals `require()` zou doen. Met een callback is het `callback(err, module, response)`; zonder geeft `IMPORT()` een promise voor de module terug. Het adres wordt onthouden: `IMPORT()` opnieuw aanroepen met hetzelfde adres downloadt het bestand **niet** opnieuw, het laadt dat in `tmp` met require (en het bestand blijft daar tussen herstarts, maar het geheugen van "al gedownload" niet: na een herstart wordt het opnieuw gedownload).

**Dit voert code uit het netwerk uit met alle rechten van je applicatie.** Importeer alleen van een adres dat je beheert en dat je via `https` bereikt, nooit van een adres dat een gebruiker je heeft gestuurd of dat iemand anders kan wijzigen. Het bestand is een CommonJS-module. **De status van het antwoord wordt niet gecontroleerd:** een adres dat met `404` (of een willekeurige foutpagina) antwoordt, wordt opgeslagen alsof het de module is, en `require()` gooit dan een `SyntaxError` binnen de download, zodat in `total5` 0.0.19 de callback **nooit wordt aangeroepen** en de promise nooit wordt afgehandeld. Geef `IMPORT()` altijd een eigen tijdslimiet, zoals de laatste route doet, en controleer het adres voordat je ervan afhankelijk bent.

Hier komt het bestand van een route van dezelfde applicatie, zodat het voorbeeld geen netwerk nodig heeft. De route telt de downloads.

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