update tutorial principiantes para node libro instalar ejemplos actualizar javascript node.js require google-closure-compiler

javascript - tutorial - Conseguir el cierre-compilador y Node.js para jugar bien



node js tutorial (5)

Cierre la biblioteca en Node.js en 60 segundos.

Es compatible, consulte https://code.google.com/p/closure-library/wiki/NodeJS .

¿Hay algún proyecto que haya usado node.js y el cierre-compilador (CC para abreviar) juntos?

La recomendación oficial de CC es compilar todos los códigos para una aplicación juntos, pero cuando compilo un código simple de node.js que contiene un require("./MyLib.js") , esa línea se coloca directamente en la salida, pero no No tiene ningún sentido en ese contexto.

Veo algunas opciones:

  1. Codifique la aplicación completa como un solo archivo. Esto resuelve el problema al evitarlo, pero es malo para el mantenimiento.
  2. Supongamos que todos los archivos se concatenarán antes de la ejecución. De nuevo, esto evita el problema, pero dificulta la implementación de un modo de depuración sin compilar.
  3. Me gustaría que CC "entendiera" la función node.js require (), pero probablemente no se pueda hacer sin editar el compilador, ¿verdad?


He estado usando Closure Compiler with Node para un proyecto que aún no he lanzado. Ha tomado un poco de herramientas, pero ha ayudado a detectar muchos errores y tiene un ciclo bastante corto de edición-reinicio-prueba.

Primero, uso plovr (que es un proyecto que creé y mantengo) para usar el compilador de cierre, la biblioteca y las plantillas juntas. Escribo mi código de nodo en el estilo de la biblioteca de cierre, por lo que cada archivo define su propia clase o colección de utilidades (como goog.array ).

El siguiente paso es crear un grupo de archivos externos para las funciones de nodo que desea usar. Publiqué algunos de estos públicamente en:

https://github.com/bolinfest/node-google-closure-latitude-experiment/tree/master/externs/node/v0.4.8

Aunque en última instancia, creo que esto debería ser algo más impulsado por la comunidad porque hay muchas funciones que documentar. (También es molesto porque algunas funciones del Nodo tienen argumentos intermedios opcionales en lugar de los últimos, lo que complica las anotaciones de tipo). No he iniciado este movimiento porque es posible que podamos trabajar con el Closure Complier para que esto sea menos incómodo. (vea abajo).

Supongamos que ha creado el archivo extern para el espacio de nombres de nodo http . En mi sistema, he decidido que cada vez que necesito http , lo incluiré a través de:

var http = require(''http'');

Aunque no incluyo esa llamada require() en mi código. En su lugar, utilizo la función de output-wrapper del Compilador de cierre para añadir al principio todos los require() al inicio del archivo, que cuando se declara en plovr, en mi proyecto actual se ve así:

"output-wrapper": [ // Because the server code depends on goog.net.Cookies, which references the // global variable "document" when instantiating goog.net.cookies, we must // supply a dummy global object for document. "var document = {};/n", "var bee = require(''beeline'');/n", "var crypto = require(''crypto'');/n", "var fs = require(''fs'');/n", "var http = require(''http'');/n", "var https = require(''https'');/n", "var mongodb = require(''mongodb'');/n", "var nodePath = require(''path'');/n", "var nodeUrl = require(''url'');/n", "var querystring = require(''querystring'');/n", "var SocketIo = require(''socket.io'');/n", "%output%" ],

De esta manera, el código de mi biblioteca nunca llama a Node''s require() , pero el compilador tolera los usos de cosas como http en mi código porque el compilador los reconoce como externos. Como no son verdaderos externos, se tienen que anteponer como describí.

En última instancia, después de hablar sobre esto en la lista de discusión , creo que la mejor solución es tener una nueva anotación de tipo para los espacios de nombres que se vería como:

goog.scope(function() { /** @type {~NodeHttpNamesapce} */ var http = require(''http''); // Use http throughout. });

En este escenario, un archivo externo definiría el NodeHttpNamespace tal manera que el Compilador de cierre podría tipear las propiedades en él usando el archivo externo. La diferencia aquí es que usted podría nombrar el valor de retorno de require() quisiera, ya que el tipo de http sería este tipo especial de espacio de nombres. (Identificar un "espacio de nombres jQuery" para $ es un problema similar). Este enfoque eliminaría la necesidad de nombrar sus variables locales para los espacios de nombres de Nodos de manera consistente, y eliminaría la necesidad de ese output-wrapper gigante en la configuración de plovr.

Pero eso fue una digresión ... una vez que tengo las cosas configuradas como se describe anteriormente, tengo un script de shell que:

  1. Utiliza plovr para construir todo en modo RAW .
  2. Ejecuta el node en el archivo generado por plovr.

El uso del modo RAW da como resultado una gran concatenación de todos los archivos (aunque también se encarga de traducir las plantillas de Soy y hasta de CoffeeScript a JavaScript). Es cierto que esto hace que la depuración sea un problema porque los números de las líneas no tienen sentido, pero hasta el momento me han funcionado lo suficientemente bien. Todos los controles realizados por el compilador de cierre han hecho que valga la pena.


Opción 4: No usar compilador de cierre.

Las personas en la comunidad de nodos no tienden a usarlo. No necesitas minificar el código fuente de node.js, eso es una tontería.

Simplemente no hay un buen uso para la minificación.

En cuanto a los beneficios de cierre del rendimiento, personalmente dudo que realmente haga que sus programas sean más rápidos.

Y, por supuesto, hay un costo. La depuración de JavaScript compilado es una pesadilla.


Reemplacé mi antiguo enfoque con un enfoque más simple:

Nuevo enfoque

  • No requiere () llamadas para mi propio código de aplicación, solo para módulos de Nodo
  • Necesito concatenar el código del servidor en un solo archivo antes de poder ejecutarlo o compilarlo
  • La concatenación y compilación se realiza mediante github.com/blaise-io/xssnake/blob/master/build/server.js

Lo curioso es que ni siquiera tuve que agregar un externo para las llamadas a require() . El compilador de cierre de Google entiende eso automáticamente. Tuve que agregar externs para los módulos de nodejs que uso.

Antiguo enfoque

Según lo solicitado por OP, desarrollaré mi manera de compilar el código de node.js con Google Closure Compiler.

Me inspiré en la forma en que bolinfest resolvió el problema y mi solución utiliza el mismo principio. La diferencia es que hice un script node.js que lo hace todo, incluidos los módulos de alineación (la solución de bolinfest permite que GCC se encargue de eso). Esto lo hace más automatizado, pero también más frágil.

Acabo de agregar comentarios de código a cada paso que tomo para compilar el código del servidor. Vea este compromiso: https://github.com/blaise-io/xssnake/commit/da52219567b3941f13b8d94e36f743b0cbef44a3

Para resumir:

  1. Comienzo con mi módulo principal, el archivo JS que paso a Node cuando quiero ejecutarlo.
    En mi caso, este archivo es start.js .
  2. En este archivo, utilizando una expresión regular, detecto todas las llamadas require() , incluida la parte de asignación.
    En start.js, esto coincide con una llamada de requerimiento: var Server = require(''./lib/server.js'');
  3. Recupero la ruta donde existe el archivo en función del nombre del archivo, recupero su contenido como una cadena y elimino las asignaciones de módulo.exportaciones dentro del contenido.
  4. Luego sustituyo la llamada requerida del paso 2 con el contenido del paso 3. A menos que sea un módulo core node.js, lo agrego a la lista de módulos principales que guardo para más adelante.
  5. El paso 3 probablemente contendrá más llamadas require() , así que repito los pasos 3 y 4 de forma recursiva hasta que todas las llamadas require() hayan desaparecido y me quede una gran cadena que contiene todo el código.
  6. Si todas las recursiones se han completado, compilo el código usando la API REST.
    También puede utilizar el compilador fuera de línea.
    Tengo externos para cada módulo de node.js del núcleo. Esta herramienta es útil para generar externos .
  7. Antes de la ejecución del módulo core.js eliminado, se require llamadas al código compilado.

Código precompilado.
Todas las llamadas require son eliminadas. Todo mi código es aplanado.
http://pastebin.com/eC2rVMiN

Código post-compilado.
Node.js require llamadas se hayan agregado manualmente.
http://pastebin.com/uB8CaejN

¿Por qué no deberías hacerlo de esta manera?

  1. Utiliza expresiones regulares (no un analizador o tokenizador) para detectar llamadas require , alinear y eliminar module.exports . Esto es frágil, ya que no cubre todas las variaciones de sintaxis.
  2. Al ingresar, todo el código del módulo se agrega al espacio de nombres global. Esto va en contra de los principios de Node.js, donde cada archivo tiene su propio espacio de nombres, y esto causará errores si tiene dos módulos diferentes con las mismas variables globales.
  3. No mejora mucho la velocidad de su código, ya que V8 también realiza muchas optimizaciones de código como la alineación y la eliminación de código muerto.

Por qué deberías:

  1. Porque funciona cuando tienes un código consistente.
  2. Detectará errores en el código de su servidor cuando habilite advertencias detalladas.