โหลดและเรียกใช้ไฟล์ js ภายนอกใน node.js ด้วยการเข้าถึงตัวแปรโลคัล?


130

มันง่าย / เป็นไปได้ไหมที่จะทำinclude('./path/to/file')คำสั่งแบบธรรมดาใน node.js?

สิ่งที่ฉันต้องการทำคือเข้าถึงตัวแปรภายในและเรียกใช้สคริปต์ โดยทั่วไปแล้วผู้คนจะจัดระเบียบโปรเจ็กต์ node.js ที่ใหญ่กว่า hello world ง่ายๆได้อย่างไร (เว็บไซต์แบบไดนามิกที่ทำงานได้อย่างสมบูรณ์)

ตัวอย่างเช่นฉันต้องการมีไดเรกทอรีเช่น:

/models

/views

... ฯลฯ


นอกจากนี้ยังสามารถรวมสคริปต์จาก URL ภายนอก (แทนที่จะเป็นไฟล์ในเครื่อง) ดูที่นี่: pastebin.com/WkvHjGsG
Anderson Green

สคริปต์ด้านบนจะทำงานได้อย่างถูกต้องก็ต่อเมื่อคุณสร้างโฟลเดอร์ที่เรียกว่าdownloadedModulesในไดเร็กทอรีเดียวกับสคริปต์
Anderson Green

คำตอบ:


134

เพียงแค่ทำ require('./yourfile.js');

ประกาศตัวแปรทั้งหมดที่คุณต้องการเข้าถึงภายนอกเป็นตัวแปรส่วนกลาง ดังนั้นแทนที่จะเป็น

var a = "hello" มันจะเป็น

GLOBAL.a="hello" หรือเพียงแค่

a = "hello"

นี่มันแย่อย่างเห็นได้ชัด คุณไม่ต้องการที่จะสร้างมลพิษให้กับขอบเขตทั่วโลก แต่วิธีที่แนะนำคือการexportฟังก์ชัน / ตัวแปรของคุณ

หากคุณต้องการรูปแบบ MVC ลองดูที่ Geddy


3
ฉันชอบ Express. คุณควรตรวจสอบด้วยเช่นกันหากคุณไม่ใช่คนที่เชี่ยวชาญเกี่ยวกับ MVC
Shripad Krishna

43
เมื่อคุณพูดว่า "นี่ไม่ดีอย่างเห็นได้ชัด" "สิ่งนี้" หมายถึงอะไร?
Anderson Green

1
@AndersonGreen - เขาหมายถึงการวางตัวแปรไว้ในขอบเขตระดับโลก
ทิม

77
@AndersonGreen: โปรดบอกฉันว่านั่นเป็นเรื่องตลกที่ฉลาดมากเกี่ยวกับการกำหนดขอบเขต ;-)
Dusty J

6
มันช่วยให้ฉันเรียนรู้ว่าrequireรูปลักษณ์ในโมดูล npm ของคุณถ้าคุณไม่นำหน้าเส้นทางของคุณด้วยสิ่งที่ชอบ./
Dylan Valade

93

คุณต้องเข้าใจ CommonJS ซึ่งเป็นรูปแบบในการกำหนดโมดูล คุณไม่ควรใช้ขอบเขต GLOBAL ในทางที่ผิดซึ่งเป็นสิ่งที่ไม่ดีเสมอไป แต่คุณสามารถใช้โทเค็น 'การส่งออก' ได้เช่นนี้:

// 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;
};

และรหัสไคลเอนต์ที่จะใช้โมดูลของเรา:

// client.js

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

รหัสนี้ดึงมาจาก API เอกสาร node.js:

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

นอกจากนี้หากคุณต้องการใช้บางอย่างเช่น Rails หรือ Sinatra ฉันขอแนะนำ Express (ฉันโพสต์ URL ไม่ได้อับอายใน Stack Overflow!)


64

หากคุณกำลังเขียนโค้ดสำหรับ Node การใช้โมดูลโหนดตามที่ Ivan อธิบายไว้ไม่ต้องสงสัยเลยว่าจะไปได้อย่างไร

อย่างไรก็ตามหากคุณต้องการโหลด JavaScript ที่เขียนไปแล้วและไม่รู้จักโหนดไฟล์ vmโมดูลนี้ก็เป็นวิธีที่จะไป (และดีกว่าeval)

