2012-07-10 15 views
7

Vi la charla de Paul Irish anunciando a Yeoman (www.yeoman.io), y estoy enganchado al concepto de ejecutar un entorno de compilación continua. No contento con esperar una invitación de Yeoman, probé Grunt y Brunch. Ambos se instalan fácilmente, y puedo poner en marcha nuevos proyectos con un mínimo esfuerzo.Importar un proyecto de JavaScript existente en un proyecto Grunt/Brunch

No entiendo cómo se podría migrar un proyecto existente a cualquiera de las plataformas. Mi proyecto utiliza un solo espacio de nombres y utiliza dos convenciones para módulos (una para instaurar otra para la utilidad), cada una de las cuales está envuelta en funciones anónimas autoejecutables que se exportan a la instancia o al espacio de nombres.

Tengo al menos 200 módulos y muchas más funciones simples, exportaciones de ayuda al espacio de nombres; por lo tanto, no es del todo eficiente usar la consola para crear estos en un proyecto grunt/brunch y luego importar manualmente cada módulo individualmente. Además, estoy usando al menos 15 herramientas de JavaScript de terceros diferentes. No me queda claro cómo introducirlos.

¿Cuál es la forma más eficiente de tomar un proyecto grande y existente y migrarlo a Grunt/Brunch con la menor cantidad de refactorización y compatibilidad con herramientas arbitrarias de terceros?

Actualización: de los dos, he encontrado a Brunch un poco más fácil de sobrellevar. Si usa el stock "esqueleto" (que es "plantilla" - desde la línea de comando {en la carpeta donde desea que ocurra el cambio), ejecute "brunch new [project_name] --skeleton git: //github.com/brunch /simple-js-skeleton.git ") para JS puro, obtienes una nueva estructura de carpetas que en realidad es bastante receptiva. Cualquier cosa que agregue a las carpetas de la "aplicación" (su propio código) o del "proveedor" (de terceros) se compilará automáticamente en la edición del archivo (cuando ejecute "brunch watch").

Esto es genial, excepto. De acuerdo con la documentación, usted controla el orden en que los scripts de los proveedores se compilan y concatenan juntos desde el archivo brunch config.coffee (archivo de texto JSON). Parece que los cambios en este archivo no tienen efecto, por lo que terminas con condiciones de carreras de terceros desde complementos que esperan otros complementos.

Además, cuando inserta su propio código en la carpeta de 'aplicación' creada automáticamente, obtiene una versión del código autocompilada, en tiempo real, como la edita; pero no es accesible. Brunch oscurece el objeto de ventana, por lo que mi declaración de espacio de nombre inicial para window.myNameSpace falla y todas las llamadas posteriores a la biblioteca al espacio de nombres también fallan. Esto tiene algo que ver con el sistema de módulos de Brunch, para lo cual no puedo encontrar documentación.

Lo resolví colocando mi clase de espacio de nombres en la carpeta 'proveedor', lo que aseguró que se adjuntara al objeto ventana; sin embargo, ahora hay una condición de carrera: mi espacio de nombres no siempre está disponible para todos mis módulos.

El problema ahora es la siguiente:

Una vez que haya copiado todos sus bibliotecas internas y externas en un proyecto Almuerzo, ¿Cómo se configura la aplicación para cargar en un orden cuerdo?

Respuesta

8

