Hoe kan ik een JavaScript-bestand opnemen in een ander JavaScript-bestand?

Is er in JavaScript iets vergelijkbaars als @import in CSS waarmee je een JavaScript bestand in een ander JavaScript bestand kunt opnemen?

Oplossing

De oude versies van JavaScript hadden geen import, include, of require, dus zijn er veel verschillende benaderingen voor dit probleem ontwikkeld. Maar sinds 2015 (ES6) heeft JavaScript de ES6 modules standaard om modules te importeren in Node.js, die ook wordt ondersteund door de meeste moderne browsers. Voor compatibiliteit met oudere browsers kunnen build en/of transpilation tools worden gebruikt.

ES6 modules

ECMAScript (ES6) modules worden ondersteund in Node.js sinds v8.5, met de --experimental-modules vlag. Alle betrokken bestanden moeten de .mjs extensie hebben.

// module.mjs
export function hello() {
  return "Hello";
}
// main.mjs
import { hello } from 'module'; // or './module'
let val = hello();  // val is "Hello";

ECMAScript modules in browsers

Browsers hebben ondersteuning voor het direct laden van ECMAScript modules (geen tools zoals Webpack nodig) sinds Safari 10.1, Chrome 61, Firefox 60, en Edge 16. Controleer de huidige ondersteuning op caniuse.

<script type="module">
  import { hello } from './hello.mjs';
  hello('world');
</script>
// hello.mjs
export function hello(text) {
  const div = document.createElement('div');
  div.textContent = `Hello ${text}`;
  document.body.appendChild(div);
}

Lees meer op https://jakearchibald.com/2017/es-modules-in-browsers/

Dynamische import in browsers

Dynamische imports laten het script andere scripts laden wanneer nodig:

<script type="module">
  import('hello.mjs').then(module => {
      module.hello('world');
    });
</script>

Lees meer op https://developers.google.com/web/updates/2017/11/dynamic-import

Node.js require

De oude stijl van het importeren van modules, nog steeds veel gebruikt in Node.js, is het module.exports/require systeem.

// mymodule.js
module.exports = {
   hello: function() {
      return "Hello";
   }
}
// server.js
const myModule = require('./mymodule');
let val = myModule.hello(); // val is "Hello"   

Er zijn andere manieren voor JavaScript om externe JavaScript inhoud in browsers op te nemen die geen voorbewerking vereisen.

AJAX laden

Je zou een extra script kunnen laden met een AJAX oproep en dan eval gebruiken om het uit te voeren. Dit is de meest eenvoudige manier, maar het is beperkt tot jouw domein vanwege het JavaScript zandbak beveiligingsmodel. Het gebruik van eval opent ook de deur naar bugs, hacks en veiligheidsproblemen.

Fetch Laden

Net als bij Dynamic Imports kun je een of meer scripts laden met een fetch call met behulp van beloftes om de volgorde van uitvoering voor script afhankelijkheden te regelen met behulp van de Fetch Inject library:

fetchInject([
  'https://cdn.jsdelivr.net/momentjs/2.17.1/moment.min.js'
]).then(() => {
  console.log(`Finish in less than ${moment().endOf('year').fromNow(true)}`)
})

jQuery laden

De jQuery bibliotheek biedt laadfunctionaliteit in één regel:

$.getScript("my_lovely_script.js", function() {
   alert("Script loaded but not necessarily executed.");
});

Dynamisch Script Laden

Je zou een script tag met de script URL in de HTML kunnen toevoegen. Om de overhead van jQuery te vermijden, is dit een ideale oplossing. Het script kan zelfs op een andere server staan. Bovendien evalueert de browser de code. De <script> tag kan worden geïnjecteerd in de webpagina , of net voor de afsluitende tag worden ingevoegd. Hier is een voorbeeld van hoe dit zou kunnen werken:

