Tải và thực thi tệp js bên ngoài trong node.js với quyền truy cập vào các biến cục bộ?


130

Có dễ dàng / có thể thực hiện một include('./path/to/file')loại lệnh đơn giản trong node.js không?

Tất cả những gì tôi muốn làm là có quyền truy cập vào các biến cục bộ và chạy một tập lệnh. Làm thế nào để mọi người thường tổ chức các dự án node.js lớn hơn một thế giới xin chào đơn giản? (Một trang web năng động đầy đủ chức năng)

Ví dụ tôi muốn có các thư mục như:

/models

/views

... Vân vân


Cũng có thể bao gồm một tập lệnh từ một URL bên ngoài (thay vì một tệp cục bộ). Xem tại đây: pastebin.com/WkvHjGsG
Anderson Green

Kịch bản trên chỉ hoạt động chính xác nếu bạn tạo một thư mục được gọi downloadedModulestrong cùng thư mục với tập lệnh.
Anderson Green

Câu trả lời:


134

Chỉ cần làm một require('./yourfile.js');

Khai báo tất cả các biến mà bạn muốn truy cập bên ngoài dưới dạng các biến toàn cục. Vì vậy, thay vì

var a = "hello" nó sẽ là

GLOBAL.a="hello" hoặc chỉ

a = "hello"

Điều này rõ ràng là xấu. Bạn không muốn làm ô nhiễm phạm vi toàn cầu. Thay vào đó, phương thức đề xuất là exportcác hàm / biến của bạn.

Nếu bạn muốn mô hình MVC hãy xem Geddy.


3
Như một lưu ý phụ .. tôi yêu Express. Bạn cũng nên kiểm tra nó, miễn là bạn không đặc biệt về MVC.
Shripad Krishna

42
Khi bạn nói "điều này rõ ràng là xấu", "điều này" đề cập đến điều gì?
Anderson Green

1
@AndersonGreen - Ông có nghĩa là đặt các biến trong phạm vi toàn cầu.
Tim

77
@AndersonGreen: Xin vui lòng cho tôi biết đó là một trò đùa cực kỳ thông minh về phạm vi ;-)
Dusty J

6
Nó giúp tôi học được cách requirenhìn trong các mô-đun npm của bạn nếu bạn không đặt tiền tố cho đường dẫn của mình bằng một cái gì đó như./
Dylan Valade

93

Bạn cần hiểu CommonJS, đây là một mẫu để xác định các mô-đun. Bạn không nên lạm dụng phạm vi TOÀN CẦU luôn luôn là điều xấu, thay vào đó bạn có thể sử dụng mã thông báo 'xuất khẩu', như thế này:

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

Và mã máy khách sẽ sử dụng mô-đun của chúng tôi:

// client.js

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

Mã này được trích xuất từ ​​API tài liệu của node.js:

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

Ngoài ra, nếu bạn muốn sử dụng một cái gì đó như Rails hoặc Sinatra, tôi khuyên bạn nên Express (Tôi không thể đăng URL, xấu hổ về Stack Overflow!)


64

Nếu bạn đang viết mã cho Node, sử dụng các mô-đun Node như được mô tả bởi Ivan thì không còn nghi ngờ gì nữa.

Tuy nhiên, nếu bạn cần tải JavaScript đã được viết và không biết về nút, vmmô-đun là cách để đi (và chắc chắn là thích hợp hơn eval).

Ví dụ, đây là execfilemô-đun của tôi , đánh giá tập lệnh tại pathmột trong hai contexthoặc bối cảnh toàn cầu:

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

Cũng lưu ý: các mô-đun được tải require(…)không có quyền truy cập vào bối cảnh toàn cầu.


1
Cảm ơn vì món tiền boa này. Trường hợp sử dụng thực tế là khi bạn cần tải các mô-đun adhoc. Nói như một mẫu đăng ký trong đó bạn sẽ có 1000 mô-đun đăng ký trong một dịch vụ trung tâm. Nó sạch sẽ hơn và được thiết kế tốt hơn để quét các mô-đun và tải từng cái một thay vì thực hiện 1000 yêu cầu trong dịch vụ của bạn ...
Assaf Moldavsky

Nút hỗ trợ yêu cầu động, vì vậy không có lý do gì để sử dụng mẫu này khi tải động các mô-đun nhận biết Node. Trên thực tế, nó rất có hại khi sử dụng ở đó, vì nó bỏ qua Node require.cache, vì vậy một tệp có thể được tải nhiều lần.
David Wolever 17/8/2016

Ok, để giải quyết trường hợp mà tôi đã trình bày khi bạn có 1000 mô-đun nơi mỗi mô-đun đang đăng ký vào một dịch vụ đăng ký, làm thế nào để bạn sử dụng những gì bạn đã đề xuất mà không có 1000 yêu cầu báo cáo trong dịch vụ đăng ký?
Assaf Moldavsky

1
Cũng requiregiống như bình thường: function loadService(name) { return require('./services/' + name); }sau đó liệt kê các dịch vụ tuy nhiên có ý nghĩa cho ứng dụng.
David Wolever

Đúng, nhưng điều đó ngụ ý rằng bạn phải biết tất cả 1000 mô-đun trong dịch vụ đăng ký. Điều này không tốt hơn là có 1000 yêu cầu báo cáo. Toàn bộ ý tưởng là dịch vụ đăng ký không biết tất cả các mô-đun và trên thực tế, nó quan tâm đến chúng. Các mô-đun đăng ký ad hoc vào dịch vụ đăng ký. Điều đó có ý nghĩa?
Assaf Moldavsky

7

Nếu bạn đang dự định tải các chức năng hoặc đối tượng của tệp javascript bên ngoài, hãy tải vào ngữ cảnh này bằng mã sau - lưu ý phương thức runIn ThisContext:

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
Sau rất nhiều tìm kiếm và tìm kiếm, kỹ thuật này đã làm việc với tôi. Các tệp của tôi được viết để trình duyệt sử dụng trực tiếp và khai báo một biến, ví dụ: const aVar = {thing: 'a'}
lucsan

3

Mở rộng trên @Shripad 's và @Ivan câu trả lời' s, tôi sẽ khuyên bạn nên sử dụng tiêu chuẩn của Node.js module.export chức năng.

Trong tệp của bạn cho các hằng số ( ví dụ constants.js ), bạn sẽ viết các hằng như thế này:

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

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

Sau đó, trong tệp mà bạn muốn sử dụng các hằng số đó, hãy viết đoạn mã sau:

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

Nếu bạn chưa bao giờ thấy const { ... }cú pháp trước đó: đó là sự phá hủy bài tập .


0

Xin lỗi vì đã hồi sinh. Bạn có thể sử dụng mô đun child_ process để thực thi các tệp js bên ngoài trong 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}`);
    }
});
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.