My favorite way to manage configuration file is to use .env (dotenv).
Because
- You have shared config file with your team.
- But you also have your own private config file which is ignored by git.
- You can have multiple config files for each deployment types (e.g., development, production, test).
- It is (kind of) a standard way of managing configuration. So most of the time, it will work with many other tools seamlessly (e.g., Docker).
Now I will show you my code. But first I want to tell you that I got this inspiration from create-react-app source code.
const fs = require('fs')
const path = require('path')
const dotenv = require('dotenv')
const dotenvExpand = require('dotenv-expand')
You need 2 libraries which are dotenv and dotenv-expand.
if (!process.env.NODE_ENV) {
process.env.NODE_ENV = 'development'
}
You can throw error if you want but I prefer to use development environment as a default.
function getEnvPath() {
return path.resolve(__dirname, '../', '.env')
}
// my folder structure looks like this
// /src/environments.js (this file)
// /src/index.js (entry point)
// /.env
// /.env.development
// /.env.development.local
// /.gitignore
This function returns absolute path of .env file which is relative to the directory that contains this file.
function getNodeEnv() {
return process.env.NODE_ENV.trim()
}
The function above is optional. But I've found a bug when I used windows to run code with CMD, the NODE_ENV gave me an extra spacebar. So I use .trim() to fix that bug (I don't know whether the bug still exists today because I moved to WSL already).
const dotenvFiles = [
`${getEnvPath()}.${getNodeEnv()}.local`,
getNodeEnv() !== 'test' && `${getEnvPath()}.local`,
`${getEnvPath()}.${getNodeEnv()}`,
getEnvPath(),
].filter(Boolean)
The code above is the array that contains order of .env files to load. The order came from this link, I believe it is best practice of some framework and that practice is popular among us (developers).
dotenvFiles.forEach(dotenvFile => {
if (fs.existsSync(dotenvFile)) {
dotenvExpand(
dotenv.config({
path: dotenvFile,
})
)
}
})
Then what's this code doing is loading each file sequentially from the order of dotEnvFiles array.
This is full code of the environments.js file.
// environments.js
// Inspiration from https://github.com/facebook/create-react-app/blob/fddce8a9e21bf68f37054586deb0c8636a45f50b/packages/react-scripts/config/env.js
const fs = require('fs')
const path = require('path')
const dotenv = require('dotenv')
const dotenvExpand = require('dotenv-expand')
if (!process.env.NODE_ENV) {
process.env.NODE_ENV = 'development'
}
function getEnvPath() {
return path.resolve(__dirname, '../', '.env')
}
function getNodeEnv() {
return process.env.NODE_ENV.trim()
}
// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
const dotenvFiles = [
`${getEnvPath()}.${getNodeEnv()}.local`,
// Don't include `.env.local` for `test` environment
// since normally you expect tests to produce the same
// results for everyone
getNodeEnv() !== 'test' && `${getEnvPath()}.local`,
`${getEnvPath()}.${getNodeEnv()}`,
getEnvPath(),
].filter(Boolean)
// Load environment variables from .env* files. Suppress warnings using silent
// if this file is missing. dotenv will never modify any environment variables
// that have already been set. Variable expansion is supported in .env files.
// https://github.com/motdotla/dotenv
// https://github.com/motdotla/dotenv-expand
dotenvFiles.forEach(dotenvFile => {
if (fs.existsSync(dotenvFile)) {
dotenvExpand(
dotenv.config({
path: dotenvFile,
})
)
}
})
Finally I will show you how to use this new cool stuff.
1) Create .env files
# /.env.development
CONFIG_1 = SHARED_CONFIG_1
CONFIG_2 = SHARED_CONFIG_2
EXPANDED_CONFIG = ${CONFIG_1}+${CONFIG_2}
# /.env.development.local
CONFIG_2 = YOUR_CONFIG_2
CONFIG_WITH_SPACE = " SPACE"
2) Include environments.js to your entry point of your project (in this case, it's /src/index.js)
// /src/index.js
require('./environments')
console.log(process.env.CONFIG_1)
console.log(process.env.CONFIG_2)
console.log(process.env.EXPANDED_CONFIG)
console.log(process.env.CONFIG_WITH_SPACE)
3) Run your code with development environment
NODE_ENV=development node src/index.js
Here's the result.
SHARED_CONFIG_1
YOUR_CONFIG_2
SHARED_CONFIG_1+YOUR_CONFIG_2
SPACE
Don't forget to add .gitignore file
# /.gitignore
.env.local
.env.development.local
.env.test.local
.env.production.local
Top comments (1)
ππ΄