function dynamicallyLoadScript(url) {
    var script = document.createElement("script");  // create a script DOM node
    script.src = url;  // set its src to the provided URL

    document.head.appendChild(script);  // add it to the end of the head section of the page (could change 'head' to 'body' to add it to the end of the body section instead)
}

Deze functie voegt een nieuwe <script> tag toe aan het einde van de head sectie van de pagina, waarbij het src attribuut is ingesteld op de URL die als eerste parameter aan de functie is meegegeven. Beide oplossingen worden besproken en geïllustreerd in JavaScript Madness: Dynamic Script Loading.

Detecteren wanneer het script is uitgevoerd

Nu is er een groot probleem waar je rekening mee moet houden. Dit doen impliceert dat je de code op afstand laadt. Moderne web browsers zullen het bestand laden en je huidige script blijven uitvoeren omdat ze alles asynchroon laden om de performance te verbeteren. (Dit geldt zowel voor de jQuery methode als voor de handmatige dynamische script laad methode). Het betekent dat als je deze trucs direct gebruikt, je niet in staat zult zijn om je nieuw geladen code te gebruiken de volgende regel nadat je gevraagd hebt om het te laden, omdat het nog steeds aan het laden zal zijn. Bijvoorbeeld: my_lovely_script.js bevat MySuperObject:

var js = document.createElement("script");

js.type = "text/javascript";
js.src = jsFilePath;

document.body.appendChild(js);

var s = new MySuperObject();

Error : MySuperObject is undefined

Dan herlaad je de pagina door F5 te drukken. En het werkt! Verwarrend... En wat moet ik er aan doen?? Wel, je kan de hack gebruiken die de auteur suggereert in de link die ik je gaf. In het kort, voor mensen met haast, gebruikt hij een event om een callback functie uit te voeren wanneer het script geladen wordt. Dus je kunt alle code die gebruik maakt van de remote library in de callback functie zetten. Bijvoorbeeld:

function loadScript(url, callback)
{
    // Adding the script tag to the head as suggested before
    var head = document.head;
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = url;

    // Then bind the event to the callback function.
    // There are several events for cross browser compatibility.
    script.onreadystatechange = callback;
    script.onload = callback;

    // Fire the loading
    head.appendChild(script);
}

Dan schrijf je de code die je wilt gebruiken NA het laden van het script in een lambda functie:

var myPrettyCode = function() {
   // Here, do whatever you want
};

Dan voer je dat alles uit:

loadScript("my_lovely_script.js", myPrettyCode);

Merk op dat het script kan worden uitgevoerd nadat het DOM is geladen, of ervoor, afhankelijk van de browser en of je de regel script.async = false; hebt opgenomen. Er is een geweldig artikel over Javascript laden in het algemeen die dit bespreekt.

Broncode samenvoegen/voorbewerken

Zoals bovenaan dit antwoord vermeld, gebruiken veel ontwikkelaars build/transpilation tool(s) zoals Parcel, Webpack, of Babel in hun projecten, waardoor ze de nieuwste JavaScript syntax kunnen gebruiken, achterwaartse compatibiliteit kunnen bieden voor oudere browsers, bestanden kunnen combineren, minifyen, code splitsen kunnen uitvoeren, enz.

Commentaren (31)

Het is mogelijk om dynamisch een JavaScript-tag te genereren en deze toe te voegen aan een HTML-document van binnenuit andere JavaScript-code. Hierdoor wordt een gericht JavaScript-bestand geladen.

function includeJs(jsFilePath) {
    var js = document.createElement("script");

    js.type = "text/javascript";
    js.src = jsFilePath;

    document.body.appendChild(js);
}

includeJs("/path/to/some/file.js");
Commentaren (13)

Misschien kun je deze functie gebruiken die ik vond op deze pagina How do I include a JavaScript file in a JavaScript file?:

function include(filename)
{
    var head = document.getElementsByTagName('head')[0];

    var script = document.createElement('script');
    script.src = filename;
    script.type = 'text/javascript';

    head.appendChild(script)
}
Commentaren (7)