9

I've tried a few implementations which none have been successful.

First Attempt

Using eval in package.json script "fetch:data": "eval $(cat .env) ts-node -O '{\"module\":\"commonjs\"}' ./bin/build-api-data.ts".

This results in a JSON parsing error because eval is removing my quotes for some reason.

undefined:1
{module:commonjs}
 ^

SyntaxError: Unexpected token m in JSON at position 1

Second Attempt

Using dotenv, the problem I encountered here was it was a race condition resulting in errors like this:

$ CANDID_ENV=local ts-node -O '{"module":"commonjs"}' ./bin/build-api-data.ts

/Users/lassiter.gregg/code/candidco-web/node_modules/contentful/dist/webpack:/contentful/contentful.js:49
    throw new TypeError('Expected parameter accessToken')
          ^
TypeError: Expected parameter accessToken

Code Sample

import fs from 'fs';
import path from 'path';
import fetchApiData from '../lib/apiData';
import dotEnv from 'dotenv-safe';

const { CANDID_ENV } = process.env;

const isLocalBuild = CANDID_ENV === 'local';

console.log(dotEnv);

const API_DATA_FILENAME = 'api_data.json';

const ensureDirectoryExistence = filePath => {
  var dirname = path.dirname(filePath);
  if (fs.existsSync(dirname)) {
    return true;
  }
  ensureDirectoryExistence(dirname);
  fs.mkdirSync(dirname);
};

const writeData = (filename, data) => {
  const filePath = path.join(__dirname, '..', '.data', filename);
  ensureDirectoryExistence(filePath);
  fs.writeFileSync(filePath, JSON.stringify(data));

  console.log('API data stored', filePath);
};

const fetchAndStoreApiData = async () => {
  console.log('Fetching all API data');
  await dotEnv.config({
    path: isLocalBuild ? './.env' : `./.env.${CANDID_ENV}`,
  });

  const newData = await fetchApiData();
  writeData(API_DATA_FILENAME, newData);
};

const init = async () => {
  fetchAndStoreApiData();
};

if (require.main === module) {
  init();
}

In the case above, I've tried doing dotenv.config at the top of the file, in the init, in the function as you see. It always throws the same error about contentful not getting the env variable it needs. That said, if I log process.env and comment out the code relevant to fetchApiData then I see all my environment variables. That's why I think it's a race-time condition but haven't been able to find anything similar to my own issue.

Additionally, what makes this even more thorny is that this is a custom script that has to work in a node and esnext environment. So, I've had my fair share of thorny import/export issues using syntax I don't really prefer but haven't found away around it (e.g. export = someFunction).

jango
  • 133
  • 1
  • 1
  • 5
  • Note that `dotenv` does not load environment variables. Environment variables are already there, like every other application. `dotenv` fakes environment variables by parsing a file and placing the values in the same place real environment variables live. – Evert Jul 20 '23 at 21:26

3 Answers3

2

Do I see it correctly, that you are trying to configure dotenv with a variable that you initialize with an env variable? I don't think that's going to work out. Dotenv's work is to load the env variables to process.env. You have to config it as early as possible in your app.

More about it here: https://www.npmjs.com/package/dotenv

Skezo
  • 312
  • 2
  • 11
1

I encountered a similar issue and end up loading dotenv module with "require" flag:

> ts-node --help
...
-r, --require [path]            Require a node module before execution
...

So having a simple module for calling dotenv was enough:

// env-loader.ts
require("dotenv").config({ path: "../.env" });
ts-node -r ./env-loader.ts other-script.ts

So that .env or other environment variable sources can be loaded before executing the script.

CKK
  • 899
  • 8
  • 13
0

In fact, I was able to set the environment variables without having to manipulate any ts code. I had to:

npm install dotenv --save

After defining .env in the root of the project, I was able to simply invoke it like this:

npx ts-node -r dotenv/config ./src/run.ts

Thanks @CKK and @Skezo for helping above.

Mário Meyrelles
  • 1,594
  • 21
  • 26