Переменные среды в изоморфном приложении JS: найти и заменить Webpack?

Я использую webpack для объединения изоморфного приложения JS (на основе этого примера), чтобы браузер выполнял тот же код, что и сервер, Все работает плавно, за исключением того, что у меня есть config.js с некоторыми настройками, которые извлекаются из переменных среды на сервере:

module.exports = {
  servers:
    auth: process.env.AUTH_SERVER_URL,
    content: process.env.CONTENT_SERVER_URL
  }
}

На сервере это грандиозно, но когда webpack делает это для клиента process пустым, и это не работает.

Я надеюсь, что есть какой-то "найти и заменить" плагин webpack, который заменит их своим содержимым только в этом файле?

"…config.js content…".replace(/process\.env\.([a-z0-9_]+)/, function(match, varName) {
  return process.env[varName];
})

Ответ 1

В webpack.config.js используйте preLoaders (или postLoaders),

  module: {
    preLoaders: [
      { test: /\.js$/, loader: "transform?envify" },
    ]
  }

Другой способ: webpack.DefinePlugin:

plugins: [
    new DefinePlugin({
      'process.env': Object.keys(process.env).reduce(function(o, k) {
        o[k] = JSON.stringify(process.env[k]);
        return o;
      }, {})
    })
]

ПРИМЕЧАНИЕ. Старый метод с использованием envify-loader устарел:

DEPRECATED: вместо этого используйте transform-loader + envify.

Ответ 2

Обратите внимание, что использование DefinePlugin, как предлагается в принятом ответе, потенциально опасно, поскольку оно полностью предоставляет process.env. Как уже отмечал Тобиас, на самом деле есть плагин EnvironmentPlugin, который делает именно это с добавленной способностью "белый список", используя DefinePlugin внутренне.

В webpack.config.js:

{
  plugins: [
    new webpack.EnvironmentPlugin([
      'NODE_ENV',
      'WHITELISTED_ENVIRONMENT_VARIABLE'
    ])
  ]
}

Ответ 3

Да; выглядит как envify-loader - это простое решение.

Я добавил к моим загрузчикам webpack следующее:

{
  test: /config\.js$/, loader: "envify-loader"
}

И config.js (и только тот файл) изменен, чтобы включить любые ссылочные переменные среды статически:)

Ответ 4

Мне нужен был способ использовать переменные env, установленные на машине, на которой запущен код, нет переменных env машины, создающей приложение.

Я пока не вижу решения для этого. Это то, что я сделал.

В publicEnv.js:

// List of the env variables you want to use on the client. Careful on what you put here!
const publicEnv = [
  'API_URL',
  'FACEBOOK_APP_ID',
  'GA_ID'
];

const isBrowser = typeof window !== 'undefined';
const base = (isBrowser ? window.__ENV__ : process.env) || {};

const env = {};
for (const v of publicEnv) {
  env[v] = base[v];
}
export default env;

В файле шаблона HTML страницы у меня есть:

import publicEnv from 'publicEnv.js';

...

<script>
  window.__ENV__ = ${stringify(publicEnv)};

  // Other things you need here...
  window.__INITIAL_STATE__ = ${stringify(initialState)};
</script>

Итак, теперь я могу получить значение переменной env как для frontend, так и для backend с помощью:

import publicEnv from 'publicEnv.js';

...

console.log("Google Analytic code is", publicEnv.GA_ID);

Надеюсь, это поможет.