ตัวอย่างเช่นนี่คือexecfileโมดูลของฉันซึ่งประเมินสคริปต์ที่pathในcontextบริบทอย่างใดอย่างหนึ่งหรือบริบทส่วนกลาง:

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

โปรดทราบ: โมดูลที่โหลดโดยrequire(…)ไม่สามารถเข้าถึงบริบทส่วนกลางได้


1
ขอบคุณสำหรับเคล็ดลับนี้ กรณีการใช้งานจริงคือเมื่อคุณต้องการโหลดโมดูล adhoc พูดเหมือนกับรูปแบบการลงทะเบียนที่คุณจะมีโมดูล 1,000 โมดูลที่ลงทะเบียนในบริการส่วนกลาง การออกแบบที่สะอาดและดีกว่ามากในการสแกนหาโมดูลและโหลดทีละโมดูลแทนที่จะทำ 1,000 รายการต้องใช้งบในบริการของคุณ ...
Assaf Moldavsky

โหนดรองรับความต้องการแบบไดนามิกดังนั้นจึงไม่มีเหตุผลที่จะใช้รูปแบบนี้เมื่อโหลดโมดูลที่รับรู้โหนดแบบไดนามิก ในความเป็นจริงมันเป็นอันตรายอย่างมากที่จะใช้ที่นั่นเนื่องจากมันข้าม Node require.cacheดังนั้นไฟล์เดียวอาจถูกโหลดหลายครั้ง
David Wolever

ตกลงดังนั้นเพื่อแก้ปัญหากรณีที่ฉันนำเสนอว่าคุณมีโมดูล 1,000 โมดูลที่แต่ละโมดูลลงทะเบียนในบริการรีจิสทรีคุณจะใช้สิ่งที่คุณเสนอโดยไม่ต้องมีคำสั่ง 1,000 รายการในบริการรีจิสทรีได้อย่างไร
Assaf Moldavsky

1
เพียงแค่requireเหมือนปกติ: function loadService(name) { return require('./services/' + name); }แล้วรายการบริการ แต่จะทำให้ความรู้สึกสำหรับการประยุกต์ใช้
David Wolever

ถูกต้อง แต่นั่นหมายความว่าคุณต้องรู้โมดูลทั้งหมด 1,000 โมดูลในบริการรีจิสทรี ซึ่งไม่ดีไปกว่าการมีงบ 1000 แนวคิดทั้งหมดก็คือบริการรีจิสทรีไม่รู้จักโมดูลทั้งหมดและในความเป็นจริงมันดูแลเกี่ยวกับพวกเขา โมดูลลงทะเบียนเฉพาะกิจในบริการรีจิสทรี มันสมเหตุสมผลไหม
Assaf Moldavsky

7

หากคุณกำลังวางแผนที่จะโหลดฟังก์ชั่นหรืออ็อบเจ็กต์ของไฟล์ javascript ภายนอกให้โหลดบนบริบทนี้โดยใช้โค้ดต่อไปนี้ - สังเกตเมธอด 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. 

2
หลังจากการค้นหาและความสนุกสนานมากมายเทคนิคนี้ได้ผลสำหรับฉัน ไฟล์ของฉันเขียนขึ้นเพื่อให้เบราว์เซอร์ใช้โดยตรงและประกาศตัวแปรเช่น const aVar = {thing: 'a'}
lucsan

3

ขยายตัวใน@Shripad 's และ@Ivanคำตอบของผมจะแนะนำให้คุณใช้มาตรฐาน Node.js ของmodule.exportการทำงาน

ในไฟล์ของคุณสำหรับค่าคงที่ ( เช่น constants.js ) คุณต้องเขียนค่าคงที่ดังนี้:

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

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

จากนั้นในไฟล์ที่คุณต้องการใช้ค่าคงที่ให้เขียนโค้ดต่อไปนี้:

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

ถ้าคุณไม่เคยเห็นconst { ... }ไวยากรณ์ก่อนที่destructuring ที่ได้รับมอบหมาย


0

ขออภัยในการฟื้นคืนชีพ คุณสามารถใช้โมดูล child_process เพื่อเรียกใช้ไฟล์ js ภายนอกใน 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}`);
    }
});
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.