Esto es un poco opus, pero finalmente lo descubrí.Cuando comencé con Brunch, no era obvio cómo dar el primer paso: importar la estructura de mi directorio. Me tomó un par de pases sobre la documentación, antes de que se hizo evidente:

  1. Ejecutar brunch new MyAppName -s https://github.com/damassi/Javascript-App-Skeleton, lo que generará una estructura de carpetas de archivos esqueleto y config.coffee
  2. Para mí, las únicas carpetas relevantes de esta estructura estaban 'aplicación' (el contenido crudo de src para CSS, JS y HTML), 'público' (el destino para el contenido compilado y la ubicación que presta servicios al servidor NodeJS) y 'proveedor' (el lugar para archivos de terceros).
  3. Almuerzo crea un archivo config.coffee en la raíz de la estructura de directorios con este contenido: files: javascripts: defaultExtension: 'js' joinTo: 'javascripts/app.js': /^app/ 'javascripts/vendor.js': /^vendor/ order: before: [ 'vendor/scripts/console-helper.js', 'vendor/scripts/jquery-1.7.1.min.js' ]
  4. La propiedad de este objeto 'joinTo' me confundió, hasta que me di cuenta de que los javascript '' es en realidad sólo una máscara para ' código de cliente 'y que' apps.js 'es efectivamente una llamada a' obtener todos los archivos * .js en la carpeta 'aplicación', recursivamente '.
  5. Una vez que esto está claro, todo lo que necesita hacer es soltar su contenido en 'aplicación'. Puse mis archivos * .html y de imágenes en la subcarpeta 'assets' y puse todo mi contenido de JavaScript en lib.
  6. En este punto, puede ejecutar brunch build y brunch watch, y su proyecto estará en funcionamiento, compilando en tiempo real mientras realiza cambios, cargando de nuevo en tiempo real en el navegador.

Mientras que Brunch está fuera de la caja mejor que Grunt en la facilidad de usar el paso 6, donde falló para mí es la naturaleza de la compilación en Brunch. Cada archivo JavaScript se envuelve en un módulo CommonJS y el nombre del módulo se basa en la ruta relativa y el nombre del archivo ('lib/core/ajax', etc.). La filosofía de CommonJS no es para mí, y el trabajo que implica refacturar mi biblioteca para usar CommonJS es enorme.

Así que, volvamos a Grunt. Una vez que entendí cómo importar un proyecto en Brunch, importarlo a Grunt fue muy fácil. Estoy en Windows, así que todas las llamadas grunt usan grunt.cmd.

  1. llamada grunt init:jquery (esto puede estar en cualquier lugar, que trasladó la estructura de directorios creada en mi carpeta de proyecto existente)
  2. Como Almuerzo, se obtiene un auto generada estructura de directorios y archivos de configuración (grunt.js), pero es mucho, mucho más delgado. La configuración de Grunt se ve así: concat: { dist: { src: ['<config:lint.files>'], dest: 'dist/<%= pkg.name %>.js' } }, min: { dist: { src: ['<banner:meta.banner>', '<config:concat.dist.dest>'], dest: 'dist/<%= pkg.name %>.min.js' } }, qunit: { files: ['test/**/*.html'] }, lint: { files: ['grunt.js', 'src/**/*.js', 'test/**/*.js'] }, watch: { files: '<config:lint.files>', tasks: 'lint qunit' }
  3. Esto me pareció un poco ajeno a mi mente al principio, pero en realidad es bastante elegante. La propiedad 'min' define el archivo final, concatenado, linted y minified que mi aplicación web servirá. Su valor de origen es '', que es magia de Grunt para ver el valor del valor de la propiedad distcat del objeto concat, que luego se deriva del valor de la propiedad del archivo de lint. Por lo tanto, debe definir los recursos que desea filtrar, concatenar, minificar y enviar a un destino en el nivel de pelusa.
  4. Una vez que esta pieza está en su lugar, debe hacer un poco de trabajo adicional para obtener la construcción, el reloj y las piezas del servidor en su lugar. En gruñido, cuando el servidor termina de ejecutarse, se cierra. Eso significa que si ejecuta la tarea del servidor de grunt, se iniciará el servidor y, sin otras tareas que hacer, se cerrará.
  5. Mi primer error fue agrupar la tarea del servidor con la tarea del reloj, configurando watch.task = 'server lint qunit'. Esto funciona para el primer cambio que realice en la fuente, pero el segundo cambio intentará iniciar una segunda instancia del servidor en el mismo puerto y fallará. En su lugar, puede registrar una tarea grunt.registerTask('dev', 'server watch qunit'); y llamar a grunt dev para que un servidor se ejecute en tiempo real y de forma continua.
  6. A continuación, mi contenido HTML dependía de las inclusiones del servidor para ensamblar la página.No pude encontrar la manera de hacerlo funcionar en Node, y el lado del cliente incluye el uso de <object/> no funciona, ya que insertan el contenido (en mi caso varios elementos <script/> y <link/>) en un Iframe, lo que por supuesto me rompe patrón de módulo (Mi espacio de nombre está en un objeto de ventana diferente que el objeto de ventana de los iframes). Afortunadamente, el objeto concat de grunt es una multitarea y puede concatenar cualquier cosa. Así que agregué mis archivos HTML a concat, y mi aplicación de una sola página estaba lista para funcionar.
  7. A continuación, como el servidor de Nodo se ejecuta en un puerto diferente al de mi instancia de IIS, tiene el problema ajax de dominio cruzado. Este SO article me inició en el camino correcto, pero terminé necesitando los siguientes cambios a los encabezados de contenido predeterminado de IIS: Access-Control-Allow-Credentials: true Access-Control-Allow-Headers: X-Requested-With, X-Prototype-Version, Content-Type, Origin, Allow Access-Control-Allow-Methods: PUT, GET, POST, DELETE, OPTIONS Access-Control-Allow-Origin: http://localhost:88
  8. Finalmente, como estoy usando jQuery para mi controlador AJAX predeterminado, necesitaba agregar esto a mis opciones de ajax : xhrFields: { withCredentials: true }
  9. Obviamente, aquí hay implicaciones de seguridad; pero dado que esto solo afectará mi entorno de desarrollo y no será enviado a producción, creo que está bien.
  10. Por último, pero no menos importante, pasé una hora intentando depurar un error en la minificación a través de Uglify, which was conveniently answered by this SO post. Dado que Visual Studio insiste en insertar BOM en todo el ritmo ("UTF-8 With Signature" es el eufemismo), pero UTF-8 Cast soluciona esto en un orden rápido.

