[javascript] Node.js에서 스크립트가 실행 중인지 확인하는 방법

JavaScript 엔진을 독립적으로 유지하려는 Node.js 스크립트에서 필요한 스크립트가 있습니다.

예를 들어 exports.x = y;Node.js에서 실행중인 경우에만 하고 싶습니다 . 이 테스트를 어떻게 수행 할 수 있습니까?


이 질문을 게시 할 때 Node.js 모듈 기능이 CommonJS 기반인지 몰랐습니다 .

내가 준 구체적인 예에서보다 정확한 질문은 다음과 같습니다.

스크립트가 CommonJS 모듈로 필요한지 어떻게 알 수 있습니까?



답변

CommonJS 지원을 살펴보면 ,이 방법이다 Underscore.js을 라이브러리를 수행합니다

편집 : 업데이트 된 질문 :

(function () {

    // Establish the root object, `window` in the browser, or `global` on the server.
    var root = this;

    // Create a reference to this
    var _ = new Object();

    var isNode = false;

    // Export the Underscore object for **CommonJS**, with backwards-compatibility
    // for the old `require()` API. If we're not in CommonJS, add `_` to the
    // global object.
    if (typeof module !== 'undefined' && module.exports) {
            module.exports = _;
            root._ = _;
            isNode = true;
    } else {
            root._ = _;
    }
})();

여기 예제는 모듈 패턴을 유지합니다.


답변

모든 웹 사이트가 동일한 변수를 쉽게 선언 할 수 있기 때문에 Node.js에서 실행을 감지하는 신뢰할 수있는 방법은 없지만 window기본적으로 Node.js에 객체 가 없으므로 다른 방법으로 이동하여 내부에서 실행 중인지 확인할 수 있습니다 브라우저.

이것은 브라우저와 Node.js에서 모두 작동 해야하는 lib에 사용하는 것입니다.

if (typeof window === 'undefined') {
    exports.foo = {};

} else {
    window.foo = {};
}

그것은 아직도 경우 폭발 할 수 windowNode.js를에 정의되어 있지만 없다 좋은의 명시 적 떠날 필요가 있기 때문에 사람이 작업을 수행 할 이유는, var나에 대한 속성 설정 global개체를.

편집하다

CommonJS 모듈로 스크립트가 필요한지 여부를 감지하는 것은 쉽지 않습니다. commonJS가 지정한 것은 A : 함수에 대한 호출을 통해 모듈이 포함되며 requireB : 모듈은 exports객체의 속성을 통해 항목을 내 보냅니다 . 이제 이것이 구현 방식이 기본 시스템에 남아 있습니다. Node.js는 모듈의 내용을 익명 함수로 래핑합니다.

function (exports, require, module, __filename, __dirname) { 

참조 : https://github.com/ry/node/blob/master/src/node.js#L325

그러나 미친 물건 을 통해 그것을 감지하려고 하지 말고arguments.callee.toString() 대신 브라우저를 확인하는 위의 예제 코드를 사용하십시오. Node.js는 더 깨끗한 환경이므로 window거기에 선언 되지는 않습니다 .


답변

현재 오해의 소지가있는 기능 감지로 인해 Electron 의 노드 환경을 인식 하지 못하는 잘못된 노드 감지를 발견했습니다. 다음 솔루션은 프로세스 환경을 명시 적으로 식별합니다.


Node.js 만 식별

(typeof process !== 'undefined') && (process.release.name === 'node')

이것은 노드 프로세스에서 실행 중인지를 발견합니다. process.release“현재 [노드] 릴리스와 관련된 메타 데이터”가 포함되어 있습니다.

산란 후 io.js 후에도 값이 process.release.name될 수 있습니다 io.js( process-doc 참조). ). 노드 준비 환경을 올바르게 감지하려면 다음과 같이 확인해야합니다.

노드 식별 (> = 3.0.0) 또는 io.js

(typeof process !== 'undefined') &&
(process.release.name.search(/node|io.js/) !== -1)

이 문장은 Node 5.5.0, Electron 0.36.9 (Node 5.1.1) 및 Chrome 48.0.2564.116으로 테스트되었습니다.

노드 식별 (> = 0.10.0) 또는 io.js

(typeof process !== 'undefined') &&
(typeof process.versions.node !== 'undefined')

@daluege의 의견은 더 일반적인 증거에 대해 생각하도록 영감을주었습니다. Node.js에서 작동해야합니다.> = 0.10 . 이전 버전의 고유 식별자를 찾지 못했습니다.


추신 : OP가 다른 질문에 대한 답을 찾고 있었지만 질문이 여기로 이어 지므로 여기에 답을 게시하고 있습니다.


답변

코드가 실행중인 환경을 파악하려고 할 때 발생하는 문제는 모든 객체를 수정하고 선언하여 환경에 고유 한 객체와 프로그램에 의해 수정 된 객체를 파악하는 것이 거의 불가능하다는 것입니다.

그러나 어떤 환경에 있는지 확인하기 위해 사용할 수있는 몇 가지 트릭이 있습니다.

밑줄 라이브러리에서 일반적으로 사용되는 솔루션으로 시작해 보겠습니다.

typeof module !== 'undefined' && module.exports

이 기술은 실제로 require함수가 호출되면 this객체를 빈 객체로 재설정 하고 다시 재정의 하므로 서버 측에 완벽하게 적합 module합니다. 즉, 외부 변조에 대해 걱정할 필요가 없습니다. 코드가로드 된 한require 있으면 안전합니다.

