Как установить process.env перед запуском браузерного скрипта?

Начальный html исходит из серверной части. Сервер имеет определенный process.env.NODE_ENV (а также другие переменные среды). Браузерный код собирается один раз и запускается в нескольких средах (staging, production и т. д.), поэтому невозможно встроить переменные среды в браузерный скрипт ( через envify например). Я хотел бы иметь возможность записывать переменные среды в отображаемом html и для браузерного кода использовать эти переменные. Это возможно?

Вот как я себе это представляю:

<html>
  <head>
    <script>window.process = {env: {NODE_ENV: 'production'}};</script>
    <script src="/build/browserified_app.js"></script>
  </head>
</html>

person Yuriy Nemtsov    schedule 24.10.2014    source источник


Ответы (5)


Вместо жесткого кодирования переменных среды тут и там используйте подключаемый модуль envify.

npm install envify 

Этот плагин автоматически изменяет process.env.VARIABLE_HERE тем, что вы передали в качестве аргумента для envify.

Например:

browserify index.js -t [ envify --DEBUG app:* --NODE_ENV production --FOO bar ] > bundle.js

В вашем приложении process.env.DEBUG будет заменено на app:*, process.env.NODE_ENV будет заменено на production и так далее. На мой взгляд, это чистый и элегантный способ справиться с этим.

person alessioalex    schedule 16.02.2015
comment
поэтому невозможно встроить переменные среды в браузерный скрипт (например, через envify) - asker - person alxgb; 30.07.2015

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

process.env.NODE_ENV = 'production';
require('app.js');

Другой способ (более чистый) - использовать преобразование, например envify, которое заменяет ваш NODE_ENV в коде на строку значение напрямую.

Опция 1

Я думаю, что ваш подход в целом должен работать, но я бы не стал писать напрямую в process.env, так как я почти уверен, что он будет перезаписан в комплекте. Вместо этого вы можете создать глобальную переменную, например __env, а затем в фактическом коде пакета установить для нее значение process.env в вашем файле ввода. Это непроверенное решение, но я считаю, что оно должно работать.

Вариант 2

Используйте localStorage и позвольте вашему основному сценарию читать оттуда переменные при инициализации. Вы можете установить переменные в localStorage вручную или даже позволить серверу предоставить их, если они у вас есть. Разработчик просто откроет консоль и наберет что-то вроде loadEnv('production'), он сделает XHR и сохранит результат в localStorage. Даже при ручном подходе все еще есть преимущество, заключающееся в том, что их не нужно жестко кодировать в html.

Если руководство не звучит достаточно хорошо, а сервер тоже тупик, вы можете просто включить все переменные из всех сред (если они у вас где-то есть) в пакет, а затем использовать оператор switch, чтобы выбрать правильные на основе некоторых условий (например, .localhost, производственный хост).


Думая об этом, вы определенно выходите за рамки Browserify с вашими потребностями. Он может сделать пакет для вас, но если вы не хотите, чтобы эта информация была в пакете, вы сами по себе.

person FredyC    schedule 24.10.2014
comment
Вы предлагаете создать файл для каждой среды? Если да, то это невозможно в моей настройке, потому что нет предопределенного набора сред. Разработчики могут создавать новую среду для каждой функции и устанавливать свои собственные переменные среды, которые мне нужны, чтобы отразить их во внешнем интерфейсе (в React). Использование envify также невозможно, как я упоминал в вопросе, потому что мы создаем js один раз, сохраняем его в CDN, а затем используем много раз в разных средах. - person Yuriy Nemtsov; 24.10.2014
comment
Хорошо, я думаю, что плохо иметь один пакет, содержащий код для всех сред, но если это вам подходит... Если вам действительно нужно это динамично, я обновил ответ. - person FredyC; 25.10.2014
comment
Это весело. Это именно то, чем я сейчас занимаюсь. Однако это взлом, поэтому поиск чистого решения был моей главной мотивацией задать вопрос. Похоже, что без этого хака нет встроенного способа заранее установить глобальные переменные. - person Yuriy Nemtsov; 26.10.2014
comment
Ну, возможно, вам следует сначала спросить, как это должно работать. Вам нужен один пакет, поэтому эти переменные не могут быть включены туда. Браузер не знает ничего похожего на переменные env, поэтому единственный способ - предоставить их извне. Я добавил вариант 2 выше, если он кажется вам чище. - person FredyC; 27.10.2014
comment
Кто бы ни проголосовал за это, я хотел бы услышать, почему вы считаете это таким бесполезным. - person FredyC; 24.02.2015

Поэтому я решил, что задача веб-сервера — вставить переменные среды. В моем сценарии требовались разные регистраторы для каждой среды (например, «локальный», «тест», «продукт»).

код:

var express = require('express')
  , replace = require('replace');

...

var app = express();
var fileToReplace = <your browserified js here>;
replace({
  regex: 'ENV_ENVIRONMENT'
  , replacement: process.env.ENVIRONMENT
  , paths: [fileToReplace]
});

...

app.listen(process.env.PORT);

Я жестко закодировал «ENV_ENVIRONMENT», но вы можете создать объект в своем package.json и сделать его настраиваемым.

Это, безусловно, работает, и это имеет смысл, потому что это, возможно, единственная точка входа на сервер, которая у вас есть.

person aaaaaa    schedule 27.11.2014
comment
Мне бы хотелось получить объяснение отрицательного голоса или, что более важно, лучшее решение проблемы. - person aaaaaa; 02.04.2015

Сначала мне удалось записать файл json, а затем импортировать этот файл json в любое место, где нужно было прочитать среду.

Итак, в моем файле глотка:

import settings from './settings';
import fs from 'fs';
...
fs.writeFileSync('./settings.json', JSON.stringify(settings));

В файле settings.js:

if(process.env.NODE_ENV) {
    console.log('Starting ' + process.env.NODE_ENV + ' environment...');
} else {
    console.log('No environment variable set.');
    process.exit();
}

export default (() => {
    let settings;

    switch(process.env.NODE_ENV) {
        case 'development':
            settings = {
                baseUrl: '...'
            };
            break;
        case 'production':
            settings = {
                baseUrl: 'some other url...'
            };
            break;
    }

    return settings;
})();

Затем вы можете импортировать файл settings.json в любой другой файл, и он будет статическим, но будет содержать вашу текущую среду:

import settings from './settings.json';
...
console.log(settings.baseUrl);

Я пришел сюда в поисках более чистого решения... удачи!

person David Sinclair    schedule 19.11.2015

Я сталкиваюсь с этой проблемой при создании изоморфных реагирующих приложений. Я использую следующее (хорошо, немного хакерское) решение:

Я назначаю env объекту window, конечно, я не раскрываю все env vars, только те, которые могут быть общедоступными (без секретных ключей паролей и т.п.).

// code...
const expose = ["ROOT_PATH", "ENDPOINT"];
const exposeEnv = expose.reduce(
    (exposeEnv, key) => Object.assign(exposeEnv, { [key]: env[key] }), {}
);
// code...
res.send(`<DOCTYPE html>
// html...
<script>window.env = ${JSON.stringify(exposeEnv)}</script>
// html...
`);
// code...

затем в точке входа клиентов моих приложений (о да, у вас должна быть одна точка входа) я делаю это:

process.env = window.env;

YMMV АКА WFM!

person Elmer    schedule 28.11.2016