loading...
Cover image for build your own deno-dotenv module

build your own deno-dotenv module

am77 profile image Vincent Mancini ・5 min read

Hello DEV,

​ In the last post we have seen how we can create a REST API using Deno with oak.


Here is the post Simple REST API with Deno if you want to take a look at it.


​ Today we are going to build a deno-dotenv module inspired from the node dotenv module

What is the node dotenv module ?

​ Dotenv is a zero-dependency module that loads environment variables from a .env file into process.env. Storing configuration in the environment separate from code is based on The Twelve-Factor App methodology.

for more information: check it's page on npm and it's repository on github.

what is a .env file ?

.env is the file that contains the environment variables you want to load to your application, each line of the .env file has this format KEY=VALUE

example:

HOST=https://www.example.com
PORT=7700
KEY=J46Sq8r4s5d9

​ With that out of the way, let's get started by defining the steps to create this module:

The main steps

​ These are the main steps to build this module:

  1. Read the content from the .env.
  2. Parse the environment variables from the content.
  3. Set environment variables in Deno.env.

1. Read the content from the .env:

​ Let's start by creating the mod.ts file and add this function to it

const readFileToStrSync = (filePath: string): string => {
    const bytes = Deno.readFileSync(filePath)
    const fileContent = new TextDecoder("utf-8").decode(bytes)
    return fileContent
}

NOTE: You can name the file however you want, but as a best practice we are going to stick to mod.ts

​ What does this function do is:

​ Now that we have the .env file content let's parse the environment variables in it.

2. Parse the environment variables:

​ To do that let's add the parse function to the mod.ts file

const LINE_BREAK: RegExp = /\r\n?|\n/

const parse = (envContent: string): string[][] => {
    const envList = envContent.split(LINE_BREAK)
    let parsedContent: string[][] = []
    for ( let i = 0; i < envList.length; i++) {
        parsedContent.push(envList[i].split("="))
    }
    return parsedContent
}

​ what does this code do is:

  • The LINE_BREAK is a regular expression that matches the line break.
  • The parse function takes the content of the .env file as a parameter of type string ( the string returned from the previous function readFileStrSync ), split the content into separate lines ( because each line contain one environment variable with the structure KEY=VALUE ) using the split function with LINE_BREAK RegExp as a parameter, then loop throw all the lines and retrieve the KEY and the VALUE in a form of an array of strings [KEY, VALUE] and push it to the two-dimensional array parsedContent which will be returned when the loop is completed.

​ Now we have the environment variables in a form of a two-dimensional array, all we have left to do is to set it to the Deno.env so it will be accessible in all the application.

3. Set the environment variables in Deno.env:

​ Now, let's add the setEnv function to the mod.ts file

const setEnv = (parsedEnv: string[][]): void => {
  for (let i = 0; i < parsedEnv.length; i++) {
    Deno.env.set(parsedEnv[i][0], parsedEnv[i][1])
  }
}

​ This function takes the environment variables in a form of a two-dimensional array ( returned from the parse function ) and add them to the Deno.env object with the Deno.env.set() function.

​ Now we have all the functions we need created, but they are not doing anything yet, they have to collaborate with each other to provide the functionality we are looking for. So let's just create a function to do that let's give a name of dotenv

const dotenv = (envFilePath?:string) => {
  const filePath: string = envFilePath || ".env"
  const fileContent = readFileToStrSync(filePath)
  const parsedEnv = parse(fileContent)
  setEnv(parsedEnv)
}

​ This function take an optional parameter envFilePath which is the path to the .env file ( if it's provided the function will use it, if not the function will use '.env' as a path value ), then using this path filePath to read the content of the .env file synchronously using the readFileToStrSync(filePath), then parse the result using the parse(fileContent) function, then uses the parsed result in the setEnv(parsedEnv) function to set the environment variables in the Deno.env object.

4. Finally export

​ Now that we have the functionality create and ready, we need just to export the dotenv function so the users can use it in their apps.

export default dotenv

# Let's test the module

​ First create a .env file and add some KEY=VALUE pairs, something like:

PASSWORD=1234567
KEY=12T1S654Ts6sc5fsd4Q6np9dx2A

​ Then create a typescript file, call it test.ts or however you want, import the dotenv function from the dotenv module we just created, and execute it, so that the environment variables will be available to use from the Deno.env object

import dotenv from "./mod.ts"
// or you can use import  if from this URL
// import dotenv from "https://raw.githubusercontent.com/AM-77/deno-dotenv/master/mod.ts"
dotenv()

now create a snapshot of the environment variables from the Deno.env using the Deno.env.toObject() function and just use it:

const env = Deno.env.toObject()
console.log("PASSWORD: ", env.PASSWORD)
console.log("KEY: ", env.KEY)

Run your test.tsusing the flags --allow-read --allow-env

$ deno run --allow-read --allow-env test.ts
PASSWORD: 1234567
KEY: 12T1S654Ts6sc5fsd4Q6np9dx2A

And that's all, we are finished. Thank you.

Here is the source code (I re-factored it a little bit).

Posted on by:

am77 profile

Vincent Mancini

@am77

Software engineer, Javascript lover & blockchain enthusiast.

Discussion

pic
Editor guide