그러나 이것은 누구나 module원하는 객체처럼 보이도록 쉽게 정의 할 수 있기 때문에 브라우저와 다릅니다 . 한편으로는 원하는 동작 일 수도 있지만 라이브러리 사용자가 전역 범위에서 사용할 수있는 변수도 결정합니다. 누군가가 이름을 가진 변수를 사용하고 싶을 수도 있습니다.module 을 있습니다.exports 있습니다. 다른 환경에서 해당 변수 이름을 사용하기 때문에 다른 사람이 사용할 수있는 변수를 누가 판단해야합니까?

그러나 트릭은 스크립트가 전역 범위 (스크립트 태그를 통해로드 된 경우)에로드되고 있다고 가정하면 브라우저가 허용하지 않기 때문에 변수를 외부 클로저에 예약 할 수 없다는 것입니다 . 이제 노드에서 this객체는 빈 객체이지만 module변수는 여전히 사용 가능 하다는 것을 기억하십시오 . 외부 폐쇄로 선언 되었기 때문입니다. 그런 다음 추가 검사를 추가하여 밑줄의 검사를 수정할 수 있습니다.

this.module !== module

이를 통해 누군가 module브라우저의 전역 범위에서 선언 하면 this객체가 객체에 배치되어 this.module모듈과 동일한 객체가 되기 때문에 테스트가 실패 합니다. 노드 this.module에는 존재하지 않으며 module외부 폐쇄 내에 존재하므로 테스트가 동일하지 않으므로 테스트에 성공합니다.

따라서 최종 테스트는 다음과 같습니다.

typeof module !== 'undefined' && this.module !== module

참고 : 이제 module전역 범위에서 변수를 자유롭게 사용할 수 있지만 새 클로저를 만들고 그 module안에 선언 한 다음 해당 클로저 내에 스크립트를로드하여 브라우저에서이 변수를 무시할 수 있습니다 . 이 시점에서 사용자는 노드 환경을 완전히 복제하고 있으며 자신이 무엇을하고 있는지 알고 노드 스타일 요구 사항을 수행하려고합니다. 코드가 스크립트 태그에서 호출 된 경우에도 새로운 외부 클로저로부터 안전합니다.


답변

의도적으로 명시 적으로 방해하지 않는 한 다음은 브라우저에서 작동합니다.

if(typeof process === 'object' && process + '' === '[object process]'){
    // is node
}
else{
    // not node
}

밤.


답변

다음과 같이 멋진 방법이 있습니다.

const isBrowser = this.window === this;

이것은 브라우저에서 전역 ‘this’변수에 ‘window’라는 자체 참조가 있기 때문에 작동합니다. 이 자체 참조는 노드에 없습니다.

  • 브라우저에서 ‘this’는 ‘window’라는 전역 객체에 대한 참조입니다.
  • 노드 ‘this’는 module.exports 객체에 대한 참조입니다.
    • ‘이것’은 아닙니다 ‘global’이라는 Node 전역 객체에 대한 참조 .
    • ‘this’는 모듈 변수 선언 공간에 대한 참조 가 아닙니다 .

위의 제안 된 브라우저 확인을 중단하려면 다음과 같은 작업을 수행해야합니다

this.window = this;

확인을 실행하기 전에.


답변

또 다른 환경 감지 :

(의미 : 대부분의 답변은 괜찮습니다.)

function isNode() {
    return typeof global === 'object'
        && String(global) === '[object global]'
        && typeof process === 'object'
        && String(process) === '[object process]'
        && global === global.GLOBAL // circular ref
        // process.release.name cannot be altered, unlike process.title
        && /node|io\.js/.test(process.release.name)
        && typeof setImmediate === 'function'
        && setImmediate.length === 4
        && typeof __dirname === 'string'
        && Should I go on ?..
}

약간 편집증이 맞습니까? 더 많은 글로벌 을 확인하여 더 자세한 정보를 얻을 수 있습니다 .

그러나하지 마십시오!.

어쨌든 위의 모든 내용은 위조 / 시뮬레이션 될 수 있습니다.

예를 들어 global객체 를 위조하려면

global = {
    toString: function () {
        return '[object global]';
    },
    GLOBAL: global,
    setImmediate: function (a, b, c, d) {}
 };
 setImmediate = function (a, b, c, d) {};
 ...

이것은 노드의 원래 전역 객체에 첨부되지 않지만 window 브라우저 객체에 . 따라서 브라우저 내부의 Node env에 있음을 의미합니다.

인생은 짧다!

환경이 위조되는지 걱정합니까? 바보 같은 개발자가 전역 변수를 선언 할 때 발생합니다.global 가 전역 범위에서 된 합니다. 또는 어떤 사악한 개발자가 우리 환경에 코드를 주입합니다.

우리는 이것을 잡을 때 코드가 실행되는 것을 막을 수 있지만 앱의 다른 많은 의존성이 이것에 잡힐 수 있습니다. 결국 코드가 깨질 것입니다. 코드가 충분하다면, 다른 사람들이했을 수있는 각각의 어리석은 실수는 신경 쓰지 않아야합니다.

그래서 무엇?

2 개의 환경을 타겟팅하는 경우 : 브라우저 및 노드;
"use strict"; 및 중 하나를 간단히 확인 window또는 global; 문서에서 코드가 이러한 환경 만 지원한다는 것을 명확하게 표시하십시오. 그게 다야!

var isBrowser = typeof window !== 'undefined'
    && ({}).toString.call(window) === '[object Window]';

var isNode = typeof global !== "undefined"
    && ({}).toString.call(global) === '[object global]';

가능한 경우 사용 사례; 환경 감지 대신; try / catch 블록 내에서 동기식 기능 탐지를 수행합니다. 실행하는 데 몇 밀리 초가 걸립니다.

예 :

function isPromiseSupported() {
    var supported = false;
    try {
        var p = new Promise(function (res, rej) {});
        supported = true;
    } catch (e) {}
    return supported;
}