Una vez que calculé todo esto, Grunt parece estar funcionando bastante bien. Todavía no he tenido la oportunidad de comenzar a probar el proceso real de desarrollo en este nuevo entorno de construcción continua; pero esto es lo que se necesitó para poder comenzar.

2

config.coffee no es realmente json en lugar de js/coffeescript real, pero la edición de órdenes debería funcionar. ¿Puedes abrir un problema en brunch bugtracker con el orden de configuración exacto?

No creo que haya una forma rápida de volver a escribir su aplicación para usar módulos en lugar de variables globales window. Globales son considerados como un mal sabor, por cierto. Pero tu solución podría funcionar, sí.

+0

Lo que no entendí sobre Brunch fue que (al menos parece) requiere el patrón del módulo CommonJS. Estoy usando un patrón de espacio de nombres simple (pero en mi opción, bastante elegante) [Ver http://stackoverflow.com/questions/9072834/auto-generate-visual-studio-vsdoc-for-javascript-library y http://jsfiddle.net/2gxYJ/1/], lo que realmente hace que la conversión a otros sistemas de módulos (RequireJS, CommonJS, AMD, etc.) sea bastante no trivial una vez que la biblioteca se ha hecho grande. Entonces, cambié a Grunt, que no impone la restricción de diseño. – Christopher

+0

Dado que 1.4 brunch es independiente de los sistemas de módulos, incluso puede deshabilitar los módulos. –

+0

Eso es sobresaliente. La única característica que falta entonces es el soporte JSHint. Deshilachar como una opción de construir/ver sería genial. La configuración de Grunt también le da un objeto jshint/uglifyjs para configurar explícitamente su comportamiento. De todos modos, mi mayor problema con el brunch fue el requisito del módulo, así que definitivamente le daré otra oportunidad. – Christopher

Cuestiones relacionadas