Node объект процесса, доступный для кода клиента браузера
Я пытаюсь понять, как webpack использует DefinePlugin. У меня есть:
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('development'),
}),
и функция:
export const foo = () => {
console.log(process)
console.log(process.env.NODE_ENV)
}
window.foo = foo
когда я печатаю foo, я вижу следующее в моей консоли браузера:
ƒ foo() {
console.log(process);
console.log("development");
}
Кажется, что переменная "development" была введена, а webpack - для компиляции входного файла. В то же время webpack также ввел объект процесса в код JavaScript, и браузер распечатал объект процесса при вызове foo:
{title: "browser", browser: true, env: {…}, argv: Array(0), nextTick: ƒ, …}
Мой вопрос: каким образом объект процесса, который является концепцией Node, будет доступен для браузера?
Фактически, если я делаю:
window.process = process
Я могу использовать process.nextTick прямо в консоли браузера! Я думал, что функция nextTick является Node -специфической реализацией! Может ли кто-нибудь объяснить это?
Спасибо!
Ответы
Ответ 1
Как уже упоминалось здесь https://webpack.js.org/configuration/node/#node-process, webpack может создавать полисы для различных функций node, но он отображается как node.process
a "mock"
;
"mock": предоставить макет, который реализует ожидаемый интерфейс, но практически не имеет функциональности.
Пробовали ли вы его проверить, действительно ли он работает? Это может быть просто пустая оболочка.
Если это работает, я предполагаю, что плагин фактически использует что-то вроде node-process, как показано в этом блоге: http://timnew.me/blog/2014/06/23/process-nexttick-implementation-in-browser/
Скопировано из этого блога:
process.nextTick = (function () {
var canSetImmediate = typeof window !== 'undefined'
&& window.setImmediate;
var canPost = typeof window !== 'undefined'
&& window.postMessage && window.addEventListener;
if (canSetImmediate) {
return function (f) { return window.setImmediate(f) };
}
if (canPost) {
var queue = [];
window.addEventListener('message', function (ev) {
var source = ev.source;
if ((source === window || source === null) && ev.data === 'process-tick') {
ev.stopPropagation();
if (queue.length > 0) {
var fn = queue.shift();
fn();
}
}
}, true);
return function nextTick(fn) {
queue.push(fn);
window.postMessage('process-tick', '*');
};
}
return function nextTick(fn) {
setTimeout(fn, 0);
};
})();
Немного сложно узнать из предоставленной вами информации. Если это действительно работает, я думаю, что у вас есть Browserify включен в вашем приложении node. Возможно, вы найдете то, что вам нужно здесь: https://webpack.js.org/loaders/transform-loader/#src/components/Sidebar/Sidebar.jsx
Надеюсь, вы найдете этот ответ несколько полезным.
Суть в том, что я верю, что это polyfill откуда-то.
Ответ 2
Как webpack взаимодействует с глобальными узлами Node и webpack.DefinePlugin
, на самом деле это две разные проблемы.
webpack.DefinePlugin
значения узлов по умолчанию внедряются глобально, в то время как константы, определенные в webpack.DefinePlugin
, физически заменяются одна за другой через всю кодовую базу.
например:
// config
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('development'),
'process.env.MY_VAR': {foo: JSON.stringify('bar')},
}),
// source
console.log('process.env.NODE_ENV', process.env.NODE_ENV);
console.log('process.env.MY_VAR', process.env.MY_VAR);
console.log('process.env', process.env);
console.log('process', process);
// compiled
console.log('process.env.NODE_ENV', "development");
console.log('process.env.MY_VAR', __webpack_require__.i({"foo":"bar"}));
console.log('process.env', process.env);
console.log('process', process);
Обратите внимание, что process.env.NODE_ENV
и process.env.MY_VAR
p физически заменяются, тогда как process.env
и process
сохраняют свои ссылки на внедренный макет process
.
Но webpack.DefinePlugin
также способен переопределить объект process
(или только его часть), который можно webpack.DefinePlugin
: большая мощность, которая подразумевает риск непредвиденного поведения.
Из документов Webpack:
При определении значений для процесса предпочитайте "process.env.NODE_ENV": JSON.stringify("production"), а не process: {env: {NODE_ENV: JSON.stringify("production")}}. Использование последнего перезапишет объект процесса, что может нарушить совместимость с некоторыми модулями, которые ожидают определения других значений в объекте процесса.
например:
// config
new webpack.DefinePlugin({
'process': JSON.stringify('override'),
'process.env.NODE_ENV': JSON.stringify('development'),
}),
// source
console.log('process', process);
console.log('process.env', process.env);
console.log('process.env.NODE_ENV', process.env.NODE_ENV);
// compiled
console.log('process', "override");
console.log('process.env', "override".env); // [boum!]
console.log('process.env.NODE_ENV', "development"); // [replaced by DefinePlugin!]
Ответ 3
Это не дает прямого ответа на этот вопрос, но это было решение, которое мне было нужно. Я пытался получить доступ к process
в коде, скомпилированном веб-пакетом, намереваясь запустить скомпилированный код в среде NodeJS, а не в браузере. Переменная process
существует не в window
, а в global
.
Решением было установить target
в конфиге веб-пакета.
webpack.config.js
const config = {
// ...
target: 'node',
// ...
};
module.exports = config;
Это удаляет window
макет.
Ответ 4
видеть
https://webpack.js.org/configuration/node/#node
Эти параметры определяют, нужно ли заполнять или макетировать некоторые глобальные переменные и модули Node.js. Это позволяет коду, изначально написанному для среды Node.js, запускаться в других средах, таких как браузер.
Эта функция предоставляется внутренним плагином NodeStuffPlugin. Если целью является "web" (по умолчанию) или "webworker", плагин NodeSourcePlugin также активируется.
Ответ 5
Я собираюсь предположить, что вы экспериментируете с этим на своем локальном сервере webpack dev, а не в своей производственной сборке. Сервер Webpack dev использует websockets для обмена в реальном времени между базовыми процессами node и интерфейсом. Если вы хотите использовать это в производственной среде, вам нужно будет настроить сокет между вашим JS переднего конца и вашим экземпляром node для отправки команд. С точки зрения безопасности это звучит как кошмар, но может иметь некоторые допустимые варианты использования.