Node.js 서버에서 사용하고 싶은 일부 기능이있는 타사 Javascript 라이브러리가 있습니다. (특히 내가 찾은 QuadTree javascript 라이브러리를 사용하고 싶습니다.) 그러나 이러한 라이브러리는 .js
“Node.js 라이브러리”가 아닌 단순한 파일입니다.
따라서 이러한 라이브러리는 exports.var_name
Node.js가 모듈에 대해 기대 하는 구문을 따르지 않습니다 . 지금까지 내가 그 방법을 이해 당신이 할 때, module = require('module_name');
또는 module = require('./path/to/file.js');
당신은 등 더 공개적으로 액세스 할 수있는 기능을 가진 모듈을하게 될 겁니다
내 질문은 “임의의 자바 스크립트 파일을 Node.js에로드하여 다시 작성하지 않고도 기능을 활용할 수 있도록하는 방법은 무엇 exports
입니까?”입니다.
저는 Node.js를 처음 사용하므로 작동 방식을 이해하는 데 눈에 띄는 구멍이 있는지 알려주십시오.
편집 : 더 많은 것을 연구하고 이제 Node.js가 사용하는 모듈 로딩 패턴이 실제로 CommonJS 라는 Javascript 라이브러리를로드하기 위해 최근 개발 된 표준의 일부임을 알았습니다 . Node.js 의 모듈 문서 페이지 에이 내용이 나와 있지만 지금까지 놓쳤습니다.
내 질문에 대한 대답은 “도서관의 작성자가 CommonJS 인터페이스를 작성하거나 직접 수행 할 때까지 기다리십시오”라는 것입니다.
답변
사용하는 것보다 훨씬 더 나은 방법이있다 eval
: vm
모듈.
예를 들어 다음은 전역 컨텍스트 또는 전역 컨텍스트 에서 execfile
스크립트를 평가하는 내 모듈입니다 .path
context
var vm = require("vm");
var fs = require("fs");
module.exports = function(path, context) {
context = context || {};
var data = fs.readFileSync(path);
vm.runInNewContext(data, context, path);
return context;
}
그리고 다음과 같이 사용할 수 있습니다.
> var execfile = require("execfile");
> // `someGlobal` will be a global variable while the script runs
> var context = execfile("example.js", { someGlobal: 42 });
> // And `getSomeGlobal` defined in the script is available on `context`:
> context.getSomeGlobal()
42
> context.someGlobal = 16
> context.getSomeGlobal()
16
example.js
포함하는 곳 :
function getSomeGlobal() {
return someGlobal;
}
이 방법의 가장 큰 장점은 실행 된 스크립트에서 전역 변수를 완벽하게 제어 할 수 있다는 것입니다. 사용자 정의 전역 (을 통해 context
)을 전달할 수 있으며 스크립트에 의해 생성 된 모든 전역이에 추가됩니다 context
. 구문 오류 등이 올바른 파일 이름으로보고되기 때문에 디버깅도 더 쉽습니다.
답변
이 상황에 대한 ‘가장 올바른’답이라고 생각합니다.
라는 스크립트 파일이 있다고 가정합니다 quadtree.js
.
node_module
이런 종류의 디렉터리 구조를 가진 사용자 지정 을 만들어야합니다 .
./node_modules/quadtree/quadtree-lib/
./node_modules/quadtree/quadtree-lib/quadtree.js
./node_modules/quadtree/quadtree-lib/README
./node_modules/quadtree/quadtree-lib/some-other-crap.js
./node_modules/quadtree/index.js
./node_modules/quadtree/quadtree-lib/
디렉토리의 모든 것은 타사 라이브러리의 파일입니다.
그러면 ./node_modules/quadtree/index.js
파일이 파일 시스템에서 해당 라이브러리를로드하고 제대로 내보내기 작업을 수행합니다.
var fs = require('fs');
// Read and eval library
filedata = fs.readFileSync('./node_modules/quadtree/quadtree-lib/quadtree.js','utf8');
eval(filedata);
/* The quadtree.js file defines a class 'QuadTree' which is all we want to export */
exports.QuadTree = QuadTree
이제 quadtree
다른 노드 모듈처럼 모듈을 사용할 수 있습니다 .
var qt = require('quadtree');
qt.QuadTree();
타사 라이브러리의 소스 코드를 변경할 필요가 없기 때문에이 방법을 좋아하므로 유지 관리가 더 쉽습니다. 업그레이드시해야 할 일은 소스 코드를 살펴보고 여전히 적절한 개체를 내보내고 있는지 확인하는 것입니다.
답변
가장 간단한 방법은 다음과 같습니다 eval(require('fs').readFileSync('./path/to/file.js', 'utf8'));
. 대화 형 셸에서 테스트 할 때 유용합니다.
답변
AFAIK, 실제로 모듈을로드해야하는 방법입니다. 그러나 내 보낸 모든 함수를 exports
개체 에 고정하는 대신 에 this
(그렇지 않으면 전역 개체가 될 수있는) 추가 할 수도 있습니다.
따라서 다른 라이브러리를 호환되도록 유지하려면 다음을 수행 할 수 있습니다.
this.quadTree = function () {
// the function's code
};
또는, 외부 라이브러리가 이미 자신의 네임 스페이스, 예를 들어이있는 경우 jQuery
(없는 당신이 사용할 수있는 것을 서버 측 환경에서)
this.jQuery = jQuery;
비 노드 환경 this
에서 전역 개체로 확인되어 이미있는 전역 변수가됩니다. 그래서 그것은 아무것도 깨지 않아야합니다.
편집 : James Herdman은 초보자를위한 node.js에 대한 멋진 글을 가지고 있으며 이것도 언급합니다.
답변
다소 해키 한 솔루션이기 때문에 실제로 이것을 사용하게 될지 확실하지 않지만이 문제를 해결하는 한 가지 방법은 이와 같은 작은 미니 모듈 가져 오기 도구를 만드는 것입니다.
파일에서 ./node_modules/vanilla.js
:
var fs = require('fs');
exports.require = function(path,names_to_export) {
filedata = fs.readFileSync(path,'utf8');
eval(filedata);
exported_obj = {};
for (i in names_to_export) {
to_eval = 'exported_obj[names_to_export[i]] = '
+ names_to_export[i] + ';'
eval(to_eval);
}
return exported_obj;
}
그런 다음 라이브러리의 기능을 사용하려면 내보낼 이름을 수동으로 선택해야합니다.
따라서 파일과 같은 라이브러리의 경우 ./lib/mylibrary.js
…
function Foo() { //Do something... }
biz = "Blah blah";
var bar = {'baz':'filler'};
Node.js 코드에서 기능을 사용하려는 경우 …
var vanilla = require('vanilla');
var mylibrary = vanilla.require('./lib/mylibrary.js',['biz','Foo'])
mylibrary.Foo // <-- this is Foo()
mylibrary.biz // <-- this is "Blah blah"
mylibrary.bar // <-- this is undefined (because we didn't export it)
이 모든 것이 실제로 얼마나 잘 작동하는지 모르겠습니다.
답변
스크립트를 매우 쉽게 업데이트하고 module.exports =
적절한 곳에 간단히 추가하여 작동하도록 만들 수있었습니다 .
예를 들어, 나는 그들의 파일을 가져 와서 ‘./libs/apprise.js’에 복사했습니다. 그런 다음 시작하는 곳
function apprise(string, args, callback){
module.exports =
따라서 기능을 할당했습니다 .
module.exports = function(string, args, callback){
따라서 다음과 같이 라이브러리를 내 코드 로 가져올 수 있습니다 .
window.apprise = require('./libs/apprise.js');
그리고 나는 갈 수 있었다. YMMV, 이것은 webpack 입니다.
답변
include(filename)
오류 발생시에 대한 더 나은 오류 메시지 (스택, 파일 이름 등)가 있는 간단한 함수 eval
:
var fs = require('fs');
// circumvent nodejs/v8 "bug":
// https://github.com/PythonJS/PythonJS/issues/111
// http://perfectionkills.com/global-eval-what-are-the-options/
// e.g. a "function test() {}" will be undefined, but "test = function() {}" will exist
var globalEval = (function() {
var isIndirectEvalGlobal = (function(original, Object) {
try {
// Does `Object` resolve to a local variable, or to a global, built-in `Object`,
// reference to which we passed as a first argument?
return (1, eval)('Object') === original;
} catch (err) {
// if indirect eval errors out (as allowed per ES3), then just bail out with `false`
return false;
}
})(Object, 123);
if (isIndirectEvalGlobal) {
// if indirect eval executes code globally, use it
return function(expression) {
return (1, eval)(expression);
};
} else if (typeof window.execScript !== 'undefined') {
// if `window.execScript exists`, use it
return function(expression) {
return window.execScript(expression);
};
}
// otherwise, globalEval is `undefined` since nothing is returned
})();
function include(filename) {
file_contents = fs.readFileSync(filename, "utf8");
try {
//console.log(file_contents);
globalEval(file_contents);
} catch (e) {
e.fileName = filename;
keys = ["columnNumber", "fileName", "lineNumber", "message", "name", "stack"]
for (key in keys) {
k = keys[key];
console.log(k, " = ", e[k])
}
fo = e;
//throw new Error("include failed");
}
}
그러나 nodejs를 사용하면 더러워집니다. 다음을 지정해야합니다.
export NODE_MODULE_CONTEXTS=1
nodejs tmp.js
그렇지 않으면에 포함 된 파일에서 전역 변수를 사용할 수 없습니다 include(...)
.
