bit icon indicating copy to clipboard operation
bit copied to clipboard

Environment variables

Open amitrahav opened this issue 3 years ago • 3 comments

Description

Environment variables are not loading into process during run app or preview.

Specifications

  • Bit version: 0.0.792
  • Node version: v16.16.0
  • npm / yarn version: yarn -v 1.22.19
  • Platform: OSx Monterey
  • Bit compiler (include version): ?
  • Bit tester (include version): ?

Context and additional information

Using an existing mono-repo, trying to convert it into small bits. But I can not load env vars from the host app (that contains all the other bit components). All of my components are teambit/react.

amitrahav avatar Aug 06 '22 17:08 amitrahav

which env-vars you refer? variables defined in the node process and your app can't access?

itaymendel avatar Aug 18 '22 08:08 itaymendel

Yap.

environment variables ( like: REACT_APP_SOME_API_KEY=a12m3234fjdp-xx#5) aren't being loaded from .env, but is not avilable also if i run export REACT_APP_SOME_API_KEY=a12m3234fjdp-xx#5 && bit run app_compnenet_path (or bit start).

Is there a best practice of loading environment variables into apps so this code could will load the correct value instead of undfined? process.env.REACT_APP_SOME_API_KEY

amitrahav avatar Aug 25 '22 15:08 amitrahav

@itaymendel Here is a git repo that helps to understand the problem: https://github.com/amitrahav/bit-load-env-reproduce

amitrahav avatar Aug 31 '22 15:08 amitrahav

Same issue here. Any updates?

LordOfTheDings avatar Oct 19 '22 17:10 LordOfTheDings

Hello, same issue here, any updates pls ? Cannot access .env variables through process.env !

gramosukaj avatar Feb 08 '23 11:02 gramosukaj

The best way to go is probably to create a build task that will inject these vars. If it's something you configure for production then it should be set on Netlify or wherever you deploy. If you need it for the devserver, you shouldn't be using the process.env because it doesn't run on node.

NitsanCohen770 avatar Aug 28 '23 23:08 NitsanCohen770

@NitsanCohen770 can you suggest an alternative to env vars that works in Bit? I tried setting up a custom env with a webpack config transformation to inject the variables into the process.env object but this does not seem to work.

  function commonTransformation(config: WebpackConfigMutator, _context: WebpackConfigTransformContext) {
    config.addPlugin(
      new webpack.EnvironmentPlugin( { REACT_ENV_HELLO: "HELLO FROM WEBPACK" } )
    )
    return config;
  }

Edit: After a few restarts and changing webpack.EnvironmentPlugin to webpack.DefinePlugin I got the above to work.

sbland avatar Sep 27 '23 19:09 sbland

Hello, same issue here. I have checked the documentation and nothing about environment variables.

yasniel1408 avatar Dec 28 '23 15:12 yasniel1408

I managed to hack together a solution that I think may be using an old version of a custom React bit env but it's working for me.

The solution below uses a namespace id to filter only required environment variables.

The env file looks like this

PROJECT_NAMESPACE=MY_PROJECT
MY_PROJECT_api_port=1234
MY_PROJECT_api_host=4567
OTHER_VAR=foo

In this file only variables with MY_PROJECT prefix will be injected with Webpack.

I have this inside of react-env-custom.main.runtime.ts


import { ReactEnvCustomAspect } from './react-env-custom.aspect';
import { EnvsAspect, EnvsMain } from '@teambit/envs';
import { ReactAspect, ReactMain } from '@teambit/react';
import { MainRuntime } from '@teambit/cli';

import {
  WebpackConfigTransformer,
  WebpackConfigMutator,
  WebpackConfigTransformContext,
} from '@teambit/webpack';

/**
 * Transformation to apply for both preview and dev server
 * @param config
 * @param _context
 */
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function commonTransformation(
  config: WebpackConfigMutator,
  _context: WebpackConfigTransformContext
) {
  const webpack = require('webpack');
  if (process.env.NODE_ENV !== 'production') {
    const filteredEnv = Object.keys(process.env).reduce((acc, key) => {
      if (
        process.env.PROJECT_NAMESPACE?.split(',').some((prefix) => {
          return key.startsWith(prefix);
        })
      ) {
        acc[key] = process.env[key];
      }
      return acc;
    }, {});
    config.addPlugin(
      new webpack.DefinePlugin({
        'process.env': JSON.stringify(filteredEnv),
      })
    );
  } else {
    // TODO: Find safe way of injecting env vars into production build
  }
  return config;
}

/**
 * Transformation for the preview only
 * @param config
 * @param context
 * @returns
 */
export const previewConfigTransformer: WebpackConfigTransformer = (
  config: WebpackConfigMutator,
  context: WebpackConfigTransformContext
) => {
  const newConfig = commonTransformation(config, context);
  return newConfig;
};



export class ReactEnvCustomMain {
  static slots = [];

  static dependencies = [ReactAspect, EnvsAspect];

  static runtime = MainRuntime;

  static async provider([react, envs]: [ReactMain, EnvsMain]) {

    const webpackModifiers = {
       previewConfig: [previewConfigTransformer],
       devServerConfig: [devServerConfigTransformer],
    };

    const ReactEnvCustomEnv = react.compose([

      react.useWebpack(webpackModifiers),
 
    ]);
    envs.registerEnv(ReactEnvCustomEnv);
    return new ReactEnvCustomMain();
  }
}

ReactEnvCustomAspect.addRuntime(ReactEnvCustomMain);

sbland avatar Jan 16 '24 20:01 sbland

Thanks for sharing @sbland! That code looks very useful. I noticed it doesn't define the devServerConfigTransformer function - is there any additional special logic we'd need to be aware of in that function beyond what's visible in the commonTransformation function? Thanks again!

coreyaus avatar Jan 17 '24 02:01 coreyaus

@coreyaus my devServerConfigTransformer looks exactly the same as previewConfigTransformer

export const devServerConfigTransformer: WebpackConfigTransformer = (
  config: WebpackConfigMutator,
  context: WebpackConfigTransformContext
) => {
  const newConfig = commonTransformation(config, context);
  return newConfig;
};

sbland avatar Jan 17 '24 08:01 sbland

I want to add a environment variable can someone help me by providing a simple step by step procedure.

Jagadishvg avatar Feb 05 '24 07:02 Jagadishvg

@Jagadishvg create a react environment by following the steps here: https://bit.dev/docs/react-env/set-up-your-env/ making sure to assign the env to your component.

Then in my-custom-env/config/webpack.config.ts add the following...


import type {
  WebpackConfigMutator,
  WebpackConfigTransformContext,
} from '@teambit/webpack';

/**
 * modifies the webpack config for the components preview bundle.
 * @see https://bit.dev/reference/webpack/webpack-config
 */
export const webpackTransformer = (
  config: WebpackConfigMutator,
  _context: WebpackConfigTransformContext
): WebpackConfigMutator => {

  const webpack = require('webpack');
  if (process.env.NODE_ENV !== 'production') {
    const filteredEnv = Object.keys(process.env).reduce((acc: any, key: string) => {
      if (
        process.env.PROJECT_NAMESPACE?.split(',').some((prefix) => {
          return key.startsWith(prefix);
        })
      ) {
        acc[key] = process.env[key];
      }
      return acc;
    }, {});
    config.addPlugin(
      new webpack.DefinePlugin({
        'process.env': JSON.stringify(filteredEnv),
      })
    );
  } else {
    // TODO: Find safe way of injecting env vars into production build
  }
  return config;

};

Then create an .env file in the root dir like below...

PROJECT_NAMESPACE=MY_PROJECT
MY_PROJECT_api_port=1234
MY_PROJECT_api_host=4567

sbland avatar Feb 05 '24 14:02 sbland

If your using ReactEnv instead of ReactMain (I think this must have been a doc change at some point?) you can implement as below.

import { ReactEnv } from '@teambit/react.react-env';
import { webpackTransformer } from './config/webpack.config.js';
import { EnvHandler } from '@teambit/envs';
import { ReactPreview } from '@teambit/preview.react-preview';
import { Preview } from '@teambit/preview';
import hostDependencies from './preview/host-dependencies.js';


export class ReactEnvCustom extends ReactEnv {

  protected previewMounter = require.resolve('./preview/mounter');

  /**
   * create an instance for Bit Preview.
   */
  preview(): EnvHandler<Preview> {
    return ReactPreview.from({
      // TODO: Add webpack here
      transformers: [
        webpackTransformer,
      ],
      mounter: this.previewMounter,
      hostDependencies,
    });
  }

}

sbland avatar Apr 04 '24 04:04 sbland