optimizar llamar insertar externo desde codigo archivo javascript node.js

javascript - llamar - ¿Cómo puedo compartir código entre Node.js y el navegador?



llamar javascript desde html (14)

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) ni global (no existe en el navegador).

Solución:

  • Archivo config.js:

    var config = { foo: ''bar'' }; if (typeof module === ''object'') module.exports = config;

  • En el navegador (index.html):

    <script src="config.js"></script> <script src="myApp.js"></script>

    Ahora puede abrir las herramientas dev y acceder a la config variable global

  • En Node.js (app.js):

    const config = require(''./config''); console.log(config.foo); // Prints ''bar''

  • Con Babel o TypeScript:

    import config from ''./config''; console.log(config.foo); // Prints ''bar''

Estoy creando una pequeña aplicación con un cliente JavaScript (ejecutado en el navegador) y un servidor Node.js, comunicándome mediante WebSocket.

Me gustaría compartir el código entre el cliente y el servidor. Acabo de empezar con Node.js y mi conocimiento del JavaScript moderno está un poco oxidado, por decir lo menos. Por lo tanto, todavía me estoy enfocando en la función require () de CommonJS. Si estoy creando mis paquetes utilizando el objeto ''exportar'', no puedo ver cómo puedo 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 la creación de archivos JavaScript que puedan usarse en ambos lados.

También intenté usar JS.Class para obtener un modelo de OO más estricto, pero me di por vencido porque no podía averiguar cómo hacer que funcionen los archivos JavaScript provistos con require () ¿Hay algo que me estoy perdiendo aquí?


El servidor puede simplemente enviar archivos de código fuente de JavaScript al cliente (navegador), pero el truco es que el cliente tendrá que proporcionar un entorno de mini "exportaciones" antes de poder exec el código y almacenarlo como un módulo.

Una forma sencilla de crear un entorno de este tipo es utilizar un cierre. Por ejemplo, digamos que su servidor proporciona archivos de origen a través de HTTP como http://example.com/js/foo.js . El navegador puede cargar los archivos requeridos a través de un XMLHttpRequest y cargar el código así:

