What's the proper way of setting environment variable in Netlify functions? - javascript

What's the proper way of setting environment variables in netlify? I would like to be able to set different values for the variables depending on the environment.
Pseudo code:
let host;
if (process.env.GATSBY_CUSTOM_CONTEXT === 'production') {
host = process.env.PRODUCTION_HOST
} else if (process.env.GATSBY_CUSTOM_CONTEXT === 'development') {
host = process.env.DEVELOPMENT_HOST
}
I have tried passing env variable thru CLI, like GATSBY_CUSTOM_CONTEXT=production gatsby build and I also tried using same command with cross-env.
My other attempt used netlify.toml:
[build]
base = "/"
publish = "public"
command = "yarn build"
functions = "src/functions"
[context.production]
[context.production.environment]
GATSBY_CUSTOM_CONTEXT = "production"
All of these options worked with netlify dev locally, but in production GATSBY_CUSTOM_CONTEXT is always undefined.

The reason you can't resolve the environment variables in your Netlify functions is because as of the time of your question, Netlify does not transfer the environment variables from the netlify.toml file.
You must put them into the admin panel in your site settings in the app.netlify.com dashboard.

Unfortunately, what you're looking to doesn't seem to be currently supported. Though they provide an alternative approach.
I found this snippet on their docs:
CALLING ENVIRONMENT VARIABLES
Using environment variables directly as
values ($VARIABLENAME) in your netlify.toml file is not supported.
However, the following workflow can be used to substitute values in
the file with environment variable values, assuming you are only
trying to change headers or redirects. The rest of the file is read
BEFORE your build — but those sections are read AFTER the build
process.
Add a placeholder like HEADER_PLACEHOLDER somewhere in the netlify.toml redirects or headers sections.
Create an environment variable, for example PROD_API_LOCATION, with the desired value. You can create environment variables in the
toml file or in our UI. You might use the latter to keep sensitive
values out of your repository.
Prepend a replacement command to your build command. Here’s an example for a site using yarn build to build: sed -i
s/HEADER_PLACEHOLDER/${PROD_API_LOCATION}/g netlify.toml && yarn build
Taken from here: https://www.netlify.com/docs/netlify-toml-reference/

Related

Building configurable react app with additional environment variable

I'm building an app that has some variations. The core of an app is the same but for now, I need to develop some parts of the app in different way, like another color scheme, different photos etc.
My Question is: Is there any possibility to build an app with specified instance by env variable? For example, I have set of photos provided as below.
[{
"photo1":{
"path":"my_path_to_file1",
"instanceToDeploy":"instanceABC"
}
},
{
"photo2":{
"path":"my_path_to_file2",
"instanceToDeploy":"instanceCBA"
}
}]
And for now, I would like to build my app like
npm run build instanceCBA
After this operation, I want to have build version of an app only with photos/whatever I will include in build command.
If elements are not tagged - I would like to build them anyway.
Is there any way to do this in React or something similar to this idea?
My previous attempt to this, was building the app on a few separated branches. Of course, unique changes was written without affecting another instances, but in situation when I've written the code which have to be on all instances - I have to actualize all the branches.
My main desire is to build some configurable elements that depends of choosen instance in my app.
Thanks for all possible help.
There are several options of how you can do it:
#1 (the easiest way)
If you use create-react-app boilerplate for your project you can use '.env' file for setting environment variables. You can find more info about it here: https://create-react-app.dev/docs/adding-custom-environment-variables/
#2
You can pass the parameter from your scripts that you defined in the package.json file. For example, let's say your scripts section looks like this:
"scripts": {
"build": "webpack --myInstance instanceCBA",
}
In this case in the webpack.config file you can read your parameter via process.argv array:
const instancePrefixInd = process.argv.indexOf('--myInstance');
let instance = '';
if (instancePrefixInd >= 0) {
instance = process.argv[instancePrefixInd + 1];
}
Then you can use this value in you webpack.config to specify details of the build or pass it directly to the app via setting 'process.env' variables (e.g process.env.MY_INSTANCE)

Node Js Environment Specific Variables Dev/Testing/UAT

