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 для отправки команд. С точки зрения безопасности это звучит как кошмар, но может иметь некоторые допустимые варианты использования.