javascript - En Node.js, ¿cómo “incluyo” las funciones de mis otros archivos?
import header (23)
Incluir archivo y ejecutarlo en un contexto dado (no global)
fileToInclude.js
define({
"data": "XYZ"
});
main.js
var fs = require("fs");
var vm = require("vm");
function include(path, context) {
var code = fs.readFileSync(path, ''utf-8'');
vm.runInContext(code, vm.createContext(context));
}
// Include file
var customContext = {
"define": function (data) {
console.log(data);
}
};
include(''./fileToInclude.js'', customContext);
Digamos que tengo un archivo llamado app.js. Bastante simple:
var express = require(''express'');
var app = express.createServer();
app.set(''views'', __dirname + ''/views'');
app.set(''view engine'', ''ejs'');
app.get(''/'', function(req, res){
res.render(''index'', {locals: {
title: ''NowJS + Express Example''
}});
});
app.listen(8080);
¿Qué pasa si tengo una función dentro de "tools.js". ¿Cómo los importaría para usar en apps.js?
O ... ¿se supone que convierta las "herramientas" en un módulo y luego lo requiera? << parece difícil, prefiero hacer la importación básica del archivo tools.js.
¿Te gusta tener un archivo abc.txt
y muchos más?
Cree 2 archivos: fileread.js
y fetchingfile.js
, luego en fileread.js
escriba este código:
function fileread(filename) {
var contents= fs.readFileSync(filename);
return contents;
}
var fs = require("fs"); // file system
//var data = fileread("abc.txt");
module.exports.fileread = fileread;
//data.say();
//console.log(data.toString());
}
En fetchingfile.js
escribe este código:
function myerror(){
console.log("Hey need some help");
console.log("type file=abc.txt");
}
var ags = require("minimist")(process.argv.slice(2), { string: "file" });
if(ags.help || !ags.file) {
myerror();
process.exit(1);
}
var hello = require("./fileread.js");
var data = hello.fileread(ags.file); // importing module here
console.log(data.toString());
Ahora, en un terminal: $ node fetchingfile.js --file = abc.txt
Usted está pasando el nombre del archivo como un argumento, además de incluir todos los archivos en readfile.js
en lugar de pasarlo.
Gracias
App.js:
var mymouldle = require("C:/Users/Yourname/tools.js")
//replace C:/Users/Yourname/tools.js with the path to your tools.js
NOTA: El archivo debe comenzar con C: o D: o E: de lo contrario, Node.js cree que el molde está en la carpeta de moldes del nodo
Aquí hay una explicación clara y simple:
Contenido de Server.js:
// Include the public functions from ''helpers.js''
var helpers = require(''./helpers'');
// Let''s assume this is the data which comes from the database or somewhere else
var databaseName = ''Walter'';
var databaseSurname = ''Heisenberg'';
// Use the function from ''helpers.js'' in the main file, which is server.js
var fullname = helpers.concatenateNames(databaseName, databaseSurname);
Contenido de Helpers.js:
// ''module.exports'' is a node.JS specific feature, it does not work with regular JavaScript
module.exports =
{
// This is the function which will be called in the main file, which is server.js
// The parameters ''name'' and ''surname'' will be provided inside the function
// when the function is called in the main file.
// Example: concatenameNames(''John,''Doe'');
concatenateNames: function (name, surname)
{
var wholeName = name + " " + surname;
return wholeName;
},
sampleFunctionTwo: function ()
{
}
};
// Private variables and functions which will not be accessible outside this file
var privateFunction = function ()
{
};
Crea dos archivos js
// File cal.js
module.exports = {
sum: function(a,b) {
return a+b
},
multiply: function(a,b) {
return a*b
}
};
Archivo js principal
// File app.js
var tools = require("./cal.js");
var value = tools.sum(10,20);
console.log("Value: "+value);
Salida
value: 30
El módulo vm en Node.js proporciona la capacidad de ejecutar código JavaScript dentro del contexto actual (incluido el objeto global). Consulte http://nodejs.org/docs/latest/api/vm.html#vm_vm_runinthiscontext_code_filename
Tenga en cuenta que, a partir de hoy, hay un error en el módulo vm que evita que runInThisContext haga lo correcto cuando se invoca desde un nuevo contexto. Esto solo importa si su programa principal ejecuta código dentro de un nuevo contexto y luego ese código llama runInThisContext. Ver https://github.com/joyent/node/issues/898
Lamentablemente, el enfoque con (global) que Fernando sugirió no funciona para funciones nombradas como "function foo () {}"
En resumen, aquí hay una función de inclusión () que funciona para mí:
function include(path) {
var code = fs.readFileSync(path, ''utf-8'');
vm.runInThisContext(code, path);
}
Esta es la mejor manera que he creado hasta ahora.
var fs = require(''fs''),
includedFiles_ = {};
global.include = function (fileName) {
var sys = require(''sys'');
sys.puts(''Loading file: '' + fileName);
var ev = require(fileName);
for (var prop in ev) {
global[prop] = ev[prop];
}
includedFiles_[fileName] = true;
};
global.includeOnce = function (fileName) {
if (!includedFiles_[fileName]) {
include(fileName);
}
};
global.includeFolderOnce = function (folder) {
var file, fileName,
sys = require(''sys''),
files = fs.readdirSync(folder);
var getFileName = function(str) {
var splited = str.split(''.'');
splited.pop();
return splited.join(''.'');
},
getExtension = function(str) {
var splited = str.split(''.'');
return splited[splited.length - 1];
};
for (var i = 0; i < files.length; i++) {
file = files[i];
if (getExtension(file) === ''js'') {
fileName = getFileName(file);
try {
includeOnce(folder + ''/'' + file);
} catch (err) {
// if (ext.vars) {
// console.log(ext.vars.dump(err));
// } else {
sys.puts(err);
// }
}
}
}
};
includeFolderOnce(''./extensions'');
includeOnce(''./bin/Lara.js'');
var lara = new Lara();
Aún necesita informar lo que quiere exportar.
includeOnce(''./bin/WebServer.js'');
function Lara() {
this.webServer = new WebServer();
this.webServer.start();
}
Lara.prototype.webServer = null;
module.exports.Lara = Lara;
Funcionó conmigo como la siguiente ...
Lib1.js
//Any other private code here
// Code you want to export
exports.function1 = function1 (params) {.......};
exports.function2 = function2 (params) {.......};
// Again any private code
ahora en el archivo Main.js necesita incluir Lib1.js
var mylib = requires(''lib1.js'');
mylib.function1(params);
mylib.function2(params);
Recuerde colocar el archivo Lib1.js en la carpeta node_modules .
No necesitas nuevas funciones ni nuevos módulos. Simplemente necesita ejecutar el módulo al que está llamando si no desea usar el espacio de nombres.
en tools.js
module.exports = function() {
this.sum = function(a,b) { return a+b };
this.multiply = function(a,b) { return a*b };
//etc
}
en app.js
o en cualquier otro .js como myController.js:
en lugar de
var tools = require(''tools.js'')
que nos obliga a usar un espacio de nombres y herramientas de llamada como tools.sum(1,2);
podemos simplemente llamar
require(''tools.js'')();
y entonces
sum(1,2);
En mi caso tengo un archivo con controladores ctrls.js
module.exports = function() {
this.Categories = require(''categories.js'');
}
y puedo usar las Categories
en todos los contextos como clase pública después de require(''ctrls.js'')()
Otra forma de hacer esto en mi opinión, es ejecutar todo en el archivo lib cuando llama a la función require () usando la función (/ / cosas aquí * /) {}) (); Hacer esto hará que todas estas funciones tengan un alcance global, exactamente igual que la solución eval () .
src / lib.js
(function () {
funcOne = function() {
console.log(''mlt funcOne here'');
}
funcThree = function(firstName) {
console.log(firstName, ''calls funcThree here'');
}
name = "Mulatinho";
myobject = {
title: ''Node.JS is cool'',
funcFour: function() {
return console.log(''internal funcFour() called here'');
}
}
})();
Y luego en su código principal puede llamar a sus funciones por su nombre como:
main.js
require(''./src/lib'')
funcOne();
funcThree(''Alex'');
console.log(name);
console.log(myobject);
console.log(myobject.funcFour());
Hará esta salida
bash-3.2$ node -v
v7.2.1
bash-3.2$ node main.js
mlt funcOne here
Alex calls funcThree here
Mulatinho
{ title: ''Node.JS is cool'', funcFour: [Function: funcFour] }
internal funcFour() called here
undefined
Preste atención a lo indefinido cuando llame a mi object.funcFour () , será lo mismo si carga con eval () . Espero eso ayude :)
Otro método cuando se usa el framework node.js y express.js
var f1 = function(){
console.log("f1");
}
var f2 = function(){
console.log("f2");
}
module.exports = {
f1 : f1,
f2 : f2
}
almacene esto en un archivo js llamado sy en la carpeta de estadísticas
Ahora para usar la función.
var s = require(''../statics/s'');
s.f1();
s.f2();
Puede poner sus funciones en variables globales, pero es una mejor práctica simplemente convertir su script de herramientas en un módulo. Realmente no es demasiado difícil, solo adjunte su API pública al objeto de exports
. Eche un vistazo al módulo de exportaciones Entender Node.js para más detalles.
Puede requerir cualquier archivo js, solo necesita declarar lo que quiere exponer.
// tools.js
// ========
module.exports = {
foo: function () {
// whatever
},
bar: function () {
// whatever
}
};
var zemba = function () {
}
Y en su archivo de aplicación:
// app.js
// ======
var tools = require(''./tools'');
console.log(typeof tools.foo); // => ''function''
console.log(typeof tools.bar); // => ''function''
console.log(typeof tools.zemba); // => undefined
Se me ha ocurrido un método bastante burdo de manejar esto para las plantillas HTML. De manera similar a PHP <?php include("navigation.html"); ?>
<?php include("navigation.html"); ?>
server.js
var fs = require(''fs'');
String.prototype.filter = function(search,replace){
var regex = new RegExp("{{" + search.toUpperCase() + "}}","ig");
return this.replace(regex,replace);
}
var navigation = fs.readFileSync(__dirname + "/parts/navigation.html");
function preProcessPage(html){
return html.filter("nav",navigation);
}
var express = require(''express'');
var app = express();
// Keep your server directory safe.
app.use(express.static(__dirname + ''/public/''));
// Sorta a server-side .htaccess call I suppose.
app.get("/page_name/",function(req,res){
var html = fs.readFileSync(__dirname + "/pages/page_name.html");
res.send(preProcessPage(html));
});
page_name.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>NodeJS Templated Page</title>
<link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="/css/font-awesome.min.css">
<!-- Scripts Load After Page -->
<script type="text/javascript" src="/js/jquery.min.js"></script>
<script type="text/javascript" src="/js/tether.min.js"></script>
<script type="text/javascript" src="/js/bootstrap.min.js"></script>
</head>
<body>
{{NAV}}
<!-- Page Specific Content Below Here-->
</body>
</html>
navigation.html
<nav></nav>
Resultado de la página cargada
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>NodeJS Templated Page</title>
<link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="/css/font-awesome.min.css">
<!-- Scripts Load After Page -->
<script type="text/javascript" src="/js/jquery.min.js"></script>
<script type="text/javascript" src="/js/tether.min.js"></script>
<script type="text/javascript" src="/js/bootstrap.min.js"></script>
</head>
<body>
<nav></nav>
<!-- Page Specific Content Below Here-->
</body>
</html>
Si desea aprovechar las múltiples CPU y la arquitectura de microservicio, para acelerar las cosas ... Use RPC en procesos bifurcados.
Suena complejo, pero es simple si usas octopus .
Aquí hay un ejemplo:
en tools.js añadir:
const octopus = require(''octopus'');
var rpc = new octopus(''tools:tool1'');
rpc.over(process, ''processRemote'');
var sum = rpc.command(''sum''); // This is the example tool.js function to make available in app.js
sum.provide(function (data) { // This is the function body
return data.a + data.b;
});
en app.js, agregue:
const { fork } = require(''child_process'');
const octopus = require(''octopus'');
const toolprocess = fork(''tools.js'');
var rpc = new octopus(''parent:parent1'');
rpc.over(toolprocess, ''processRemote'');
var sum = rpc.command(''sum'');
// Calling the tool.js sum function from app.js
sum.call(''tools:*'', {
a:2,
b:3
})
.then((res)=>console.log(''response : '',rpc.parseResponses(res)[0].response));
revelación: soy el autor de Octopus y lo construí para un caso de uso similar al mío, ya que no pude encontrar ninguna biblioteca liviana.
Si, a pesar de todas las demás respuestas, aún desea incluir tradicionalmente un archivo en un archivo de origen node.js, puede usar esto:
var fs = require(''fs'');
// file is included here:
eval(fs.readFileSync(''tools.js'')+'''');
- La concatenación de cadena vacía
+''''
es necesaria para obtener el contenido del archivo como una cadena y no un objeto (también puede usar.toString()
si lo prefiere). - El eval () no se puede usar dentro de una función y debe llamarse dentro del alcance global, de lo contrario no se podrá acceder a las funciones o variables (es decir, no se puede crear una función de utilidad de
include()
o algo por el estilo).
Tenga en cuenta que en la mayoría de los casos esto es una mala práctica y que, en cambio, debe escribir un módulo . Sin embargo, hay situaciones raras, donde lo que realmente desea es la contaminación de su contexto local / espacio de nombres.
Actualización 2015-08-06
Tenga en cuenta que esto no funcionará con "use strict";
(cuando está en "modo estricto" ) porque el código que realiza la importación no puede acceder a las funciones y variables definidas en el archivo "importado". El modo estricto impone algunas reglas definidas por las versiones más recientes del estándar de idioma. Esta puede ser otra razón para evitar la solución descrita aquí.
Simplemente puede require(''./filename'')
.
P.ej.
// file: index.js
var express = require(''express'');
var app = express();
var child = require(''./child'');
app.use(''/child'', child);
app.get(''/'', function (req, res) {
res.send(''parent'');
});
app.listen(process.env.PORT, function () {
console.log(''Example app listening on port ''+process.env.PORT+''!'');
});
// file: child.js
var express = require(''express''),
child = express.Router();
console.log(''child'');
child.get(''/child'', function(req, res){
res.send(''Child2'');
});
child.get(''/'', function(req, res){
res.send(''Child'');
});
module.exports = child;
Tenga en cuenta que:
- no se puede escuchar el puerto PORT en el archivo secundario, solo el módulo padre express tiene el receptor PORT
- El niño está usando ''Enrutador'', no el modo expreso principal.
Solo quiero agregar, en caso de que necesite solo ciertas funciones importadas desde tools.js , entonces puede usar una asignación de desestructuración que sea compatible con node.js desde la versión 6.4 - vea node.green .
Ejemplo : (ambos archivos están en la misma carpeta)
herramientas.js
module.exports = {
sum: function(a,b) {
return a + b;
},
isEven: function(a) {
return a % 2 == 0;
}
};
main.js
const { isEven } = require(''./tools.js'');
console.log(isEven(10));
salida: true
Esto también evita que asigne esas funciones como propiedades de otro objeto como es el caso en la siguiente asignación (común):
const tools = require(''./tools.js'');
donde necesita llamar a tools.isEven(10)
.
NOTA:
No olvide colocar el nombre del archivo con la ruta correcta, incluso si ambos archivos están en la misma carpeta, debe usar el prefijo ./
De los documentos de Node.js :
Sin un ''/'', ''./'' o ''../'' inicial para indicar un archivo, el módulo debe ser un módulo central o debe cargarse desde una carpeta node_modules.
También estaba buscando una función ''include'' de NodeJS y verifiqué la solución propuesta por Udo G : consulte el mensaje https://.com/a/8744519/2979590 . Su código no funciona con mis archivos JS incluidos. Finalmente resolví el problema así:
var fs = require("fs");
function read(f) {
return fs.readFileSync(f).toString();
}
function include(f) {
eval.apply(global, [read(f)]);
}
include(''somefile_with_some_declarations.js'');
Claro, eso ayuda.
También estaba buscando una opción para incluir código sin escribir módulos, resp. use las mismas fuentes independientes probadas de un proyecto diferente para un servicio Node.js, y la respuesta de hizo por mí.
El beneficio es que no contamina el espacio de nombres, no tengo problemas con el "use strict";
y funciona bien.
Aquí una muestra completa :
Script para cargar - /lib/foo.js
"use strict";
(function(){
var Foo = function(e){
this.foo = e;
}
Foo.prototype.x = 1;
return Foo;
}())
SampleModule - index.js
"use strict";
const fs = require(''fs'');
const path = require(''path'');
var SampleModule = module.exports = {
instAFoo: function(){
var Foo = eval.apply(
this, [fs.readFileSync(path.join(__dirname, ''/lib/foo.js'')).toString()]
);
var instance = new Foo(''bar'');
console.log(instance.foo); // ''bar''
console.log(instance.x); // ''1''
}
}
Espero que esto haya sido útil de alguna manera.
Udo G. dijo:
- El eval () no se puede usar dentro de una función y debe llamarse dentro del alcance global, de lo contrario no se podrá acceder a las funciones o variables (es decir, no se puede crear una función de utilidad de inclusión () o algo por el estilo).
Tiene razón, pero hay una manera de afectar el alcance global desde una función. Mejorando su ejemplo:
function include(file_) {
with (global) {
eval(fs.readFileSync(file_) + '''');
};
};
include(''somefile_with_some_declarations.js'');
// the declarations are now accessible here.
Espero que ayude.
digamos que queremos llamar a la función ping () y agregar (30,20) que está en el archivo lib.js de main.js
main.js
lib = require("./lib.js")
output = lib.ping();
console.log(output);
//Passing Parameters
console.log("Sum of A and B = " + lib.add(20,30))
lib.js
this.ping=function ()
{
return "Ping Success"
}
//Functions with parameters
this.add=function(a,b)
{
return a+b
}
app.js
let { func_name } = require(''path_to_tools.js'');
func_name(); //function calling
herramientas.js
let func_name = function() {
...
//function body
...
};
module.exports = { func_name };