file appeler une - Comment inclure un fichier JavaScript dans un autre fichier JavaScript?




15 Answers

Si quelqu'un recherche quelque chose de plus avancé, essayez RequireJS . Vous obtiendrez des avantages supplémentaires, tels que la gestion des dépendances, une meilleure simultanéité et d'éviter la duplication (c'est-à-dire, récupérer un script plusieurs fois).

Vous pouvez écrire vos fichiers JavaScript dans des "modules", puis les référencer en tant que dépendances dans d'autres scripts. Ou vous pouvez utiliser RequireJS en tant que solution simple "allez chercher ce script".

Exemple:

Définissez les dépendances en tant que modules:

un-dependency.js

define(['lib/dependency1', 'lib/dependency2'], function (d1, d2) {

     //Your actual script goes here.   
     //The dependent scripts will be fetched if necessary.

     return libraryObject;  //For example, jQuery object
});

implementation.js est votre fichier JavaScript "principal" qui dépend de some-dependency.js

require(['some-dependency'], function(dependency) {

    //Your script goes here
    //some-dependency.js is fetched.   
    //Then your script is executed
});

Extrait du fichier README de GitHub :

RequireJS charge des fichiers JavaScript simples ainsi que des modules plus définis. Il est optimisé pour une utilisation dans le navigateur, y compris dans un Web Worker, mais peut être utilisé dans d'autres environnements JavaScript, tels que Rhino et Node. Il implémente l'API de module asynchrone.

RequireJS utilise des balises de script simples pour charger des modules / fichiers, ce qui devrait permettre un débogage facile. Il peut être utilisé simplement pour charger des fichiers JavaScript existants, afin que vous puissiez l'ajouter à votre projet existant sans avoir à réécrire vos fichiers JavaScript.

...

fonction externe include

Y a-t-il quelque chose dans JavaScript similaire à @import dans CSS qui vous permet d'inclure un fichier JavaScript dans un autre fichier JavaScript?




Une autre façon, qui à mon avis est beaucoup plus propre, consiste à faire une demande Ajax synchrone au lieu d'utiliser une <script> . C’est aussi la façon dont Node.js gère les inclus.

Voici un exemple d'utilisation de jQuery:

function require(script) {
    $.ajax({
        url: script,
        dataType: "script",
        async: false,           // <-- This is the key
        success: function () {
            // all good...
        },
        error: function () {
            throw new Error("Could not load script " + script);
        }
    });
}

Vous pouvez ensuite l'utiliser dans votre code comme vous utiliseriez habituellement un include:

require("/scripts/subscript.js");

Et être capable d'appeler une fonction du script requis dans la ligne suivante:

subscript.doSomethingCool(); 



Il est possible de générer dynamiquement une balise JavaScript et de l'ajouter à un document HTML à partir d'un autre code JavaScript. Cela chargera le fichier JavaScript ciblé.

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



Peut-être que vous pouvez utiliser cette fonction que j'ai trouvée sur cette page Comment inclure un fichier JavaScript dans un fichier JavaScript? :

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

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

    head.appendChild(script)
}



Je viens d'écrire ce code JavaScript (en utilisant Prototype pour la manipulation DOM ):

var require = (function() {
    var _required = {};
    return (function(url, callback) {
        if (typeof url == 'object') {
            // We've (hopefully) got an array: time to chain!
            if (url.length > 1) {
                // Load the nth file as soon as everything up to the
                // n-1th one is done.
                require(url.slice(0, url.length - 1), function() {
                    require(url[url.length - 1], callback);
                });
            } else if (url.length == 1) {
                require(url[0], callback);
            }
            return;
        }
        if (typeof _required[url] == 'undefined') {
            // Haven't loaded this URL yet; gogogo!
            _required[url] = [];

            var script = new Element('script', {
                src: url,
                type: 'text/javascript'
            });
            script.observe('load', function() {
                console.log("script " + url + " loaded.");
                _required[url].each(function(cb) {
                    cb.call(); // TODO: does this execute in the right context?
                });
                _required[url] = true;
            });

            $$('head')[0].insert(script);
        } else if (typeof _required[url] == 'boolean') {
            // We already loaded the thing, so go ahead.
            if (callback) {
                callback.call();
            }
            return;
        }

        if (callback) {
            _required[url].push(callback);
        }
    });
})();

Usage:

<script src="prototype.js"></script>
<script src="require.js"></script>
<script>
    require(['foo.js','bar.js'], function () {
        /* Use foo.js and bar.js here */
    });
</script>

Gist: http://gist.github.com/284442 .




Si vous voulez en JavaScript pur, vous pouvez utiliser document.write .

document.write('<script src="myscript.js" type="text/javascript"></script>');

Si vous utilisez la bibliothèque jQuery, vous pouvez utiliser la méthode $.getScript .

$.getScript("another_script.js");



Vous pouvez également assembler vos scripts en utilisant PHP :

Fichier main.js.php :