ajaxRequest({ method: ''GET'', url: ''http://example.com/js/foo.js'', onSuccess: function(xhr) { var pre = ''(function(){var exports={};'' , post = '';return exports;})()''; window.fooModule = eval(pre + xhr.responseText + post); } });

La clave es que el cliente puede incluir el código externo en una función anónima para que se ejecute inmediatamente (un cierre), lo que crea el objeto "exportado" y lo devuelve para que pueda asignarlo donde lo desee, en lugar de contaminar el espacio de nombres global. En este ejemplo, se asigna al atributo fooModule la ventana que contendrá el código exportado por el archivo foo.js


Epeli tiene una buena solución aquí http://epeli.github.com/piler/ que incluso funciona sin la biblioteca, simplemente coloque esto en un archivo llamado share.js

(function(exports){ exports.test = function(){ return ''This is a function from shared module''; }; }(typeof exports === ''undefined'' ? this.share = {} : exports));

En el lado del servidor solo use:

var share = require(''./share.js''); share.test();

Y en el lado del cliente solo cargue el archivo js y luego use

share.test();


Escribí un módulo simple , que se puede importar (ya sea usando las etiquetas Node o script del 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:

let exports = {}; exports.log2 = function(x) { if ( (typeof stdlib) !== ''undefined'' ) return stdlib.math.log(x) / stdlib.math.log(2); return Math.log(x) / Math.log(2); }; return exports;

¡Simple como eso!

2. Usando el módulo

Como se trata de 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 (por no hablar de un orden en particular):

  • En Nodo

En Node, es simple:

var loader = require(''./mloader.js''); loader.setRoot(''./web''); var logModule = loader.importModuleSync(''log2.js''); console.log(logModule.log2(4));

Esto debería devolver 2 .

Si su archivo no está en el directorio actual de Node, asegúrese de llamar a loader.setRoot con la ruta a su carpeta de archivos web estáticos (o donde sea que esté su módulo).

  • En el navegador:

Primero, define la página web:

<html> <header> <meta charset="utf-8" /> <title>Module Loader Availability Test</title> <script src="mloader.js"></script> </header> <body> <h1>Result</h1> <p id="result"><span style="color: #000088">Testing...</span></p> <script> let mod = loader.importModuleSync(''./log2.js'', ''log2''); if ( mod.log2(8) === 3 && loader.importModuleSync(''./log2.js'', ''log2'') === mod ) document.getElementById(''result'').innerHTML = "Your browser supports bilateral modules!"; else document.getElementById(''result'').innerHTML = "Your browser doesn''t support bilateral modules."; </script> </body> </html>

Asegúrese de no abrir el archivo directamente en su navegador; ya que utiliza AJAX, le sugiero que eche un vistazo al módulo http.server Python 3 (o cualquiera que sea su superfast, línea de comandos, solución de implementación del servidor web de carpetas).

Si todo va bien, esto aparecerá:


Escribí esto, es fácil de usar si desea establecer todas las variables en el ámbito global:

(function(vars, global) { for (var i in vars) global[i] = vars[i]; })({ abc: function() { ... }, xyz: function() { ... } }, typeof exports === "undefined" ? this : exports);


Escriba su código como módulos RequireJS y sus pruebas como pruebas Jasmine .

De esta manera, el código se puede cargar en cualquier lugar con RequireJS y las pruebas se ejecutan 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.


Ninguna de las soluciones anteriores lleva el sistema de módulos CommonJS al navegador.

Como se mencionó en las otras respuestas, hay soluciones de gestión / empaquetador de activos como Browserify o http://epeli.github.com/piler/ y hay soluciones RPC como DNode o nowjs .

Pero no pude encontrar una implementación de CommonJS para el navegador (incluyendo una función require() y objetos module.exports / module.exports , etc.). Así que 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 satisfacen las necesidades de la mayoría de los desarrolladores. Sin embargo, si necesita una implementación de CommonJS en el navegador, es probable que https://github.com/weepy/brequire se ajuste a la factura.

Actualización de 2015: ya no uso Brequire (no se ha actualizado en algunos años). Si estoy escribiendo un pequeño módulo de código abierto y quiero que cualquiera pueda usarlo fácilmente, seguiré un patrón similar al de la respuesta de Caolan (arriba): escribí una publicación en el 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 de Ampersand ), los escribiré en formato CommonJS y Browserify .


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 se envíen 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 tanto en el servidor como en los scripts del cliente. Estoy utilizando ese enfoque para un simple juego 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 en cada tic para asegurarse de que nadie haga trampas.

Mi sistema de compilación para el juego es un simple script de 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, por lo que puedo usar todo el material del preprocesador normal como #include, #define, #ifdef , etc.


Recomendaría mirar el RequireJs El problema es que el patrón de módulo CommonJS que utiliza Node.js por defecto no es asíncrono, lo que bloquea la carga en el navegador web. RequireJS utiliza el patrón de AMD, que es asíncrono y compatible con el servidor y el cliente, siempre que use el adaptador r.js


Si desea escribir su navegador con el estilo de Node.js, puede intentar la dualify .

No hay compilación de código del navegador, por lo que puede escribir su aplicación sin limitaciones.


Tal vez esto no esté totalmente en línea con la pregunta, pero pensé que compartiría esto.

Quería hacer un par de funciones simples de utilidad de cadena, declaradas en String.prototype, disponibles tanto para el nodo como para el navegador. Simplemente guardo estas funciones en un archivo llamado utilities.js (en una subcarpeta) y puedo hacer referencia fácilmente a ellas 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

var utilities = require(''./static/js/utilities'')

my_browser_code.html

<script src="/static/js/utilities.js"></script>

Espero que esta información sea útil para alguien que no sea yo.


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:

(function(window){ var jQuery = ''blah''; if (typeof module === "object" && module && typeof module.exports === "object") { // Expose jQuery as module.exports in loaders that implement the Node // module pattern (including browserify). Do not create the global, since // the user will be storing it themselves locally, and globals are frowned // upon in the Node module world. module.exports = jQuery; } else { // Otherwise expose jQuery to the global object as usual window.jQuery = window.$ = jQuery; // Register as a named AMD module, since jQuery can be concatenated with other // files that may use define, but not via a proper concatenation script that // understands anonymous AMD modules. A named AMD is safest and most robust // way to register. Lowercase jquery is used because AMD module names are // derived from file names, and jQuery is normally delivered in a lowercase // file name. Do this after creating the global so that if an AMD module wants // to call noConflict to hide this version of jQuery, it will work. if (typeof define === "function" && define.amd) { define("jquery", [], function () { return jQuery; }); } } })(this)


nowjs también vale la pena ver. Le permite llamar al lado del servidor desde el lado del cliente y las funciones del lado del servidor desde el lado del servidor


Si desea escribir un módulo que se pueda usar tanto en el lado del cliente como en el del servidor, tengo una breve publicación en el blog sobre un método rápido y fácil: Escribiendo para Node.js y el navegador , esencialmente lo siguiente (donde this es lo mismo que window ):

(function(exports){ // Your code goes here exports.test = function(){ return ''hello world'' }; })(typeof exports === ''undefined''? this[''mymodule'']={}: exports);

Alternativamente, hay algunos proyectos que apuntan a implementar la API Node.js en el lado del cliente, como los gemini de Marak .

Es posible que también le interese el DNode , que le permite exponer una función de JavaScript para que pueda llamarse desde otra máquina utilizando un protocolo de red simple basado en JSON.