I am new to Node js, started developing the Angular application using Angular 1.2 and Node js. As of now, I have hardcoded the REST API(Java) endpoints in the node services.js. Now I want to load the base endpoint URI specific to the environment. I have tried few ways by setting a new key value for the process.env, a env file and load it. Can anyone please help me.
I have tried below approach.
Created devEnv.env file under root folder.
Added 3 key-value pairs
hostname = xyz
apikey = 123
devUrl = xyz/xyz/xyz.com/
Then in terminal, I am trying to add it to the source.
$ source denEnv.env
I am getting source not found.
Another way I have added the script in package.json file
{
"start-dev": "source devEnv.env; node server.js"
}
In terminal I executed
$ npm start-dev
It's also failing. Can anyone please let me know what mistake I am doing and what is the correct approach.
Thanks in advance.
There are three methods known to me:
1) .env file
You need to install dotenv package using npm install/yarn add and on top of your main file (e.g. index.js) put require('dotenv').config(). That should load your variables to node.
2) passed on a start
If you want pass a small amount of environmental variables you can try something like this in your package.json:
{
"start-dev": "hostname=xyz apikey=123 devUrl=xyz/xyz/xyz.com node server.js"
}
Advice: environmental variables should look like HOSTNAME, API_KEY or DEV_URL.
3) system environmental variables
Solution: Set environment variables from file
Your variables are most likely not being exported to the shell. To be able to source your devEnv.env script, try to modify it as follows:
#!/bin/bash
export hostname=xyz
export apikey=123
export devUrl=xyz/xyz/xyz.com/
You most likely need to give it executable rights:
chmod +x devEnv.env
And then source it by running:
. devEnv.env
Another example can be found here: Set environment variables from file

Conditional javascript source code

