Estoy creando una pequeña aplicación con un cliente JavaScript (se ejecuta en el navegador) y un servidor Node.js, que se comunica mediante WebSocket.
Me gustaría compartir el código entre el cliente y el servidor. Acabo de comenzar con Node.js y mi conocimiento del JavaScript moderno es un poco oxidado, por decir lo menos. Así que todavía estoy entendiendo la función require () de CommonJS. Si estoy creando mis paquetes usando el objeto 'exportar', entonces no puedo ver cómo podría usar los mismos archivos JavaScript en el navegador.
Quiero crear un conjunto de métodos y clases que se utilizan en ambos extremos para facilitar la codificación y decodificación de mensajes y otras tareas duplicadas. Sin embargo, los sistemas de empaquetado Node.js / CommonJS parecen impedirme crear archivos JavaScript que puedan usarse en ambos lados.
También intenté usar JS.Class para obtener un modelo OO más estricto, pero me di por vencido porque no pude descubrir cómo hacer que los archivos JavaScript proporcionados funcionen require (). ¿Hay algo que me estoy perdiendo aquí?
fuente
Respuestas:
Si desea escribir un módulo que pueda usarse tanto del lado del cliente como del lado del servidor, tengo una breve publicación de blog sobre un método rápido y fácil: Escribir para Node.js y el navegador , esencialmente lo siguiente (donde
this
es lo mismo quewindow
) :Alternativamente, hay algunos proyectos que apuntan a implementar la API Node.js en el lado del cliente, como el gemini de Marak .
También puede estar interesado en DNode , que le permite exponer una función de JavaScript para que se pueda llamar desde otra máquina utilizando un protocolo de red simple basado en JSON.
fuente
Epeli tiene una buena solución aquí http://epeli.github.com/piler/ que incluso funciona sin la biblioteca, solo ponga esto en un archivo llamado share.js
En el lado del servidor simplemente use:
Y en el lado del cliente, simplemente cargue el archivo js y luego use
fuente
Verifique el código fuente de jQuery que hace que esto funcione en el patrón del módulo Node.js, el patrón del módulo AMD y global en el navegador:
fuente
No olvide que la representación de cadena de una función de JavaScript representa el código fuente de esa función. Simplemente puede escribir sus funciones y constructores de forma encapsulada para que puedan ser toString () 'd y enviados al cliente.
Otra forma de hacerlo es usar un sistema de compilación, colocar el código común en archivos separados y luego incluirlos en los scripts del servidor y del cliente. Estoy usando ese enfoque para un juego simple de cliente / servidor a través de WebSockets donde el servidor y el cliente ejecutan esencialmente el mismo bucle de juego y el cliente se sincroniza con el servidor cada tic para asegurarse de que nadie haga trampa.
Mi sistema de compilación para el juego es un simple script Bash que ejecuta los archivos a través del preprocesador C y luego a través de sed para limpiar algunas hojas basura de cpp, para que pueda usar todo el preprocesador normal como #include, #define, #ifdef etc.
fuente
Yo recomendaría mirar en el adaptador de RequireJS para Node.js . El problema es que el patrón de módulo CommonJS que Node.js usa por defecto no es asíncrono, lo que bloquea la carga en el navegador web. RequireJS usa el patrón AMD, que es asíncrono y compatible con el servidor y el cliente, siempre que use el
r.js
adaptador.fuente
Tal vez esto no esté totalmente en línea con la pregunta, pero pensé en compartir esto.
Quería hacer un par de funciones de utilidad de cadena simples, declaradas en String.prototype, disponibles tanto para el nodo como para el navegador. Simplemente mantengo estas funciones en un archivo llamado utilities.js (en una subcarpeta) y puedo hacer referencia a ellas fácilmente desde una etiqueta de script en el código de mi navegador y al usar require (omitiendo la extensión .js) en mi script Node.js :
my_node_script.js
my_browser_code.html
Espero que esta información sea útil para alguien que no sea yo.
fuente
utilites.js
con una sola líneamodule.exports = require('./static/js/utilities');
. De esta manera, solo necesita actualizar una ruta si baraja las cosas.utilities.js
está en lashared
carpeta debajo del proyecto. Usarrequire('/shared/utilities')
me dio el errorCannot find module '/shared/utilities'
. Tengo que usar algo como estorequire('./../../shared/utilities')
para que funcione. Por lo tanto, siempre va desde la carpeta actual y viaja hacia la raíz y luego hacia abajo.Si usa paquetes de módulos como webpack para agrupar archivos JavaScript para su uso en un navegador, simplemente puede reutilizar su módulo Node.js para la interfaz que se ejecuta en un navegador. En otras palabras, su módulo Node.js se puede compartir entre Node.js y el navegador.
Por ejemplo, tiene el siguiente código sum.js:
Módulo Node.js normal: sum.js
Use el módulo en Node.js
Reutilízalo en la interfaz
fuente
El servidor simplemente puede enviar archivos fuente de JavaScript al cliente (navegador), pero el truco es que el cliente tendrá que proporcionar un entorno de mini "exportaciones" antes de que pueda
exec
el código y almacenarlo como un módulo.Una manera simple de crear un entorno así es usar un cierre. Por ejemplo, supongamos que su servidor proporciona archivos fuente a través de HTTP como
http://example.com/js/foo.js
. El navegador puede cargar los archivos requeridos a través de XMLHttpRequest y cargar el código de esta manera:La clave es que el cliente puede envolver el código externo en una función anónima que se ejecutará de inmediato (un cierre) que crea el objeto "exportaciones" y lo devuelve para que pueda asignarlo donde desee, en lugar de contaminar el espacio de nombres global. En este ejemplo, se asigna al atributo de ventana
fooModule
que contendrá el código exportado por el archivofoo.js
.fuente
window.fooModule = {}; (new Function('exports', xhr.responseText))(window.fooModule)
.Ninguna de las soluciones anteriores trae el sistema de módulos CommonJS al navegador.
Como se mencionó en las otras respuestas, existen soluciones de administrador / empaquetador de activos como Browserify o Piler y hay soluciones RPC como dnode o nowjs .
Pero no pude encontrar una implementación de CommonJS para el navegador (incluida una
require()
función yexports
/module.exports
objetos, etc.). Entonces escribí el mío, solo para descubrir después que alguien más lo había escrito mejor que yo: https://github.com/weepy/brequire . Se llama Brequire (abreviatura de navegador requiere).A juzgar por la popularidad, los administradores de activos se ajustan a las necesidades de la mayoría de los desarrolladores. Sin embargo, si necesita una implementación de navegador de CommonJS, Brequire probablemente se ajuste a la factura.
Actualización de 2015: ya no uso Brequire (no se ha actualizado en algunos años). Si solo estoy escribiendo un pequeño módulo de código abierto y quiero que cualquiera pueda usarlo fácilmente, entonces seguiré un patrón similar a la respuesta de Caolan (arriba): escribí una publicación de blog al respecto un par de años hace.
Sin embargo, si estoy escribiendo módulos para uso privado o para una comunidad que está estandarizada en CommonJS (como la comunidad Ampersand ), los escribiré en formato CommonJS y usaré Browserify .
fuente
now.js también vale la pena echarle un vistazo. Le permite llamar al lado del servidor desde el lado del cliente, y las funciones del lado del cliente desde el lado del servidor
fuente
Si desea escribir su navegador en un estilo similar a Node.js, puede intentar dualify .
No hay compilación de código del navegador, por lo que puede escribir su aplicación sin limitaciones.
fuente
Escriba su código como módulos RequireJS y sus pruebas como pruebas de Jasmine .
De esta forma, el código se puede cargar en todas partes con RequireJS y las pruebas se pueden ejecutar en el navegador con jasmine-html y con jasmine-node en Node.js sin la necesidad de modificar el código o las pruebas.
Aquí hay un ejemplo de trabajo para esto.
fuente
Caso de uso: comparta la configuración de su aplicación entre Node.js y el navegador (esto es solo una ilustración, probablemente no sea el mejor enfoque dependiendo de su aplicación).
Problema: no puede usar
window
(no existe en Node.js) niglobal
(no existe en el navegador).Solución:
Archivo config.js:
En el navegador (index.html):
Ahora puede abrir las herramientas de desarrollo y acceder a la variable global
config
En Node.js (app.js):
Con Babel o TypeScript:
fuente
shared.js
yhelpers.js
-shared.js
utiliza funciones dehelpers.js
, por lo que necesitaconst { helperFunc } = require('./helpers')
en la parte superior, para que funcione en el lado del servidor. El problema está en el cliente, se queja derequire
no ser una función, pero si envuelvo la línea requeridaif (typeof module === 'object') { ... }
, el servidor dice que helperFunc () no está definido (fuera de la instrucción if). ¿Alguna idea para que funcione en ambos?shared.js
:helperFunc = (typeof exports === 'undefined') ? helperFunc : require('./helpers').helperFunc;
- ¿Necesitará una línea para cada función exportada desafortunadamente pero espero que sea una buena solución?Escribí un módulo simple , que puede importarse (ya sea mediante require in Node, o etiquetas de script en el navegador), que puede usar para cargar módulos tanto desde el cliente como desde el servidor.
Ejemplo de uso
1. Definiendo el módulo
Coloque lo siguiente en un archivo
log2.js
, dentro de su carpeta de archivos web estáticos:¡Simple como eso!
2. Usando el módulo
Como es un cargador de módulos bilateral , podemos cargarlo desde ambos lados (cliente y servidor). Por lo tanto, puede hacer lo siguiente, pero no necesita hacer ambas cosas a la vez (y mucho menos en un orden particular):
En Node, es simple:
Esto debería volver
2
.Si su archivo no está en el directorio actual de Node, asegúrese de llamar
loader.setRoot
con la ruta a su carpeta de archivos web estáticos (o donde sea que esté su módulo).Primero, defina la página web:
Asegúrese de no abrir el archivo directamente en su navegador; dado que usa AJAX, le sugiero que eche un vistazo al
http.server
módulo de Python 3 (o cualquiera que sea su solución de implementación de servidor web de carpetas, línea de comandos y súper rápida).Si todo va bien, esto aparecerá:
fuente
Escribí esto, es fácil de usar si desea establecer todas las variables en el ámbito global:
fuente