Gestion de dépendance JavaScript

Je conserve actuellement un grand nombre de fichiers JS et le problème de dépendance augmente de ma façon. À l'heure actuelle, j'ai chaque fonction dans un fichier séparé et je maintient manuellement une base de données pour déterminer les dépendances entre les fonctions.

Je souhaite automatiser cela. Par exemple, si j'ai la fonction f

Array.prototype.f = function() {}; 

Qui est référencé dans une autre fonction g

 MyObject.g = function() { var a = new Array(); af(); }; 

Je veux pouvoir détecter que g fait référence f.

Comment puis-je aborder cela? Où est-ce que je commence? Dois-je réellement écrire un compilateur ou puis-je tordre Spidermonkey par exemple? Est-ce que quelqu'un d'autre a déjà fait cela?

Tous les conseils pour me faire démarrer sont très appréciés

Merci Dok

Bien que vous puissiez théoriquement écrire un outil d'analyse statique qui a détecté l'utilisation de globaux définis dans d'autres fichiers, comme l'utilisation de MyObject , vous ne pouvez pas suivre de façon réaliste l'utilisation des méthodes d'extension prototype .

JavaScript est un langage dynamiquement typé, de sorte qu'il n'y a aucun moyen pratique pour un outil de savoir que a , s'il est passé hors de la fonction g , est une Array , et donc si f() est appelé, il y a une dépendance. Il est seulement déterminé quelles sont les variables qui tiennent les types de temps d'exécution, afin de savoir si vous auriez besoin d'un interprète et que vous vous êtes fait un problème complet de Turing.

Sans oublier les autres aspects dynamiques de JavaScript qui défient complètement l'analyse statique, comme l'extraction de propriétés par notation de crochet, l' eval redoutable ou les chaînes dans les délais ou les attributs du gestionnaire d'événements.

Je pense vraiment que c'est vraiment un non-démarreur. Vous êtes probablement mieux de suivre les dépendances manuellement, mais en le simplifiant en regroupant des fonctions associées en modules qui seront votre unité de base de suivi de dépendance. OK, vous allez tirer quelques autres fonctions dont vous avez besoin techniquement, mais, espérons-le, pas trop.

