Skip to content

Commit

Permalink
feat: Implement dead-simple dotenv for bootstrap
Browse files Browse the repository at this point in the history
  • Loading branch information
pan93412 committed Jul 10, 2023
1 parent 3620759 commit 6f95f53
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 5 deletions.
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
"author": "nondanee, 1715173329, pan93412",
"license": "LGPL-3.0-only",
"dependencies": {
"dotenv": "^16.3.1",
"node-windows": "^1.0.0-beta.8",
"pino": "6.14.0",
"pino-pretty": "^7.6.1"
Expand Down
9 changes: 6 additions & 3 deletions src/bootstrap/index.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
const dotenv = require('dotenv');
// @ts-check

const { loadDotenv } = require('../dotenv.js');
const devMessage = require('./message');

/**
* Start the main part.
*
* @param {string} mainEntry
* @returns {Promise<void>}
*/
function startApp(mainEntry) {
async function startApp(mainEntry) {
// Inject the `.env` file into the `process.env` object.
dotenv.config();
await loadDotenv();

if (process.env.DEVELOPMENT === 'true') {
console.warn(devMessage);
Expand Down
98 changes: 98 additions & 0 deletions src/dotenv.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/**
* A very simple dotenv implementation.
*/

//@ts-check

const fs = require('fs');
const readline = require('readline');
const path = require('path');

/**
* Parse .env file.
*
* @param {string} filePath
* @returns {Promise<Record<string, string>>}
*/
async function parseDotenv(filePath) {
const env = /**@type {Record<string, string>}*/ ({});
const rl = readline.createInterface({
input: fs.createReadStream(filePath),
crlfDelay: Infinity,
});

for await (const line of rl) {
if (line.startsWith('#')) continue;

const [key, value] = line.split('=', 2);
env[key.trimEnd()] = value.trimStart();
}

return env;
}

/**
* Find .env file.
*
* @returns {Promise<string|null>}
*/
async function findEnv() {
const cwd = process.cwd();
const envPath = path.join(cwd, '.env');

try {
await fs.promises.access(envPath, fs.constants.R_OK);
return envPath;
} catch (err) {
return null;
}
}

/**
* Inject environment variables into process.env.
*
* @param {Record<string, string>} env
* @returns {void}
*/
function injectEnv(env) {
// https://github.com/motdotla/dotenv/blob/aa03dcad1002027390dac1e8d96ac236274de354/lib/main.js#L277
for (const [key, value] of Object.entries(env)) {
// the priority of .env is lower than process.env
// due to Node.js 12, we don't use nullish coalescing operator
process.env[key] = process.env[key] == null ? value : process.env[key];
}

return;
}

/**
* A simple method for finding .env file and injecting
* environment variables into process.env.
*
* No exceptions will be raised – we have handled errors
* inside this code.
*
* @returns {Promise<void>}
*/
async function loadDotenv() {
const envPath = await findEnv();
if (envPath == null) {
return;
}

try {
const env = await parseDotenv(envPath);
injectEnv(env);
} catch (e) {
console.error(e);
}

return;
}

module.exports = {
loadDotenv,
injectEnv,
findEnv,
parseDotenv,
};
1 change: 0 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1206,7 +1206,6 @@ __metadata:
browserslist: ^4.21.9
core-js: ^3.31.1
cross-env: ^7.0.3
dotenv: ^16.3.1
jest: ^29.6.1
node-windows: ^1.0.0-beta.8
pino: 6.14.0
Expand Down

0 comments on commit 6f95f53

Please sign in to comment.