2010-09-08 22 views
41

¿Cómo se organizan grandes bases de datos JS/jQuery en todo su sitio web? Hay muchos buenos recursos sobre cómo organizar partes de tu código, pero nada acerca de cómo juntarlo todo y ajustar cada pieza en su lugar: organización de código lateral, varias páginas usando el mismo código, permaneciendo SECO con acoplamiento flojo, etc.¿Cómo se organizan grandes bases de código JS/jQuery en todo su sitio web?

A continuación es cómo me ocupo de ello. Nunca me he sentido cómodo organizando mi código de esta manera, porque creo que es descuidado y puede llevar a problemas de mantenimiento/escalado, pero realmente no sé nada mejor.

Me doy cuenta de que todos tenemos sus propios requisitos y no hay soluciones llave en mano, pero me gustaría escuchar algunas opiniones sobre lo que estoy haciendo mal, POR QUÉ lo estoy haciendo mal y sugerencias sobre cómo escribir un código más fácil de mantener.

Lo que yo creo que realmente estoy tratando de conseguir en:

  1. ¿Cómo lidiar con la lógica que necesidad de utilizar en varios lugares, en varias páginas?

  2. ¿Cómo se organiza el código de página específico ? ¿Es una buena idea el espacio de nombres de cada página en un objeto global? 1.

  3. ¿Qué haces desde el principio para asegurar no estás constantemente re-escribir sus patrones de organización como su aplicación se hace más grande y más grande ? Probablemente estoy en mi 4ta iteración escribiendo esto.2.

Cada página recibe el archivo principal application.js. Cada página adicional tiene su propio archivo application.pagename.js . Utilizo la lógica del lado del servidor para incluir los archivos (primero verificando para ver si alguno existe para la página - algunas páginas no necesitan JS), y luego iniciarlos en orden.

Así que mi página de inicio se ve como:

<script src="js/application.js"></script> 
<script src="js/application.index.js"></script> 
<script> 
    MyApp.init(); 
    MyApp.index.init(); 
</script> 

mi convención URL es/página/subpágina/id /. Tengo alrededor de 10 páginas y una gran cantidad de subpáginas, cada subpágina requiere su propia lógica. ver el último ejemplo en esta publicación.

La mayor parte de mi código ya está modularizado en widgets jQuery UI o complementos jQuery, así que diría que el 75% del código en estos archivos requiere() 'un widget y lo inserta.

Uso requireJS para instalar widgets según sea necesario.

// application.js 
var MyApp = { 
    init: function(){ 
     var self = this; 

     // these widgets are available on every single page 
     // notice the call to jquery.deparam.js - i'll use this later to init subpage logic. 
     require(['js/widget1.js', 'js/widget2.js', 'js/widget3.js', 'js/jquery.deparam.js'], function(){ 

      // deparam the query string. I'll use this later. 
      self.querystring = $.deparam.querystring(); 

      // init widgets once the document is ready 
      $(function(){ 
       $("#widget1").widget1(); 
       $("#widget2").widget2(); 

       // make these bindings available immediately as well. 
       self.rebindable(); 
      }); 
     }); 
    }, 

    // I use jQuery UI Dialog extensively as a window manager, and each dialog is loaded 
    // via an AJAX request. I'll call this method after each AJAX request to 
    // rebind some key widgets. 
    rebindable: function(){ 
     $("#widget3").widget3(); 
    } 
}; 

// application.index.js 
// home page specific stuff. this file is only included on the home page. 
MyApp.index = { 

    // my convention is that init is automatically called after the script 
    // is included in a page, outside of a doc.ready statement. 
    init: function(){ 
     var self = this; 

     require(['js/widget4.js'], function(){ 
      $(function(){ 
       self.widget4($("#foo")); 
      }); 
     }); 
    }, 

    // passing elements to each method allows me to call this init code 
    // outside of the index page. I can require() this file, and only init 
    // widget4, and even use a different element. 
    widget4: function(element){ 
     var config = { 
      something: "custom to the home page" 
     }; 

     element.widget4(config); 
    } 
}; 


// application.foo.js 
// page "foo" stuff 
MyApp.foo = { 

    init: function(){ 
     var self = this; 

     // this page happens to use the same widget3 and configuration present 
     // in MyApp.index. this is where things can get sloppy and unmaintainable 
     // really quickly. 
     require(['js/application.index.js'], function(){ 
      $(function(){ 
       MyApp.index.widget3($("#bar")); 
      }); 
     }); 

     // page "foo" has three subpages (or actions) and require 
     // their own logic. url convention: /foo/subpage1/ 
     // init whichever page we're on... 
     switch(self.querystring.subpage){ 
      case "subpage1": 
       self.subpage1.init(); 
       break; 
      case "subpage2": 
       self.subpage2.init(); 
       break; 
      case "subpage3": 
       self.subpage3.init(); 
       break; 
     } 
    }, 

    subpage1: function(){ 
     init: function(){ 
      var self = this; 

      // once the DOM is ready init dialog. 
      $(function(){ 
       self.dialog($("#openDialog")); 
      }); 
     }, 

     dialog: function(element){ 
      element.bind("click", function(){ 
       $('<div></div>').dialog({ 
        open: function(){ 

         // see what i'm doing here? 
         MyApp.rebindable(); 

         // maybe more bindings specific to this 
         // dialog here 
        } 
       }); 
      }); 
     } 
    }, 

    subpage2: function(){ 
     init: function(){ 
     } 
    }, 

    subpage3: function(){ 
     init: function(){ 
     } 
    } 
}; 
+1