Background:
I have 3 different URLs, one per environment (dev, test, prod), and I don't want to expose all the URLs in the client (source code).
How can I expose in the client code, just the one corresponding to the environment in context?
Note: As I understand, I need to do something in the build process using environment variables (I'm using node.js). However, I don't want to touch anything related with webpack, as what I'm trying to do is a standalone package that can be imported in any application regardless of the framework they are using. Webpack plugins/configuration are not an option, but I can use any npm package if required.
During your build process, you can check the environment variable and then copy over a config file. For example, you could keep your URIs in /config/<env>.js, and then copy/rename it to /settings.js during the build. Your URL could be exported from that.
The following npm package fits my requirements completely https://www.npmjs.com/package/config , you can load conditional files based on the node environment variable NODE_ENV, so when NODE_ENV=development, the file /config/development.js is used to create the build. you can use different extensions for the config files, also you can customize the config folder path by changing the environment variable $NODE_CONFIG_DIR heres an example:
const config = require('config');
process.env.$NODE_CONFIG_DIR = './' // relative path ./config
const url = config.get('url');
//if NODE_ENV is development will load the file config/development.js
console.log(url);

Setting default environment variables in Heroku

I'm working on an app that connects to third-party APIs which require the use of an APP ID and SECRET KEY.
I am storing these values as environment variables in heroku, so that I don't need to expose them in my code.
If I deploy to heroku, it will use heroku's environment variables to resolve these API credentials.
If I'm working on it locally, I want to use my config.js module, and lookup the API credentials there. NOTE: This config.js file is included in my .gitignore so that these credentials never end up in the cloud.
The problematic code is this:
var api_secret = process.env.API_SECRET || require('../../config.js').secret;
When I run this locally, I've got no issues. Meaning, it is unable to resolve the environment variable, so instead it uses the secret from within config.js.
When I run it on heroku, it DOES throw an error telling me that module 'config.js' could not be found. This makes sense, because it was never pushed up with the rest of the repo, by virtue that it is in my .gitignore.
Because heroku is parsing through my code before it ever runs, the require('../../config.js') is problematic. It is trying to lookup a file that doesn't exist.
How can I solve the issue of using environment variables when deployed, and the config.js module when running locally?
On the Heroku dashboard for your application, you can set config variables. If you have the Heroku Toolbelt set up on your machine, you can also use:
heroku config:set API_SECRET=secret
See this article for more.
Edit: Think I may have misunderstood the question. I would suggest, if possible, using the dotenv npm package to set your config variables locally.
If not, another thing to check would be that the config.js package is in your package.json file, because Heroku will use this to build your dependencies.
If you do not want to push your config.js to heroky at all, you can just follow the following to determine whether the config file exists or not with a try catch and the file system module:
Check synchronously if file/directory exists in Node.js
In your case:
var fs = require('fs'),
api_secret,
config;
try {
// Check whether config.js exists
config = fs.lstatSync('../../config.js');
// If we reach this line then config.js exists, yay!
api_secret = process.env.API_SECRET || require('../../config.js').secret;
// or alternatively api_secret = require('../../config.js').secret;
// depending on your logic
}
catch (e) {
// else config.js does not exist
api_secret = process.env.API_SECRET
}
To run Heroku commands programmatically, you can set up a free Ruby app and make it do what you want through API calls. Use Heroku-api. See https://github.com/heroku/heroku.rb
If you want to set Heroku commands manually, you can set env variables on Heroku either with the command heroku config:set MYVAR=MYVALUE or through the Heroku dashboard (Click on your app > settings > reveal config vars > edit).

Node.js: How to setup different variables for prod and staging

I'm using Express and I need to use different credentials for each server (staging and production).
I could setup the variables in the server.coffee file but then I'd need to access those variables in different files.
server.coffee:
app.configure 'production', () ->
app.use express.errorHandler()
What's the solution? Setup the variables and then export them?
./config.js
var development = {
appAddress : '127.0.0.1:3000',
socketPort : 4000,
socketHost : '127.0.0.1',
env : global.process.env.NODE_ENV || 'development'
};
var production = {
appAddress : 'someDomain.com',
socketPort : 4000,
socketHost : '8.8.8.8',
env : global.process.env.NODE_ENV || 'production'
};
exports.Config = global.process.env.NODE_ENV === 'production' ? production : development;
./app.js
var cfg = require('./config').Config;
if (cfg.something) { // switch on environment
// your logic
}
This might be a good place to use npm-config.
When running scripts (see npm-scripts(7)) the package.json "config" keys are overwritten in the environment if there is a config param of <name>[#<version>]:<key>
I would not use them for every type of variable configuration setting, but I think it's a good solution for simple cases like URLs and ports because:
You put them directly into package.json.
In addition, you can specify them on the command line or as ENV variables.
Anything run through npm can refer to them (e.g., scripts).
You can set them per-user with `npm config set foo:port 80
The one caveat is that the config parameter in your package.json is only automatically exported into the environment when you run your code through npm. So, if you just run it with node, like, node ./myapp.js, then you can't expect that process.env.npm_package_config_foo will contain your value. However, you can always var pkg = require('./package.json'); and access the values at pkg.config.
Because it might not be immediately obvious, I'd also add that the npm_package_config environment variables do not bubble up to apps that depend on your npm package. So, if your depended-on package refers to process.env.npm_package_config_foo, then the dependent package would have to define that in its own package.json. I guess since it's an "npm_package_config" it wouldn't make sense to push them all the way up the tree.
So, how would I use one npm config variable and have it work all the way up the tree, in both the base package and the packages that depend on it? It's actually a little confusing, and I had to figure this out through trial and error.
Let's say you have a package connector and package client. client depends on connector and you want to specify a config parameter for connector that can be used or overwritten in client. If you use process.env.npm_package_config.port in your connector module, then when it's depended on in client module, then that variable won't be exported and it will end up as undefined.
However, if you instead use process.env.npm_config_connector_port (notice the first one starts with npm_package_config and the other with npm_config_packagename), then you can at least set that in your .npmrc using npm config set connector:port 80 and it will be "namespaced" as process.env.npm__config_connector_port everywhere that you run npm, including scripts that you run in client that depend on connector, and you'll always be able to overwrite it on the command line, in your ENV, or in your .npmrc. You just have to keep in mind that, as with any environment variable, it may not always be set. So, I would use the default operator with the process.env.npm_config_connector_port as the first (preferred) value:
var port = process.env.npm_config_connector_port || sane_default
Here, sane_default could be populated from one of the other recommended methods. Personally, I like keeping configuration data like these in JSON files at the very least, and package.json seems like the best JSON file to put them in. Store them in data instead of code and then you can easily use the static JSON in-line, generate them dynamically, or pull them from the filesystem, URLs or databases.
I have uploaded an implementation into https://github.com/qiangyu/nodejsconfig. I believe it will satisfy your needs. Basically, you only need to provide one configuration file:
dev.appAddress = '127.0.0.1:3000';
prod.appAddress = 'someDomain.com';
Then, you use following code to read the appAddress in prod environments:
var xnconfig = require('nodejsconfig');
var fs = require('fs');
var data = fs.readFileSync(__dirname+"/config.properties", "UTF8");
// assume we will be using environment "prod"
var config = xnconfig.parse("prod", data);
// the output will be someDomain.com
console.log(config.getConfig("appAddress"));
If you don't want the logic for determining which config to use in each file (which would look pretty ugly), you'll have to export it somewhere.
What I would suggest: Have a config.json file containing the different configs. The main file requires it and does something like config.default = config.(condition ? 'production':'development'). In all other files, you can now just do require('./config').default.
I have an app which uses three different methods of declaring config variables (uris, api keys, credentials, etc.) depending upon the environment (production = environment variables; staging = command line args; local = config files.)
I wrote a little "config" module to handle merging all of these options into one object that I can use in my app and uploaded it as a gist: https://gist.github.com/1616583
It might not be the best implementation, but it's been working pretty well so far :).

Categories

Resources