C'est aussi une bonne idée d'espace de noms de chaque module, il est donc très clair où chaque appel se déroule, ce qui permet de garder manuellement les dépendances (par exemple, par un // uses: ThisModule, ThatModule commenter en haut).

Étant donné que les extensions des prototypes intégrés sont plus difficiles à suivre, gardez-les au minimum. Extension par ex. Array pour inclure les méthodes ECMAScript Fifth Edition (comme indexOf ) sur les navigateurs qui ne les possèdent pas déjà est une bonne chose à faire comme un correctif de base que tous les scripts utiliseront. L'ajout de fonctionnalités arbitraires totalement nouvelles aux prototypes existants est discutable.

Avez-vous essayé d'utiliser un gestionnaire de dépendance comme RequireJS ou LabJS ? J'ai remarqué que personne ne les a mentionnés dans ce fil.

À partir de http://requirejs.org/docs/start.html :

À l'intérieur de main.js, vous pouvez utiliser require () pour charger tous les autres scripts que vous devez exécuter:

 require(["helper/util"], function(util) { //This function is called when scripts/helper/util.js is loaded. //If util.js calls define(), then this function is not fired until //util's dependencies have loaded, and the util argument will hold //the module value for "helper/util". }); 

Vous pouvez également nicher ces dépendances, donc helper / util peut nécessiter d'autres fichiers en soi.

Comme @bobince a déjà suggéré, faire une analyse statique sur un programme JavaScript est un problème proche de impossible à craquer. Le compilateur Google Closure le fait dans une certaine mesure, mais il s'appuie également sur l'aide externe des commentaires JSDoc .

J'ai eu un problème similaire de trouver l'ordre dans lequel les fichiers JS devraient être concaténés dans un projet précédent, et comme il y avait beaucoup de fichiers JS, la mise à jour manuelle de l'ordre d'inclusion semblait trop fastidieuse. Au lieu de cela, j'ai collé avec certaines conventions de ce qui constitue une dépendance à mes fins, et en fonction de cela et en utilisant le regexp simple 🙂 J'ai pu générer l'ordre d'inclusion correct.

La solution a utilisé un algorithme de tri topologique pour générer un graphique de dépendance qui a ensuite répertorié les fichiers dans l'ordre dans lequel ils doivent être inclus pour satisfaire toutes les dépendances. Étant donné que chaque fichier était essentiellement une pseudo-classe utilisant la syntaxe MooTools , il n'y avait que 3 façons pour lesquelles des dépendances pouvaient être créées pour ma situation.

  1. Lorsqu'une classe a étendu une autre classe.
  2. Quand une classe a mis en œuvre une autre classe.
  3. Lorsqu'une classe a créé un objet d'une autre classe en utilisant le new mot-clé.

C'était une solution simple et certainement brisée pour l'utilisation générale, mais elle m'a bien servi. Si vous êtes intéressé par la solution, vous pouvez voir le code ici – c'est à Ruby.

Si vos dépendances sont plus complexes, alors peut-être que vous pouvez répertorier manuellement les dépendances dans chaque fichier JS en utilisant des commentaires et une syntaxe locale telle que:

 // requires: Array // requires: view/TabPanel // requires: view/TabBar 

Ensuite, lisez chaque fichier JS, analysez les commentaires requis et créez un graphique de dépendance qui vous donnera l'ordre d'inclusion dont vous avez besoin.

Il serait bon d'avoir un outil qui peut détecter automatiquement ces dépendances pour vous et choisir comment elles sont chargées. Les meilleures solutions d'aujourd'hui sont cependant un peu plus grossières. J'ai créé un gestionnaire de dépendance pour mes besoins particuliers que je souhaite ajouter à la liste ( Pyramid Dependency Manager ). Il a certaines caractéristiques clés qui résolvent certains cas d'utilisation uniques.

  1. Gère les autres fichiers (y compris l'insertion de html pour les vues … oui, vous pouvez séparer vos vues pendant le développement)
  2. Combine les fichiers pour vous en javascript lorsque vous êtes prêt à être publié (pas besoin d'installer des outils externes)
  3. Un générique inclut-il pour toutes les pages html. Il suffit de mettre à jour un fichier lorsqu'une dépendance est ajoutée, supprimée, renommée, etc.

Un exemple de code pour montrer comment cela fonctionne pendant le développement.

Fichier: dependencyLoader.js

 //Set up file dependencies Pyramid.newDependency({ name: 'standard', files: [ 'standardResources/jquery.1.6.1.min.js' ] }); Pyramid.newDependency({ name:'lookAndFeel', files: [ 'styles.css', 'customStyles.css', 'applyStyles.js' ] }); Pyramid.newDependency({ name:'main', files: [ 'createNamespace.js', 'views/buttonView.view', //contains just html code for a jquery.tmpl template 'models/person.js', 'init.js' ], dependencies: ['standard','lookAndFeel'] }); 

Fichiers Html

 <head> <script src="standardResources/pyramid-1.0.1.js"></script> <script src="dependencyLoader.js"></script> <script type="text/javascript"> Pyramid.load('main'); </script> </head> 

Il vous faut maintenir un seul fichier pour gérer les dépendances. Je pense à la création d'un programme qui peut générer automatiquement le fichier de chargement pour vous en fonction de l'intégralité de l'en-tête, mais étant donné qu'il gère différents types de dépendances, le maintien d'un fichier peut être mieux.

JSAnalyse utilise l'analyse de code statique pour détecter les dépendances entre les fichiers javascript: http://jsanalyse.codeplex.com/

Il vous permet également de définir les dépendances autorisées et de l'assurer pendant la construction, par exemple. Bien sûr, il ne peut pas détecter toutes les dépendances car javascript est un langage d'interprétation dynamique qui n'est pas sécurisé, comme déjà mentionné. Mais au moins vous rend compte de votre graphique de dépendance javascript et vous aide à le garder sous contrôle.

J'ai écrit un outil pour faire quelque chose comme ça: http://github.com/damonsmith/js-class-loader

Il est très utile si vous possédez un java webapp et que vous structurez votre code JS dans le style java. Si vous le faites, il peut détecter toutes les dépendances de votre code et les regrouper, en prenant en charge les dépendances d'exécution et de temps d'analyse.