<?php
    header('Content-type:text/javascript; charset=utf-8');
    include_once("foo.js.php");
    include_once("bar.js.php");
?>

// Main JavaScript code goes here



Cela devrait faire:

xhr = new XMLHttpRequest();
xhr.open("GET", "/soap/ajax/11.0/connection.js", false);
xhr.send();
eval(xhr.responseText);



Si vous utilisez des travailleurs Web et souhaitez inclure des scripts supplémentaires dans la portée de ce dernier, les autres réponses fournies sur l'ajout de scripts à la headbalise, etc. ne fonctionneront pas pour vous.

Heureusement, les Web Workers ont leur propre importScriptsfonction, qui est une fonction globale dans la portée de Web Worker, native du navigateur lui-même car elle fait partie de la spécification .

Alternativement, comme le souligne la deuxième réponse la plus votée à votre question , RequireJS peut également gérer l’inclusion de scripts dans un Web Worker (s’appelant probablement importScriptslui-même, mais avec quelques autres fonctionnalités utiles).




La @importsyntaxe permettant de réaliser une importation JavaScript de type CSS est possible à l'aide d'un outil tel que Mixture via leur .mixtype de fichier spécial (voir here ). J'imagine que l'application utilise simplement l'une des méthodes susmentionnées en interne, bien que je ne sache pas.

De la documentation de Mixture sur les .mixfichiers:

Les fichiers de mixage sont simplement des fichiers .js ou .css avec .mix. dans le nom du fichier. Un fichier de mix étend simplement les fonctionnalités d'un fichier de style ou de script normal et vous permet d'importer et de combiner.

Voici un exemple de .mixfichier qui combine plusieurs .jsfichiers en un seul:

// scripts-global.mix.js
// Plugins - Global

@import "global-plugins/headroom.js";
@import "global-plugins/retina-1.1.0.js";
@import "global-plugins/isotope.js";
@import "global-plugins/jquery.fitvids.js";

Mixture génère ceci sous scripts-global.jsforme de version modifiée ( scripts-global.min.js).

Remarque: je ne suis en aucun cas affilié à Mixture, mis à part son utilisation en tant qu'outil de développement frontal. Je suis tombé sur cette question en voyant un .mixfichier JavaScript en action (dans l’un des circuits d’affichage Mixture) et en étant un peu confus («vous pouvez le faire?» Me suis-je dit). J'ai ensuite réalisé qu'il s'agissait d'un type de fichier spécifique à l'application (quelque peu décevant, accepté). Néanmoins, imaginé que la connaissance pourrait être utile pour les autres.

MISE À JOUR : Le mélange est maintenant gratuit (hors ligne).

UPDATE : Le mélange est maintenant interrompu. Les anciens mélanges sont toujours disponibles




Ma méthode habituelle est:

var require = function (src, cb) {
    cb = cb || function () {};

    var newScriptTag = document.createElement('script'),
        firstScriptTag = document.getElementsByTagName('script')[0];
    newScriptTag.src = src;
    newScriptTag.async = true;
    newScriptTag.onload = newScriptTag.onreadystatechange = function () {
        (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete') && (cb());
    };
    firstScriptTag.parentNode.insertBefore(newScriptTag, firstScriptTag);
}

Cela fonctionne très bien et n'utilise pas de rechargement de page pour moi. J'ai essayé la méthode AJAX (une des autres réponses) mais cela ne semble pas fonctionner aussi bien pour moi.

Voici une explication du fonctionnement du code pour les curieux: il crée essentiellement une nouvelle balise de script (après la première) de l'URL. Il le configure en mode asynchrone afin de ne pas bloquer le reste du code mais d'appeler un rappel lorsque le paramètre readyState (l'état du contenu à charger) passe à 'chargé'.




En langage moderne, ce serait

function loadJs( url ){
  return new Promise( resolve => {
    const script = document.createElement( "script" );
    script.src = url;
    script.onload = resolve;
    document.head.appendChild( script );
  });
}



Il y a aussi Head.js . Il est très facile de traiter avec:

head.load("js/jquery.min.js",
          "js/jquery.someplugin.js",
          "js/jquery.someplugin.css", function() {
  alert("Everything is ok!");
});

Comme vous le voyez, c'est plus facile que Require.js et aussi pratique que la $.getScriptméthode de jQuery . Il a aussi quelques fonctionnalités avancées, comme le chargement conditionnel, la détection de caractéristiques et bien plus encore .




Il y a beaucoup de réponses possibles à cette question. Ma réponse est évidemment basée sur un certain nombre d'entre elles. C'est ce que j'ai fini avec après avoir lu toutes les réponses.

Le problème avec $.getScripttoute autre solution nécessitant un rappel lorsque le chargement est terminé est que, si plusieurs fichiers l'utilisent et dépendent les uns des autres, vous ne pouvez plus savoir quand tous les scripts ont été chargés (une fois qu'ils sont imbriqués). dans plusieurs fichiers).

Exemple:

fichier3.js

var f3obj = "file3";

