¿Cargar y ejecutar un archivo js externo en node.js con acceso a variables locales?

130

¿Es fácil / posible hacer un include('./path/to/file')tipo simple de comando en node.js?

Todo lo que quiero hacer es tener acceso a variables locales y ejecutar un script. ¿Cómo suelen organizar las personas los proyectos de node.js que son más grandes que un simple hola mundo? (Un sitio web dinámico totalmente funcional)

Por ejemplo, me gustaría tener directorios como:

/models

/views

... etc.

Travis
fuente
También es posible incluir un script desde una URL externa (en lugar de un archivo local). Ver aquí: pastebin.com/WkvHjGsG
Anderson Green
El script anterior solo funciona correctamente si crea una carpeta llamada downloadedModulesen el mismo directorio que el script.
Anderson Green

Respuestas:

134

Solo haz un require('./yourfile.js');

Declare todas las variables que desea acceso externo como variables globales. Entonces en lugar de

var a = "hello" será

GLOBAL.a="hello" o solo

a = "hello"

Esto obviamente es malo. No quieres contaminar el alcance global. En cambio, el método de sugerencia es para exportsus funciones / variables.

Si quieres el patrón MVC, mira a Geddy.

Shripad Krishna
fuente
3
Como nota al margen ... me encanta Express. También debe verificarlo, siempre que no sea tan particular acerca de MVC.
Shripad Krishna
43
Cuando dices "esto es obviamente malo", ¿a qué se refiere "esto"?
Anderson Green
1
@AndersonGreen - Se refiere a poner variables en alcance global.
Tim
77
@AndersonGreen: Por favor dime que fue una broma extremadamente inteligente sobre el alcance ;-)
Dusty J
66
Me ayudó a aprender que se requireve en tus módulos npm si no prefijas tu camino con algo como./
Dylan Valade
93

Debe comprender CommonJS, que es un patrón para definir módulos. No debe abusar del alcance GLOBAL que siempre es algo malo, sino que puede usar el token 'exportaciones', como este:

// circle.js

var PI = 3.14; // PI will not be accessible from outside this module

exports.area = function (r) {
  return PI * r * r;
};

exports.circumference = function (r) {
  return 2 * PI * r;
};

Y el código del cliente que usará nuestro módulo:

// client.js

var circle = require('./circle');
console.log( 'The area of a circle of radius 4 is '
           + circle.area(4));

Este código se extrajo de la API de documentación de node.js:

http://nodejs.org/docs/v0.3.2/api/modules.html

Además, si desea usar algo como Rails o Sinatra, le recomiendo Express (no pude publicar la URL, ¡lástima el desbordamiento de pila!)

Ivan Torres
fuente
64

Si está escribiendo código para Node, usar módulos de Node como lo describe Ivan es sin duda el camino a seguir.

Sin embargo, si necesita cargar JavaScript que ya se ha escrito y no conoce el nodo, el vmmódulo es el camino a seguir (y definitivamente preferible eval).

Por ejemplo, aquí está mi execfilemódulo, que evalúa el script pathen contexto en el contexto global:

var vm = require("vm");
var fs = require("fs");
module.exports = function(path, context) {
  var data = fs.readFileSync(path);
  vm.runInNewContext(data, context, path);
}

También tenga en cuenta: los módulos cargados con require(…)no tienen acceso al contexto global.

David Wolever
fuente
1
Gracias por este consejo El caso de uso real es cuando necesita cargar módulos ad hoc. Digamos como un patrón de registro donde tendrías 1000 módulos que se registrarían en un servicio central. Es mucho más limpio y mejor diseño escanear en busca de módulos y cargarlos uno por uno en lugar de hacer 1000 declaraciones obligatorias en su servicio ...
Assaf Moldavsky
Node admite requisitos dinámicos, por lo que no hay razón para usar este patrón al cargar dinámicamente módulos compatibles con Node. De hecho, es activamente perjudicial usarlo allí, ya que omite los nodos require.cache, por lo que un solo archivo puede cargarse varias veces.
David Wolever
Ok, entonces para resolver el caso que presenté donde tienes 1000 módulos donde cada uno se está registrando en un servicio de registro, ¿cómo utilizas lo que has propuesto sin tener 1000 declaraciones requeridas en el servicio de registro?
Assaf Moldavsky
1
Justo requirecomo normal: function loadService(name) { return require('./services/' + name); }a continuación, se enumeran los servicios sin embargo tiene sentido para la aplicación.
David Wolever
Correcto, pero eso implica que debe conocer todos los 1000 módulos en el servicio de registro. Lo cual no es mejor que tener un 1000 requieren declaraciones. La idea es que el servicio de registro no conoce todos los módulos y, de hecho, se preocupa por ellos. Los módulos se registran ad hoc en el servicio de registro. ¿Tiene sentido?
Assaf Moldavsky
7

Si planea cargar las funciones u objetos de un archivo javascript externo, cargue en este contexto utilizando el siguiente código: tenga en cuenta el método runInThisContext:

var vm = require("vm");
var fs = require("fs");

var data = fs.readFileSync('./externalfile.js');
const script = new vm.Script(data);
script.runInThisContext();

// here you can use externalfile's functions or objects as if they were instantiated here. They have been added to this context. 
Rox
fuente
2
Después de mucha búsqueda y búsqueda, esta técnica funcionó para mí. Mis archivos están escritos para que el navegador los use directamente y declare una variable, por ejemplo: const aVar = {thing: 'a'}
lucsan
3

Ampliando la respuesta de @Shripad y @Ivan , recomendaría que utilice la funcionalidad de exportación del módulo estándar de Node.js.

En su archivo de constantes ( p constants.js . Ej. ), Escribiría constantes como este:

const CONST1 = 1;
module.exports.CONST1 = CONST1;

const CONST2 = 2;
module.exports.CONST2 = CONST2;

Luego, en el archivo en el que desea usar esas constantes, escriba el siguiente código:

const {CONST1 , CONST2} = require('./constants.js');

Si nunca const { ... }antes has visto la sintaxis: esa es una tarea desestructuradora .

Jonathan Benn
fuente
0

Perdón por la resurrección. Puede usar el módulo child_process para ejecutar archivos js externos en node.js

var child_process = require('child_process');

//EXECUTE yourExternalJsFile.js
child_process.exec('node yourExternalJsFile.js', (error, stdout, stderr) => {
    console.log(`${stdout}`);
    console.log(`${stderr}`);
    if (error !== null) {
        console.log(`exec error: ${error}`);
    }
});
lupu51nfactum N778
fuente