Как проверить, работает ли скрипт под Node.js?

У меня есть скрипт, который мне нужен из скрипта Node.js, который я хочу сохранить независимым от движка JavaScript.

Например, я хочу сделать exports.x = y;, только если он работает под Node.js. Как я могу выполнить этот тест?


Когда я писал этот вопрос, я не знал, что функция модулей Node.js основана на CommonJS.

Для конкретного примера, который я привел, более точный вопрос был бы:

Как скрипт может определить, был ли он необходим в качестве модуля CommonJS?

Ответ 1

Чтобы найти поддержку 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._ = _;
    }
})();

Пример здесь сохраняет шаблон модуля.

Ответ 2

Ну, нет надежного способа обнаружить запуск в Node.js, поскольку каждый веб-сайт может легко объявить одни и те же переменные, но, поскольку в Node.js по умолчанию нет объекта window, вы можете пойти другим путем и проверить, работает внутри браузера.

Это то, что я использую для библиотек, которые должны работать как в браузере, так и в Node.js:

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

} else {
    window.foo = {};
}

Он все еще может взорваться в случае, если window определен в Node.js, но для этого нет веской причины, так как вам явно нужно было бы опустить var или установить свойство объекта global..

EDIT

Чтобы определить, нужен ли ваш скрипт как модуль CommonJS, это опять-таки не легко. CommonJS указывает только то, что A: модули будут включены через вызов функции require, а B: модули экспортируют вещи через свойства объекта 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.

Ответ 3

В настоящее время я наткнулся на неправильное обнаружение Node, которое не известно о Node -environment в Electron из-за вводящего в заблуждение обнаружения функции. Следующие решения явно идентифицируют среду процесса.


Идентифицировать Node.js только

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

Это обнаружит, если вы работаете в Node -process, так как process.release содержит "метаданные, связанные с текущим [ Node -]. выпуск"

После появления io.js значение process.release.name также может стать io.js (см. process-doc). Чтобы правильно определить среду Node -ready, я думаю, вы должны проверить следующее:

Определите Node ( >= 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.

Определите Node ( >= 0.10.0) или io.js

(typeof process !== 'undefined') &&
(typeof process.versions.node !== 'undefined')
Комментарий

@daluege вдохновил меня на размышления о более общем доказательстве. Это должно работать от Node.js >= 0.10. Я не нашел уникальный идентификатор для предыдущих версий.


P.s.: Я размещаю этот ответ здесь, поскольку вопрос привел меня сюда, хотя OP искал ответ на другой вопрос.

Ответ 4

Проблема с попыткой выяснить, в какой среде работает ваш код, является то, что любой объект может быть изменен и объявлен, что делает невозможным выяснить, какие объекты являются родными для среды и которые были изменены программой.

Однако есть несколько трюков, которые мы можем использовать, чтобы точно определить, в какой среде вы находитесь.

Давайте начнем с общепринятого решения, которое используется в библиотеке подчёркивания:

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

Этот метод на самом деле отлично подходит для серверной части, так как при вызове функции require он сбрасывает объект this на пустой объект и снова переопределяет module, что означает, что вы не должны беспокоиться о любых внешних вмешательствах. Пока ваш код загружается с помощью require, вы в безопасности.

Однако это оборачивается в браузере, так как любой может легко определить module, чтобы он выглядел как объект, который вы ищете. С одной стороны, это может быть поведение, которое вы хотите, но оно также определяет, какие переменные пользователь библиотеки может использовать в глобальной области. Возможно, кто-то хочет использовать переменную с именем module, которая имеет exports внутри нее для другого использования. Это маловероятно, но кто мы должны судить, какие переменные кто-то может использовать, просто потому, что в другой среде используется это имя переменной?

Однако трюк заключается в том, что если мы предположим, что ваш script загружается в глобальную область (которая будет, если она будет загружена через тег script), переменная не может быть зарезервирована во внешнем закрытии, потому что браузер этого не позволяет. Теперь запомните в node, объект this - пустой объект, но переменная module по-прежнему доступна. Это потому, что оно объявлено во внешнем закрытии. Поэтому мы можем исправить проверку подчеркивания, добавив дополнительную проверку:

this.module !== module

При этом, если кто-то объявит module в глобальной области действия в браузере, он будет помещен в объект this, что приведет к сбою теста, поскольку this.module будет тем же объектом, что и модуль. В node this.module не существует, а module существует во внешнем замыкании, поэтому тест будет успешным, так как они не эквивалентны.

Таким образом, окончательный тест:

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

Примечание. Хотя теперь это позволяет свободно использовать переменную module в глобальной области видимости, все равно можно обойти это в браузере, создав новое замыкание и объявив module внутри этого, а затем загрузив script внутри этого закрытия. В этот момент пользователь полностью реплицирует среду node и, надеюсь, знает, что они делают, и пытается выполнить стиль node. Если код вызывается в теге script, он все равно будет защищен от любых новых внешних замыканий.

Ответ 5

Следующие действия выполняются в браузере, если это не преднамеренно, явно саботировано:

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

Bam.

Ответ 6

Здесь довольно крутой способ сделать это:

const isBrowser = this.window === this;

Это работает, потому что в браузерах глобальная переменная 'this' имеет самоназвание, называемое "окно". Эта самооценка отсутствует в Node.

  • В браузере 'this' есть ссылка на глобальный объект, называемый "окно".
  • В Node 'this' приведена ссылка на module.exports объект.
    • 'this' не является ссылкой на глобальный объект Node, называемый глобальным.
    • 'this' не является ссылкой на пространство объявления переменных модуля.

Чтобы разбить вышеуказанный браузер, вам нужно сделать что-то вроде следующего

this.window = this;

перед выполнением проверки.

Ответ 7

Еще одно обнаружение среды:

(Значение: большинство ответов здесь в порядке.)

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) {};
 ...