// Define other stuff

fichier2.js:

var f2obj = "file2";
$.getScript("file3.js", function(){

    alert(f3obj);

    // Use anything defined in file3.
});

fichier1.js:

$.getScript("file2.js", function(){
    alert(f3obj); //This will probably fail because file3 is only guaranteed to have loaded inside the callback in file2.
    alert(f2obj);

    // Use anything defined in the loaded script...
});

Vous avez raison de dire que vous pouvez spécifier qu'Ajax doit s'exécuter de manière synchrone ou utiliser XMLHttpRequest , mais la tendance actuelle semble être de désapprouver les demandes synchrones. Vous risquez donc de ne pas obtenir une prise en charge complète du navigateur, ni à l'avenir.

Vous pouvez essayer d'utiliser $.whenpour vérifier un tableau d'objets différés, mais maintenant vous le faites dans chaque fichier et fichier2 sera considéré comme chargé dès que le $.whenn'est pas exécuté lorsque le rappel est exécuté, de sorte que fichier1 continue l'exécution avant le chargement de fichier3. . Cela a toujours le même problème.

J'ai décidé de faire marche arrière au lieu d'avancer. Je vous remercie document.writeln. Je sais que c'est tabou, mais tant qu'il est utilisé correctement, cela fonctionne bien. Vous vous retrouvez avec un code qui peut être facilement mis au point, affiché correctement dans le DOM et peut garantir l'ordre de chargement correct des dépendances.

Vous pouvez bien sûr utiliser $ ("body"). Append (), mais alors vous ne pourrez plus déboguer correctement.

REMARQUE: vous devez utiliser ceci uniquement pendant le chargement de la page, sinon vous obtenez un écran vide. En d'autres termes, placez toujours ceci avant / en dehors de document.ready . Je n'ai pas testé l'utilisation de cette option après le chargement de la page dans un événement click ou quelque chose du genre, mais je suis certain que cela va échouer.

J'ai aimé l'idée d'étendre jQuery, mais vous n'avez évidemment pas besoin de le faire.

Avant d'appeler document.writeln, il vérifie que le script n'a pas déjà été chargé en évaluant tous les éléments du script.

Je suppose qu'un script n'est pas complètement exécuté tant que son document.readyévénement n'a pas été exécuté. (Je sais que l'utilisation document.readyn'est pas obligatoire, mais de nombreuses personnes l'utilisent, ce qui constitue une sauvegarde.)

Lorsque les fichiers supplémentaires sont chargés, les document.readyrappels seront exécutés dans le mauvais ordre. Pour résoudre ce problème lorsqu'un script est réellement chargé, le script qui l'a importé est réimporté lui-même et son exécution est arrêtée. Cela provoque maintenant le document.readyrappel du fichier d'origine, après n'importe quel script importé.

Au lieu de cette approche, vous pouvez essayer de modifier jQuery readyList, mais cela semble être une solution pire.

Solution:

$.extend(true,
{
    import_js : function(scriptpath, reAddLast)
    {
        if (typeof reAddLast === "undefined" || reAddLast === null)
        {
            reAddLast = true; // Default this value to true. It is not used by the end user, only to facilitate recursion correctly.
        }

        var found = false;
        if (reAddLast == true) // If we are re-adding the originating script we do not care if it has already been added.
        {
            found = $('script').filter(function () {
                return ($(this).attr('src') == scriptpath);
            }).length != 0; // jQuery to check if the script already exists. (replace it with straight JavaScript if you don't like jQuery.
        }

        if (found == false) {

            var callingScriptPath = $('script').last().attr("src"); // Get the script that is currently loading. Again this creates a limitation where this should not be used in a button, and only before document.ready.

            document.writeln("<script type='text/javascript' src='" + scriptpath + "'></script>"); // Add the script to the document using writeln

            if (reAddLast)
            {
                $.import_js(callingScriptPath, false); // Call itself with the originating script to fix the order.
                throw 'Readding script to correct order: ' + scriptpath + ' < ' + callingScriptPath; // This halts execution of the originating script since it is getting reloaded. If you put a try / catch around the call to $.import_js you results will vary.
            }
            return true;
        }
        return false;
    }
});

Usage:

File3:

var f3obj = "file3";

// Define other stuff
$(function(){
    f3obj = "file3docready";
});

Fichier2:

$.import_js('js/file3.js');
var f2obj = "file2";
$(function(){
    f2obj = "file2docready";
});

Fichier1:

$.import_js('js/file2.js');

// Use objects from file2 or file3
alert(f3obj); // "file3"
alert(f2obj); // "file2"

$(function(){
    // Use objects from file2 or file3 some more.
    alert(f3obj); //"file3docready"
    alert(f2obj); //"file2docready"
});



Mieux vaut utiliser la méthode jQuery . Pour retarder l'événement prêt, appelez d'abord $.holdReady(true). Exemple ( source ):

$.holdReady(true);
$.getScript("myplugin.js", function() {
    $.holdReady(false);
});



Related