Search code examples
meteor

How to access environment variables in client side code during build in Meteor?


Related:

I'm also aware of METEOR_SETTINGS.

I have a Meteor app that will be deployed for different clients with different theming/features. I want to use an env variable such as process.env.CLIENT and have code like if(process.env.CLIENT === 'foo'). During build the env variable should be replaced and dead code elimination will remove/strip the if-block. This already works with NODE_ENV.

I don't want to ship code that a certain client does not need and I also don't want to implicitly expose the list of other clients. Both these things would happen if I check Meteor.settings at runtime. I need this to happen at compile time. Each client gets a different build.

How do I get environment variables through to the client? How are others solving this? process.env on the client currently is:

{"NODE_ENV":"development","TEST_METADATA":"{}"}

In other build tools I can either access all env variables on the client or those with a special prefix (for security reasons) like FOO_.


Solution

  • As usual a night of sleep brought the answer: https://babeljs.io/docs/en/babel-plugin-transform-inline-environment-variables/

    meteor npm install babel-plugin-transform-inline-environment-variables --save-dev
    

    Add .babelrc

    {
      "plugins": [
        ["transform-inline-environment-variables", {
          "include": [
            "CLIENT"
          ]
        }]
      ]
    }
    

    Now both of these work as expected

    CLIENT=foo meteor run
    CLIENT=foo meteor build --directory $OUT
    

    (sprinkle in some m -rf .meteor/local/plugin-cache/ before switching clients in development to properly rebuild)

    Original code:

    if (process.env.CLIENT === 'foo') {
      console.log('Client is foo');
    } else if (process.env.CLIENT === 'bar') {
      console.log('Client is bar');
    }
    

    Output during development:

    if ("foo" === 'foo') {
      console.log('Client is foo');
    } else if ("foo" === 'bar') {
      console.log('Client is bar');
    }
    

    Output in production:

    console.log("Client is foo")
    

    During development this allows me to easily switch between clients. While working on the same client adding/removing process.env.CLIENT works as expected and with hmr etc.

    For deployments I'm using dokku. That means once I've configured the environments (dokku config:set app CLIENT=foo) I can do:

    git push client_foo main
    git push client_bar main
    

    to deploy both clients from the same branch without worrying that things get messed up.