Estaba pensando en esto yo esta semana. Recientemente me uní a un equipo de proyecto como el principal codificador de JavaScript. El proyecto lleva funcionando más de un año, por lo que tienen javascript por todas partes. Han acumulado una extensa biblioteca de JavaScript y han hecho algunos esfuerzos para usar espacios de nombres, pero muchas páginas tienen JavaScript personalizado que no solo está escrito en páginas y controles de usuario, sino que también se genera en base a datos de control de página o de usuario. Tengo la abrumadora tarea de darle sentido a todo e intentar estandarizar lo más posible. – Silkster

+0

(continuación) Su método es un buen comienzo, pero puedo ver dónde no se puede mantener. Tal vez pueda diseñar un método para configurar páginas y controles para que no tenga que usar muchas instrucciones de conmutación. También puede consultar Claypool (http: // http: //www.claypooljs.com/) para ver si eso podría ayudar. – Silkster

+1

@Silkster el enlace está roto: http: //http//www.claypooljs.com/ –

Respuesta

12

Para ayudar a contestar sus preguntas específicas, por favor, permítame hablar un poco acerca de las características JavaScriptMVC 's:

controlador mejorará sus widgets jQuery, el cuidado de instalación/desmontaje, extensibilidad.

Ver agrega plantillas del lado del cliente que se pueden integrar en su aplicación.

El modelo abstrae la capa de servicio/datos minimizando y localizando los cambios de JS si el servidor cambia.

Steal realiza gestión de dependencias, compresión y limpieza de códigos. Incluso tomará todas las secuencias de comandos en todas sus páginas, descubrirá las dependencias compartidas y combinará las secuencias de comandos en una carga útil óptima.

FuncUnit hace que probar sus aplicaciones sea lo más fácil posible.

DocumentJS ... bueno ... los documentos de su código

.

Ahora, en sus preguntas específicas:

¿Cómo lidiar con la lógica utilizada en múltiples lugares?

Uso el sistema de gestión de dependencias de StealJS para cargar la funcionalidad que necesito en mi página. La administración de dependencias es absolutamente necesaria en aplicaciones de cierto tamaño. RequireJS es una buena opción si puede compilarlo fácilmente.

¿Cómo se organiza página de códigos específica

página de códigos específica debe ser lo más pequeño posible. Por lo general, implica cargar dependencias y un "MainController". Ese controlador principal configura la página para obedecer los requisitos funcionales/comerciales de esa página. Es normalmente el namespace por algo como:

App.Controllers.Main 

¿cómo dejar de escribir los mismos patrones

Bueno, se sugiere emplear un marco que tiene patrones estables para el desarrollo. Además, mantenga sus módulos/complementos/widgets tan pequeños (y comprobables) como sea posible. Esto hará que estas partes sean mucho menos propensas a cambiar.

Por último ....

parece que su mayor tensión lucha entre:

  • funcionalidad compartida
  • múltiples páginas
  • tiempos de carga oportunas

Así recogiendo una sólida herramienta de gestión de la dependencia es sup er crítico. StealJS podría ayudarlo a obtener tiempos de carga óptimos, pero tendría que alejarse de la organización de carpetas estándar de JavaScriptMVC debido a su mayor número de páginas.

RequireJS es más flexible, pero tendrá que cargar muchos archivos. No solo será lento, sino que comenzará a crear muchos archivos JS grandes que no están muy organizados.

Si está satisfecho con los tiempos de carga y siente que no harán que exprima el código en los archivos a los que no pertenece, su solución actual parece que funcionará.

Creo que el secreto para el desarrollo sostenible es la facilidad con la que su sistema/estructura le permite aislar las preocupaciones. Es importante dividir su aplicación en las partes más pequeñas posibles. Además, deberías probar estas partes. La gente queda al margen al pensar en la funcionalidad de sus páginas. Pero para realmente escalar el desarrollo, realmente necesitas algo que te permita dividir tu aplicación en pequeñas partes, cargar esas partes fácilmente y de alguna manera hacer que la aplicación funcione aún más rápido.

+2

Para aclarar: RequireJS puede cargue archivos individuales durante el desarrollo, pero tiene una herramienta de optimización (http://requirejs.org/docs/optimization.html) que le permite optimizar/agrupar sus módulos en un pequeño conjunto de solicitudes HTTP. La herramienta de optimización también se puede usar en desarrollo, tiene una forma de excluir solo ciertos módulos que puede que desee depurar por su cuenta. – jrburke

+0

Sí, este fue mi error. RequireJS puede combinar todos los scripts. Pero no creo que pueda hacer la ruptura automática del robo entre varios proyectos. –

+0

"Ese controlador principal configura la página para que obedezca los requisitos funcionales/comerciales de esa página". Entonces, ¿el Controlador es el principal impulsor de la lógica aquí, en oposición a la programación del lado del servidor donde se recomienda mantener la lógica de negocios en el Modelo? –

Cuestiones relacionadas