У меня есть скрипт, который мне нужен от скрипта Node.js, который я хочу сохранить независимым от движка JavaScript.
Например, я хочу сделать exports.x = y;
только если он работает под Node.js. Как я могу выполнить этот тест?
Когда я писал этот вопрос, я не знал, что функция модулей Node.js основана на CommonJS .
Для конкретного примера, который я привел, более точный вопрос был бы:
Как скрипт может определить, был ли он необходим в качестве модуля CommonJS?
javascript
node.js
commonjs
theosp
источник
источник
Ответы:
Ища поддержку CommonJS , вот как библиотека Underscore.js делает это:
Изменить: на ваш обновленный вопрос:
Пример здесь сохраняет шаблон модуля.
источник
Что ж, нет надежного способа обнаружить запуск в Node.js, поскольку каждый веб-сайт может легко объявить одни и те же переменные, однако, поскольку
window
в Node.js по умолчанию нет объекта, вы можете пойти другим путем и проверить, выполняете ли вы внутри Browser.Вот что я использую для библиотек, которые должны работать как в браузере, так и под Node.js:
Он может все еще взорваться в случае, если
window
это определено в Node.js, но для этого нет веской причины, так как вам явно нужно было бы опуститьvar
или установить свойствоglobal
объекта.РЕДАКТИРОВАТЬ
Определить, нужен ли ваш скрипт как модуль CommonJS, опять же нелегко. CommonJS указывает только то, что A: модули будут включены через вызов функции,
require
а B: модули экспортируют вещи через свойстваexports
объекта. Теперь, как это реализовать, оставлено на усмотрение базовой системы. Node.js оборачивает содержимое модуля в анонимную функцию:См .: https://github.com/ry/node/blob/master/src/node.js#L325.
Но не пытайтесь обнаружить это с помощью каких-то сумасшедших
arguments.callee.toString()
вещей, вместо этого просто используйте приведенный выше пример кода, который проверяет браузер. Node.js - более чистая среда, поэтому вряд лиwindow
она будет там объявлена.источник
window
в первой строке вашего модуля, у вас не должно возникнуть никаких проблем. Можно также запустить анонимную функцию и проверить[[Class]]
изthis
внутри него (работает только в нестрогой режиме) в разделе «Класс» под: bonsaiden.github.com/JavaScript-Garden/#typeoftypeof self === 'object'
может быть безопаснее, так какtypeof window === 'undefined'
не работает в области веб-работников.В настоящее время я наткнулся на неправильное обнаружение узла, который не знает об окружении узла в Electron из-за вводящего в заблуждение обнаружения признаков. Следующие решения явно определяют среду процесса.
Определить только Node.js
Это обнаружит, если вы работаете в Node-процессе, так как
process.release
содержит «метаданные, связанные с текущей версией [Node-]».После появления io.js значение
process.release.name
может также статьio.js
(см. Process-doc ). Чтобы правильно определить Node-ready среду, я думаю, вам следует проверить следующее:Определить узел (> = 3.0.0) или io.js
Это утверждение было проверено с Узлом 5.5.0, Электроном 0.36.9 (с Узлом 5.1.1) и Chrome 48.0.2564.116.
Определить узел (> = 0.10.0) или io.js
Комментарий @ daluege вдохновил меня подумать о более общем доказательстве. Это должно работать с Node.js> = 0.10 . Я не нашел уникальный идентификатор для предыдущих версий.
PS: я публикую этот ответ здесь, так как вопрос привел меня сюда, хотя ОП искал ответ на другой вопрос.
источник
process
иprocess.version
существует в пакете, поэтому я добавил дополнительную проверку для того,process.version
гдеprocess.release.node
не определено на стороне клиента, но имеет версию узла в качестве значения на стороне сервераprocess.version
переменной (в реагировать, веб-пакет или реагировать-веб-пакет). Я был бы признателен за любую подсказку, где определяется переменная версии, чтобы добавить ее в ответ. В зависимости от ограничений release.node для узла> = 3.xxfunction isNodejs() { return typeof "process" !== "undefined" && process && process.versions && process.versions.node; }
Проблема с попыткой выяснить, в какой среде работает ваш код, состоит в том, что любой объект может быть изменен и объявлен, что делает практически невозможным выяснение того, какие объекты являются родными для среды, а какие были изменены программой.
Однако есть несколько приемов, которые мы можем использовать, чтобы точно определить, в какой среде вы находитесь.
Давайте начнем с общепринятого решения, которое используется в библиотеке подчеркивания:
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
в нем, а затем загрузив скрипт в этом закрытии. В этот момент пользователь полностью реплицирует среду узла и, надеюсь, знает, что он делает, и пытается выполнить требования стиля узла. Если код вызывается в теге скрипта, он все равно будет защищен от любых новых внешних замыканий.источник
Cannot read property 'module' of undefined
потому что это не определено в тестах мокко, напримерСледующее работает в браузере, если намеренно, явно не саботируется:
Bam.
источник
process+''
вместоprocess.toString()
?Object.prototype.toString.call(process)
var process = null;
приведет к сбою во втором случае. И в Javascript, и в Java выражение'' + x
выдает то же самое, что иx.toString()
за исключением случаев, когдаx
это плохо, первое выдает"null"
или"undefined"
где последнее выдает ошибку.Вот довольно крутой способ сделать это:
Это работает, потому что в браузерах глобальная переменная this имеет собственную ссылку под названием window. Эта собственная ссылка не существует в узле.
Чтобы сломать вышеупомянутую проверку браузера, вам нужно сделать что-то вроде следующего
перед выполнением проверки.
источник
const isBrowser = this.window !== undefined
? И теоретически в узле я могуthis.window = this
обмануть решение.Еще одно обнаружение среды :
(Значение: большинство ответов здесь в порядке.)
Немного параноик, верно? Вы можете сделать это более многословным, проверив наличие большего числа глобальных переменных .
Но НЕ!
Все это выше может быть подделано / смоделировано в любом случае.
Например, чтобы подделать
global
объект:Он не будет привязан к исходному глобальному объекту Node, но будет привязан к
window
объекту в браузере. Так что это будет означать, что вы находитесь в Ende Node внутри браузера.Жизнь коротка!
Неужели мы заботимся о том, что наша среда подделана? Это происходит, когда какой-то глупый разработчик объявляет глобальную переменную, называемую
global
в глобальной области видимости. Или какой-то злой разработчик как-то внедряет код в нашу среду.Мы можем препятствовать выполнению нашего кода при обнаружении этого, но множество других зависимостей нашего приложения могут попасть в это. Так что в конечном итоге код сломается. Если ваш код достаточно хорош, вы не должны заботиться о каждой глупой ошибке, которую могли совершить другие.
Ну и что?
При ориентации на 2 среды: браузер и узел;
"use strict"
; и либо просто проверьтеwindow
илиglobal
; и четко указать, что в документации ваш код поддерживает только эти среды. Это оно!Если возможно для вашего варианта использования; вместо обнаружения окружающей среды; сделать синхронное определение функции в блоке try / catch. (это займет несколько миллисекунд для выполнения).
например
источник
Большинство предложенных решений могут быть подделаны. Надежный способ - проверить внутреннее
Class
свойство глобального объекта с помощьюObject.prototype.toString
. Внутренний класс не может быть подделан в JavaScript:источник
Object.prototype.toString
что является очень плохой практикой.var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};
({}.toString.call(window))
это равный"[object global]"
.window.toString()
производит"[object Window]"
Как насчет использования объекта процесса и проверки execPath для
node
?источник
window.process = {execPath: "/usr/local/bin/node"};
?Связано: чтобы проверить, был ли он необходим, поскольку модуль запускался непосредственно в узле, вы можете проверить
require.main !== module
. http://nodejs.org/docs/latest/api/modules.html#accessing_the_main_moduleисточник
Вот мой вариант того, что выше:
Чтобы использовать его, вы изменяете «Дом» во второй последней строке, чтобы он был таким, каким вы хотите, чтобы имя модуля отображалось в браузере, и публикуете все, что хотите, чтобы значение модуля было (обычно конструктор или литерал объекта). ).
В браузерах глобальным объектом является window, и он имеет ссылку на себя (есть window.window, который == window). Мне кажется, что это вряд ли произойдет, если вы не находитесь в браузере или в среде, которая хочет, чтобы вы верили, что вы в браузере. Во всех других случаях, если объявлена глобальная переменная 'module', она использует ее, в противном случае она использует глобальный объект.
источник
Я использую,
process
чтобы проверить для node.js, как такили
Документировано здесь
источник
process.title
можно изменитьНа момент написания этой статьи этот ответ представлял собой скорее вариант «Скоро появится», поскольку он использует очень новые функции JavaScript.
runtime
Значение будет либоnode
илиnot node
.Как уже упоминалось, это зависит от нескольких новых функций JavaScript.
globalThis
является финальной функцией в спецификации ECMAScript 2020 Необязательное объединение в цепочку / нулевое объединение (?
частьglobalThis.process?.release?.name
) поддерживается в движке V8, который поставляется с Chrome 80. Начиная с 08.04.2020 этот код будет работать в браузере, но не будет работать в Node, поскольку ветвь Node 13 использует V8 7.9.xxx. Я считаю, что Node 14 (который должен быть выпущен 21.04.2020) должен использовать V8 8.x +.Этот подход идет со здоровой дозой текущих ограничений. Тем не мение; скорость, с которой выпускаются браузеры / Node, в конечном итоге станет надежной.
источник
В Node.js есть
process
объект, поэтому, если у вас нет другого скрипта, который его создает,process
вы можете использовать его, чтобы определить, выполняется ли код на Node.источник
Это довольно безопасный и простой способ обеспечения совместимости между javascript на стороне сервера и на стороне клиента, который также будет работать с browserify, RequireJS или CommonJS, включая клиентскую часть:
источник
Редактировать : Относительно вашего обновленного вопроса: «Как скрипт может определить, был ли он необходим в качестве модуля commonjs?» Я не думаю, что это возможно. Вы можете проверить,
exports
является ли объект (if (typeof exports === "object")
), поскольку спецификация требует, чтобы он был предоставлен модулям, но все, что вам говорит, это то, что ...exports
это объект. :-)Оригинальный ответ:
Я уверен, что есть какой-то специфичный для NodeJS символ (
нет, вы должны использовать егоEventEmitter
возможно,require
для получения модуля событий; см. Ниже ), который вы могли бы проверить, но, как сказал Дэвид, в идеале вам лучше обнаружить функцию (скорее чем окружающая среда), если это имеет какой-то смысл.Обновление : возможно что-то вроде:
Но это просто говорит о том, что вы находитесь в среде с
require
чем-то очень похожим на NodeJSBuffer
. :-)источник
window
переменную в приложении NodeJS. :-)window
в модуле NodeJS, таким образом , они могут включать в себя код , который полагался наwindow
время глобального объекта и не хочет , чтобы изменить этот код. Я бы не стал этого делать, вы бы не стали, но держу пари, что кто-то сделал :-) Или они просто имелиwindow
в виду что-то совсем другое.typeof process !== "undefined" && process.title === "node"
источник
Из источника отладочного пакета:
https://github.com/visionmedia/debug/blob/master/src/index.js#L6
источник
Возьмите источник node.js и измените его, чтобы определить переменную наподобие
runningOnNodeJS
. Проверьте эту переменную в вашем коде.Если у вас нет собственной частной версии node.js, откройте запрос на добавление функций в проекте. Попросите, чтобы они определили переменную, которая дает вам версию node.js, в которой вы работаете. Затем проверьте эту переменную.
источник
window
глобальных сценариев , думаю, я собираюсь подать запрос на добавление функций для этого.var
выражение, люди, которые просто просачивают его в глобальное пространство имен, ну, тогда они не понимают концепцию автономных модулейОчень старый пост, но я решил его, обернув операторы require в try - catch
источник