Это не будет привязано к исходному глобальному объекту Node, но будет прикреплено к объекту window в браузере. Таким образом, это будет означать, что вы находитесь в Ende Node внутри браузера.

Жизнь коротка!

Мы заботимся о том, что наша среда подделана? Это произойдет, когда какой-нибудь глупый разработчик объявит глобальную переменную под названием 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;
}

Ответ 8

Большинство предлагаемых решений действительно могут быть подделаны. Простой способ - проверить внутреннее свойство Class глобального объекта, используя Object.prototype.toString. Внутренний класс нельзя подделать в JavaScript:

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

Ответ 9

Как насчет использования объекта процесса и проверки execPath для node?

process.execPath

Это абсолютное путь к исполняемому файлу, который начал процесс.

Пример:

     

/USR/локальные/бен/node

Ответ 10

Как может script указать, требуется ли это в качестве модуля commonjs?

Связано: чтобы проверить, требуется ли это в качестве модуля для запуска непосредственно в node, вы можете проверить require.main !== module. http://nodejs.org/docs/latest/api/modules.html#accessing_the_main_module

Ответ 11

Здесь моя вариация на то, что выше:

(function(publish) {
    "use strict";

    function House(no) {
        this.no = no;
    };

    House.prototype.toString = function() {
        return "House #"+this.no;
    };

    publish(House);

})((typeof module == 'undefined' || (typeof window != 'undefined' && this == window))
    ? function(a) {this["House"] = a;}
    : function(a) {module.exports = a;});

Чтобы использовать его, вы изменяете "Дом" на второй последней строке, чтобы быть тем, кем хотите, чтобы имя модуля находилось в браузере, и публиковать все, что вы хотите, чтобы значение модуля (обычно это конструктор или литерал объекта).

В браузерах глобальный объект является окном, и он имеет ссылку на себя (там окно window.window, которое является окном ==). Мне кажется, что это вряд ли произойдет, если вы не находитесь в браузере или в среде, которая хочет, чтобы вы считали, что находитесь в браузере. Во всех остальных случаях, если существует глобальная переменная 'module', она использует, что в противном случае он использует глобальный объект.

Ответ 12

Я использую process для проверки node.js как

if (typeof(process) !== 'undefined' && process.version === 'v0.9.9') {
  console.log('You are running Node.js');
} else {
  // check for browser
}

или

if (typeof(process) !== 'undefined' && process.title === 'node') {
  console.log('You are running Node.js');
} else {
  // check for browser
}

Документировано здесь

Ответ 13

Это довольно безопасный и прямой способ обеспечения совместимости между серверным и клиентским javascript, который также будет работать с браузером, RequireJS или CommonJS, включенным на стороне клиента:

(function(){

  // `this` now refers to `global` if we're in NodeJS
  // or `window` if we're in the browser.

}).call(function(){
  return (typeof module !== "undefined" &&
    module.exports &&
    typeof window === 'undefined') ?
    global : window;
}())

Ответ 14

Node.js имеет объект process, так что пока у вас нет другого script, который создает process, вы можете использовать его для определения того, выполняется ли код Node.

var isOnNodeJs = false;
if(typeof process != "undefined") {
  isOnNodeJs = true;
}

if(isOnNodeJs){
  console.log("you are running under node.js");
}
else {
  console.log("you are NOT running under node.js");
}

Ответ 15

Изменить. Что касается вашего обновленного вопроса: "Как может script указать, требуется ли это в качестве модуля commonjs?" Я не думаю, что это возможно. Вы можете проверить, является ли exports объектом (if (typeof exports === "object")), так как спецификация требует, чтобы он предоставлялся модулям, но все, что сообщает вы это... exports - это объект.: -)


Оригинальный ответ:

Я уверен, что есть определенный NodeJS-символ ( EventEmitter, возможно нет, вам нужно использовать require для получения модуля событий, см. ниже), который вы можете проверить, но, как сказал Дэвид, в идеале вам лучше обнаружить функцию (а не среду), если это имеет смысл сделать это.

Обновление. Возможно, что-то вроде:

if (typeof require === "function"
    && typeof Buffer === "function"
    && typeof Buffer.byteLength === "function"
    && typeof Buffer.prototype !== "undefined"
    && typeof Buffer.prototype.write === "function") {

Но это просто говорит вам, что вы находитесь в среде с require и чем-то очень, очень похожим на NodeJS Buffer.: -)

Ответ 16

const isNode =
  typeof process !== 'undefined' &&
  process.versions != null &&
  process.versions.node != null;

Ответ 18

Возьмите источник node.js и измените его, чтобы определить переменную типа runningOnNodeJS. Проверьте эту переменную в своем коде.

Если у вас нет собственной приватной версии node.js, откройте запрос функции в проекте. Попросите, чтобы они определили переменную, которая дает вам версию node.js, в которой вы работаете. Затем проверьте эту переменную.

Ответ 19

Очень старый пост, но я просто решил его, обернув запросы require в try-catch

    try {

           var fs = require('fs')

} catch(e) {
       alert('you are not in node !!!')
}

Ответ 20

Я думаю, что это довольно просто.

     if (typeof process !== 'undefined' process && process.title === 'node') {
        // Your code here
     }