from javascript dependencies dependency-management

javascript - call js from html



GestiĆ³n de la dependencia de JavaScript (6)

Actualmente estoy manteniendo un gran número de archivos JS y el problema de la dependencia está creciendo en mi cabeza. En este momento tengo cada función en un archivo separado y mantengo manualmente una base de datos para resolver las dependencias entre las funciones.

Esto me gustaría automatizar. Por ejemplo si tengo la función f

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

que se hace referencia en otra función g

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

Quiero poder detectar que g está haciendo referencia a f.

¿Cómo hago para esto? ¿Dónde empiezo? ¿Necesito realmente escribir un compilador o puedo modificar Spidermonkey por ejemplo? ¿Alguien más ya hizo esto?

Cualquier puntero para que comience es muy apreciado

Gracias dok


¿Has intentado usar un administrador de dependencias como RequireJS o LabJS ? Noté que nadie los mencionó en este hilo.

De http://requirejs.org/docs/start.html :

Dentro de main.js, puede usar require () para cargar cualquier otro script que necesite para ejecutar:

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

También puede anidar esas dependencias, por lo que helper / util puede requerir algunos otros archivos dentro de sí mismo.


Como @bobince ya sugirió, hacer un análisis estático en un programa de JavaScript es un problema casi imposible de descifrar. El compilador Google Closure lo hace en cierta medida, pero también depende de la ayuda externa de JSDoc comentarios de JSDoc .

Tuve un problema similar al encontrar el orden en el cual los archivos JS deberían concatenarse en un proyecto anterior, y como había muchos archivos JS, la actualización manual del orden de inclusión parecía demasiado tediosa. En lugar de eso, me limité a ciertas convenciones de lo que constituye una dependencia para mis propósitos, y en base a eso y usando la regexp simple :) pude generar el orden de inclusión correcto.

La solución utilizó un algoritmo de ordenamiento topológico para generar un gráfico de dependencia que luego enumeró los archivos en el orden en el que deberían incluirse para satisfacer todas las dependencias. Dado que cada archivo era básicamente una pseudo-clase con la sintaxis de MooTools , solo había 3 formas de crear dependencias para mi situación.

  1. Cuando una clase extendió alguna otra clase.
  2. Cuando una clase implementó alguna otra clase.
  3. Cuando una clase crea una instancia de un objeto de alguna otra clase usando la new palabra clave.

Fue una solución simple y definitivamente rota para uso general, pero me sirvió bien. Si estás interesado en la solución, puedes ver el código aquí , está en Ruby.

Si sus dependencias son más complejas, tal vez podría enumerar manualmente las dependencias en cada archivo JS utilizando comentarios y alguna sintaxis propia, como:

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

Luego lea cada archivo JS, analice los comentarios requeridos y construya un gráfico de dependencia que le dará el orden de inclusión que necesita.


He escrito una herramienta para hacer algo como esto: http://github.com/damonsmith/js-class-loader

Es más útil si tiene una aplicación web java y estructura su código JS en el estilo java. Si lo hace, puede detectar todas las dependencias de su código y agruparlas, con soporte tanto para las dependencias de tiempo de ejecución como de parse-time.


JSAnalyse utiliza el análisis de código estático para detectar dependencias entre archivos javascript: http://jsanalyse.codeplex.com/

También le permite definir las dependencias permitidas y asegurarlas durante la compilación, por ejemplo. Por supuesto, no puede detectar todas las dependencias porque javascript es un lenguaje de interpretación dinámico que no es de tipo seguro, como ya se mencionó. Pero al menos te hace consciente de tu gráfico de dependencia de javascript y te ayuda a mantenerlo bajo control.


Sería bueno tener una herramienta que pueda detectar automáticamente esas dependencias y elegir cómo se cargan. Las mejores soluciones de hoy son un poco más crudas. Creé un administrador de dependencias para mis necesidades particulares que quiero agregar a la lista ( Administrador de dependencias de Pyramid ). Tiene algunas características clave que resuelven algunos casos de uso únicos.

  1. Maneja otros archivos (incluida la inserción de html para las vistas ... sí, puede separar sus vistas durante el desarrollo)
  2. Combina los archivos para usted en javascript cuando esté listo para el lanzamiento (no es necesario instalar herramientas externas)
  3. Tiene una inclusión genérica para todas las páginas html. Solo tiene que actualizar un archivo cuando una dependencia se agrega, se elimina, se le cambia el nombre, etc.

Algunos ejemplos de código para mostrar cómo funciona durante el desarrollo.

Archivo: 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''] });

Archivos 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>

Requiere que usted mantenga un solo archivo para administrar las dependencias. Estoy pensando en crear un programa que pueda generar automáticamente el archivo de carga basado en el encabezado, pero como maneja muchos tipos diferentes de dependencias, mantenerlos en un solo archivo podría ser mejor.


Si bien teóricamente podría escribir una herramienta de análisis estático que detectó el uso de globales definidos en otros archivos, como el uso de MyObject , no pudo realizar un seguimiento realista del uso de los métodos de extensión de prototype .

JavaScript es un lenguaje de tipo dinámico, por lo que no hay una forma práctica de que una herramienta sepa que a , si se pasa de la función g , es una Array , por lo que si se llama a f() existe una dependencia. Solo se determina qué variables sostienen qué tipos en el tiempo de ejecución, por lo tanto, para averiguar, necesitará un intérprete y se habrá convertido en un problema completo de Turing.

Por no mencionar los otros aspectos dinámicos de JavaScript que desafían completamente el análisis estático, como la obtención de propiedades mediante notación de corchete, la temida eval o las cadenas en los tiempos de espera o los atributos del controlador de eventos.

Creo que es un poco de un arrancador realmente. Probablemente sea mejor rastrear dependencias manualmente, pero simplificándolas agrupando funciones relacionadas en módulos que serán su unidad básica de seguimiento de dependencias. De acuerdo, incorporará algunas funciones más que técnicamente necesita, pero con suerte no demasiado.

También es una buena idea asignar nombres a cada módulo, por lo que es muy claro hacia dónde se dirige cada llamada, lo que facilita el control manual de las dependencias (p. Ej. // uses: ThisModule, ThatModule comentario de // uses: ThisModule, ThatModule en la parte superior).

Dado que las extensiones de los prototipos incorporados son más difíciles de rastrear, manténgalas al mínimo. Extender por ejemplo. Array para incluir los métodos de la quinta edición de ECMAScript (como indexOf ) en los navegadores que aún no los tienen es una buena cosa como una reparación básica que usarán todos los scripts. Agregar una funcionalidad arbitraria completamente nueva a los prototipos existentes es cuestionable.