dotenv multi logic
This commit is contained in:
parent
5582d09293
commit
060163f64a
11 changed files with 200 additions and 94 deletions
40
.gitignore
vendored
Normal file
40
.gitignore
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
# compiled output
|
||||
/dist
|
||||
/lib
|
||||
/node_modules
|
||||
*.tgz
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
|
||||
# Tests
|
||||
/coverage
|
||||
/.nyc_output
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
|
||||
# .env local files
|
||||
.env.development.local
|
||||
.env.local
|
||||
.env.production.local
|
||||
.env.test.local
|
44
README.md
44
README.md
|
@ -1,14 +1,21 @@
|
|||
# dotenv-multi
|
||||
|
||||
Dotenv-multi is a module that uses `dotenv` and `dotenv-expand` to load files similarly to Create React App script's. It allows the use of NODE_ENV and local specific env files.
|
||||
Dotenv-multi is a module that uses [dotenv](https://www.npmjs.com/package/dotenv) and [dotenv-expand](https://www.npmjs.com/package/dotenv-expand) to load files similarly to [Create React App script's](https://create-react-app.dev/docs/adding-custom-environment-variables/#what-other-env-files-can-be-used). It allows the use of NODE_ENV and local specific env files.
|
||||
|
||||
This is useful because now you can commit your default env files into the repo and still have a sane way to override them locally without having changes in your local git on one .env file.
|
||||
|
||||
Example root files:
|
||||
```
|
||||
.env
|
||||
.env.development
|
||||
.env.development.local (not pushed to git)
|
||||
```
|
||||
|
||||
# Install
|
||||
|
||||
```
|
||||
# with npm
|
||||
npm install @ringofstorms/dotenv-multi dotenv dotenv-expand
|
||||
npm install @ringofstorms/dotenv-multi
|
||||
```
|
||||
|
||||
# Usage
|
||||
|
@ -25,6 +32,27 @@ import { config } from '@ringofstorms/multi-env';
|
|||
config();
|
||||
```
|
||||
|
||||
## Boolean support
|
||||
|
||||
This package also uses the [yn](https://www.npmjs.com/package/yn) package to convert environment variables into javascript strings that will resolve as true false. (It replaces values like `0`, `no`, `false`, etc into an empty string `""`)
|
||||
|
||||
```typescript
|
||||
config({
|
||||
convertToBooleanPredicate: variable => variable.includes("BOOL"),
|
||||
/* and or */ convertToBoolean: ["BOOL_VARIABLE_TO_CONVERT"]
|
||||
});
|
||||
```
|
||||
|
||||
## Debug
|
||||
|
||||
You can enable debug logs which will also enable debug mode on `dotenv` calls to see what is going on when a variable does not resolve how you expect.
|
||||
|
||||
```typescript
|
||||
config({
|
||||
debug: true,
|
||||
});
|
||||
```
|
||||
|
||||
# Configuring .gitignore
|
||||
|
||||
You should add the following to your `.gitignore` file:
|
||||
|
@ -36,4 +64,14 @@ You should add the following to your `.gitignore` file:
|
|||
.env.test.local
|
||||
```
|
||||
|
||||
## [What other `.env` files can be used?](https://create-react-app.dev/docs/adding-custom-environment-variables/#what-other-env-files-can-be-used)
|
||||
# Contributing
|
||||
|
||||
### building
|
||||
|
||||
`npm run build`
|
||||
|
||||
### publishing
|
||||
|
||||
if not already done `npm login`
|
||||
|
||||
`npm publish --access public`
|
||||
|
|
1
dist/index.d.ts
vendored
1
dist/index.d.ts
vendored
|
@ -1 +0,0 @@
|
|||
export declare function config(): Record<string, string>;
|
9
dist/index.js
vendored
9
dist/index.js
vendored
|
@ -1,9 +0,0 @@
|
|||
"use strict";
|
||||
exports.__esModule = true;
|
||||
exports.config = void 0;
|
||||
function config() {
|
||||
console.log("TEST config");
|
||||
return { test: 'test' };
|
||||
}
|
||||
exports.config = config;
|
||||
//# sourceMappingURL=index.js.map
|
1
dist/index.js.map
vendored
1
dist/index.js.map
vendored
|
@ -1 +0,0 @@
|
|||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,SAAgB,MAAM;IACpB,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAC3B,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AAC1B,CAAC;AAHD,wBAGC"}
|
63
dist/tsconfig.tsbuildinfo
vendored
63
dist/tsconfig.tsbuildinfo
vendored
|
@ -1,63 +0,0 @@
|
|||
{
|
||||
"program": {
|
||||
"fileInfos": {
|
||||
"../node_modules/typescript/lib/lib.d.ts": {
|
||||
"version": "2dc8c927c9c162a773c6bb3cdc4f3286c23f10eedc67414028f9cb5951610f60",
|
||||
"signature": "2dc8c927c9c162a773c6bb3cdc4f3286c23f10eedc67414028f9cb5951610f60",
|
||||
"affectsGlobalScope": false
|
||||
},
|
||||
"../node_modules/typescript/lib/lib.es5.d.ts": {
|
||||
"version": "9622e8bd7cc72a7dab819a8011ecbf81d443638082e5cb99ecf2e75ff56ffc9d",
|
||||
"signature": "9622e8bd7cc72a7dab819a8011ecbf81d443638082e5cb99ecf2e75ff56ffc9d",
|
||||
"affectsGlobalScope": true
|
||||
},
|
||||
"../node_modules/typescript/lib/lib.dom.d.ts": {
|
||||
"version": "abadddbf660adeec27e9a56584907d52fa1d6e1e1dc49f639a921baa951b7a84",
|
||||
"signature": "abadddbf660adeec27e9a56584907d52fa1d6e1e1dc49f639a921baa951b7a84",
|
||||
"affectsGlobalScope": true
|
||||
},
|
||||
"../node_modules/typescript/lib/lib.webworker.importscripts.d.ts": {
|
||||
"version": "7fac8cb5fc820bc2a59ae11ef1c5b38d3832c6d0dfaec5acdb5569137d09a481",
|
||||
"signature": "7fac8cb5fc820bc2a59ae11ef1c5b38d3832c6d0dfaec5acdb5569137d09a481",
|
||||
"affectsGlobalScope": true
|
||||
},
|
||||
"../node_modules/typescript/lib/lib.scripthost.d.ts": {
|
||||
"version": "097a57355ded99c68e6df1b738990448e0bf170e606707df5a7c0481ff2427cd",
|
||||
"signature": "097a57355ded99c68e6df1b738990448e0bf170e606707df5a7c0481ff2427cd",
|
||||
"affectsGlobalScope": true
|
||||
},
|
||||
"../src/index.ts": {
|
||||
"version": "a046922c32012fd8e2d32b30256e7ae8eaf10f6ee52cb4f6a8de3fe75aa534eb",
|
||||
"signature": "a045457643ba909269c1cec5ec9c110dcfa9242adf17b0bb9676f0f3f5cf82e9",
|
||||
"affectsGlobalScope": false
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"target": 0,
|
||||
"module": 1,
|
||||
"strict": true,
|
||||
"allowJs": false,
|
||||
"declaration": true,
|
||||
"removeComments": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"sourceMap": true,
|
||||
"incremental": true,
|
||||
"outDir": "./",
|
||||
"baseUrl": "..",
|
||||
"configFilePath": "../tsconfig.json"
|
||||
},
|
||||
"referencedMap": {},
|
||||
"exportedModulesMap": {},
|
||||
"semanticDiagnosticsPerFile": [
|
||||
"../node_modules/typescript/lib/lib.d.ts",
|
||||
"../node_modules/typescript/lib/lib.dom.d.ts",
|
||||
"../node_modules/typescript/lib/lib.es5.d.ts",
|
||||
"../node_modules/typescript/lib/lib.scripthost.d.ts",
|
||||
"../node_modules/typescript/lib/lib.webworker.importscripts.d.ts",
|
||||
"../src/index.ts"
|
||||
]
|
||||
},
|
||||
"version": "4.1.3"
|
||||
}
|
25
package-lock.json
generated
25
package-lock.json
generated
|
@ -1,9 +1,15 @@
|
|||
{
|
||||
"name": "@ringofstorms/dotenv",
|
||||
"version": "0.1.0",
|
||||
"name": "@ringofstorms/dotenv-multi",
|
||||
"version": "0.0.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@types/node": {
|
||||
"version": "14.14.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.14.tgz",
|
||||
"integrity": "sha512-UHnOPWVWV1z+VV8k6L1HhG7UbGBgIdghqF3l9Ny9ApPghbjICXkUJSd/b9gOgQfjM1r+37cipdw/HJ3F6ICEnQ==",
|
||||
"dev": true
|
||||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||
|
@ -26,6 +32,16 @@
|
|||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
|
||||
"dev": true
|
||||
},
|
||||
"dotenv": {
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
|
||||
"integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw=="
|
||||
},
|
||||
"dotenv-expand": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz",
|
||||
"integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA=="
|
||||
},
|
||||
"fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
|
@ -106,6 +122,11 @@
|
|||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
||||
"dev": true
|
||||
},
|
||||
"yn": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yn/-/yn-4.0.0.tgz",
|
||||
"integrity": "sha512-huWiiCS4TxKc4SfgmTwW1K7JmXPPAmuXWYy4j9qjQo4+27Kni8mGhAAi1cloRWmBe2EqcLgt3IGqQoRL/MtPgg=="
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
21
package.json
21
package.json
|
@ -1,21 +1,26 @@
|
|||
{
|
||||
"name": "@ringofstorms/dotenv",
|
||||
"name": "@ringofstorms/dotenv-multi",
|
||||
"version": "0.1.0",
|
||||
"description": "Dot environment file loader that acts like Create React App's supporting many files with per NODE_ENV/local settings.",
|
||||
"main": "index.js",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"scripts": {
|
||||
"prebuild": "npm run clean",
|
||||
"build": "tsc",
|
||||
"clean": "rimraf dist",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
"clean": "rimraf lib *.tgz"
|
||||
},
|
||||
"author": "",
|
||||
"author": "Josh (RingOfStorms)",
|
||||
"license": "ISC",
|
||||
"peerDependencies": {
|
||||
"dotenv": "^8.x",
|
||||
"dotenv-expand": "^5.x"
|
||||
"dependencies": {
|
||||
"dotenv": "^8.2.0",
|
||||
"dotenv-expand": "^5.1.0",
|
||||
"yn": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^14.14.14",
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "^4.1.3"
|
||||
}
|
||||
|
|
71
src/index.ts
71
src/index.ts
|
@ -1,4 +1,69 @@
|
|||
export function config(): Record<string, string> {
|
||||
console.log("TEST config");
|
||||
return { test: 'test' };
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
import * as dotenv from 'dotenv';
|
||||
import * as dotenvExpand from 'dotenv-expand';
|
||||
import * as yn from 'yn';
|
||||
|
||||
export interface ConfigOptions {
|
||||
convertToBooleanPredicate?: (variable: string) => boolean;
|
||||
convertToBoolean?: string | string[];
|
||||
debug?: boolean;
|
||||
}
|
||||
|
||||
export function config(options: ConfigOptions = {}): void {
|
||||
const log = options.debug ? console.log : (() => {});
|
||||
|
||||
// Same logic as create-react-app for resolving env files
|
||||
// https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/config/env.js
|
||||
const NODE_ENV = (process.env.NODE_ENV || 'unknown').toLowerCase();
|
||||
const appDirectory = fs.realpathSync(process.cwd());
|
||||
const dotenvFilePath: string = path.resolve(appDirectory, '.env');
|
||||
|
||||
const dotenvFiles = [
|
||||
`${ dotenvFilePath }.${ NODE_ENV }.local`,
|
||||
`${ dotenvFilePath }.${ NODE_ENV }`,
|
||||
NODE_ENV !== 'test' && `${ dotenvFilePath }.local`,
|
||||
dotenvFilePath,
|
||||
].filter(i => i) as string[]; // this cast is safe due to the identity filter
|
||||
|
||||
log('Environment files to check:', dotenvFiles.join());
|
||||
|
||||
const propsConfigured = {};
|
||||
dotenvFiles.forEach((dotenvFile) => {
|
||||
if (fs.existsSync(dotenvFile)) {
|
||||
const {parsed} = dotenvExpand(dotenv.config({path: dotenvFile, debug: options.debug || undefined }));
|
||||
Object.assign(propsConfigured, parsed);
|
||||
}
|
||||
});
|
||||
|
||||
log('Environment variables loaded from dotenvs:', Object.keys(propsConfigured).length);
|
||||
log('\t', propsConfigured);
|
||||
|
||||
const runBoolConverter: boolean = (options.convertToBooleanPredicate || options.convertToBoolean);
|
||||
log('Environment variable boolean converter will run:', runBoolConverter());
|
||||
if (runBoolConverter) {
|
||||
const convertPredicate = (key: string): boolean => {
|
||||
if (key) {
|
||||
if (Array.isArray(options.convertToBoolean)) {
|
||||
if (options.convertToBoolean.includes(key)) {
|
||||
return true;
|
||||
}
|
||||
} else if (options.convertToBoolean === key) {
|
||||
return true;
|
||||
}
|
||||
if (typeof options.convertToBooleanPredicate === 'function' && options.convertToBooleanPredicate(key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
Object.entries(process.env).forEach(([key, value]) => {
|
||||
if (convertPredicate(key)) {
|
||||
const boolValue = yn(value) ? 'true' : '';
|
||||
process.env[key] = boolValue;
|
||||
log('Environment variable converted into string boolean value:', key, "original:", value, 'newValue:', boolValue);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,16 @@
|
|||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"exclude": ["node_modules", "test", "dist", "**/*spec.ts", "**/*test.ts"]
|
||||
}
|
||||
"include": ["src"],
|
||||
"exclude": [
|
||||
".github",
|
||||
"examples",
|
||||
"lib",
|
||||
"node_modules",
|
||||
"output",
|
||||
"test",
|
||||
"**/__mocks__/**",
|
||||
"**/__tests__/**",
|
||||
"**/*spec.ts",
|
||||
"**/*test.ts"
|
||||
]
|
||||
}
|
|
@ -8,10 +8,9 @@
|
|||
"removeComments": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"sourceMap": true,
|
||||
"incremental": true,
|
||||
"outDir": "./dist",
|
||||
"outDir": "./lib",
|
||||
"baseUrl": "./"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue