DEV Community

Khue Pham
Khue Pham Subscriber

Posted on

Environment File (.env) Checker and Syncer for ReactJS / NodeJS Project

This bash script provides functionality to check and sync environment files in your project.
Image description

Features

  1. Checks .env files against a template (.env.template)

  2. Identifies missing variables in .env files

  3. Offers to sync .env files with the template

  4. Skips syncing content for specified files

Usage

Source code in my Github repository here:
Check file here: misc/check_env_files.sh at main ยท khuepm/misc

  1. Place the script (check_env_files.sh) in your project root directory.

  2. Ensure you have a .env.template file with all required environment variables.

  3. Make the script executable:

    chmod +x checkenv.sh

    1. Run the script:

    ./checkenv.sh

    1. (optional) Add to package.json to check every start yarn

    {
    โ€ฆ
    scripts: {
    "prestart": "sh checkenv.sh",
    }
    }

What it does

  1. Checking Environment Files:
  • The script checks all .env* files in the current directory against .env.template.

  • It displays missing variables in each file.

  • A summary of errors (if any) is shown for each file.

2. Syncing Environment Files:

  • If errors are found, the script offers to sync .env files with .env.template.

  • If you choose to sync (by entering โ€˜yโ€™), the script will:

  • Comment out variables not present in the template

  • Add new variables from the template

  • keep existing variables: preserving the current value and adding a comment with the template value

Configuration

  • The script uses .env.template as the reference. Ensure this file contains all required variables for your project.

Note

After syncing, the script cleans the yarn cache. You may want to adjust or remove this step based on your project needs.

  • Comment out yarn cache clean

How do I created it?

1. Initial Setup:

#!/bin/bash

template=".env.template"

# Check if the template file exists
if [ ! -f "$template" ]; then
  echo "Error: $template not found"
  return 1
fi
Enter fullscreen mode Exit fullscreen mode

This section sets up the script and defines the template file. It also checks if the template file exists.

2. check_env_files() function:

# Use for later step, a flag to notice when we need to sync the .env
errors_found=false

check_env_files() {
  files_not_to_check=(".env.template")
  # Get all .env files in the current directory
  files_to_check=($(find . -maxdepth 1 -type f -name '.env*'))

  # Remove files that are in files_not_to_check
  for file in "${files_not_to_check[@]}"; do
    files_to_check=(${files_to_check[@]/$file})
  done

  # Remove any empty elements
  files_to_check=(${files_to_check[@]})

  # Get terminal height and width
  terminal_height=$(tput lines)
  terminal_width=$(tput cols)

  # Variables to store output and result
  output=""
  result=""

  # Function to update the screen, keep to notice text at the bottom of screen
  update_screen() {
    # Clear the screen
    tput clear

    # Print the output
    echo "$output"

    # Move cursor to the bottom and print the result
    tput cup $((terminal_height - 3)) 0
    printf '%*s\n' "$terminal_width" '' | tr ' ' '-'
    echo "$result"
    printf '%*s\n' "$terminal_width" '' | tr ' ' '-'

    # Move cursor back to the top
    tput cup 0 0
  }

  for file in "${files_to_check[@]}"; do
    if [ -f "$file" ]; then
      output+="\n"
      output+="Checking $file...\n\n"
      error_count=0
      while IFS= read -r line || [[ -n "$line" ]]; do
        key=$(echo "$line" | cut -d'=' -f1)
        if ! grep -q "^$key=" "$file"; then
          output+="\033[31m  ๐Ÿ’” Missing in $file: $key\033[0m\n"
          ((error_count++))
          errors_found=true
        fi
        update_screen
      done < "$template"

      # Update final result
      output+="\n\n==========================================\n"

      if [ $error_count -gt 0 ]; then
        result+="\n\033[31mโŒ Done checking $file with $error_count error(s)\033[0m\n"
        output+="$result"
      else
        result+="\n\033[32mโœ… Done checking $file with no errors\033[0m\n"
        output+="$result"
      fi

      update_screen
      output+="\n"

      # Add a small delay to make the result visible at first check
      # Remove if you want to see the result immediately
      if [ "$file" = "${files_to_check[0]}" ]; then
        sleep 1
      fi

    else
      #output+="\033[33m๐ŸŸ  Check $file: $file not found, skipping\033[0m\n"
      #result+="\033[33mโš ๏ธ $file not found, skipping\033[0m\n"
      update_screen
    fi

  done

  # Clear the result at the end
  result=""
  update_screen

  # Reset terminal settings
  tput rmcup  # Exit alternate screen buffer
  tput cnorm  # Show cursor
  tput sgr0   # Reset all attributes

  # Clear the screen and move cursor to top-left
  clear
  tput cup 0 0

  # Display final output
  echo "$output"
}
Enter fullscreen mode Exit fullscreen mode

This function is responsible for checking .env files against the template. It does the following:

  • Finds all .env files in the current directory

  • Removes files that should not be checked

  • Sets up a dynamic terminal display

  • Checks each .env file against the template, highlighting missing keys

  • Updates the screen with progress and results

The problem when template has an empty line or a comment line, the checker will not work property. So I need to adjust it a little bit:

      ...
      while IFS= read -r line || [[ -n "$line" ]]; do
        # Skip empty lines and comment lines
        if [[ -z "$line" || "$line" =~ ^[[:space:]]*# ]]; then
          continue
        fi
      ...
Enter fullscreen mode Exit fullscreen mode

3. sync_env_files() function:

This function synchronizes .env files with the template. It:

  • Finds all .env files to sync

  • For each file:

  • Comments out lines not in the template

  • Updates existing keys with new values from the template

  • Adds new keys from the template

    sync_env_files() {
    # Get all .env files in the current directory
    files_to_sync=($(find . -maxdepth 1 -type f -name '.env*'))

    # Exclude .env.template from files to sync
    files_to_sync=(${files_to_sync[@]/$template})

    # Remove any empty elements
    files_to_sync=(${files_to_sync[@]})

    # Sync files
    for file in "${files_to_sync[@]}"; do
    if [ -f "$file" ]; then

      # Check if the file is in the list of files not to sync
    
      echo "Syncing $file with $template..."
    
      # Comment lines not in template
      while IFS= read -r line || [[ -n "$line" ]]; do
        if [[ $line =~ ^[[:space:]]*# || -z $line ]]; then
          continue  # Skip comments and empty lines
        fi
        key=$(echo "$line" | cut -d'=' -f1)
        if ! grep -q "^$key=" "$template"; then
          sed -i '' "s|^$key=.*|# $line # Not in template|" "$file"
          echo "\033[31m  Commented: $key (not in template)\033[0m"
        fi
      done < "$file"
    
      while IFS= read -r line || [[ -n "$line" ]]; do
        if [[ $line =~ ^[[:space:]]*# || -z $line ]]; then
          continue  # Skip comments and empty lines
        fi
        key=$(echo "$line" | cut -d'=' -f1)
        value=$(echo "$line" | cut -d'=' -f2-)
    
        if grep -q "^$key=" "$file"; then
          # Key exists, check if value is different
          current_value=$(grep "^$key=" "$file" | cut -d'=' -f2-)
          if [ "$current_value" != "$value" ]; then
            # Value is different, update it
            sed -i '' "/# $key=.*# Updated from template/d" "$file"
            sed -i '' "s|^$key=.*|# $key=$value # Updated from template\n$key=$current_value|" "$file"
            echo "\033[33m  Updated: $key\033[0m"
          else
            echo "  Skipped: $key (value unchanged)"
          fi
        else
          # Key doesn't exist, add it
          echo "$key=$value # Added from template" >> "$file"
          echo "\033[32m  Added: $key\033[0m"
        fi
    
      done < "$template"
    
      echo "Finished syncing $file"
      echo
    
    fi
    

    done
    }

4. Main execution flow:

# Call the function
check_env_files

if [ "$errors_found" = true ]; then
  # Ask user if they want to sync files
  # If yes, call sync_env_files()
    # After sync successfully, do clean the cache
  # If no, cancel the operation
else
  echo "No errors found in .env files. Sync not needed."
fi
Enter fullscreen mode Exit fullscreen mode

This section calls the check_env_files() function and then, based on whether errors were found, either prompts the user to sync the files or informs them that no sync is needed.

Key features of this script:

  • Dynamic terminal display for real-time progress updates

  • Color-coded output for easy reading (red for errors, green for success, yellow for warnings)

  • Careful handling of existing values in .env files during sync

  • Option to sync files only if errors are found

This script is useful for maintaining consistency across multiple .env files in a project, ensuring that all required environment variables are present and up-to-date.

ReactJS #ReactNative #.env #.env.template #uptodate-env-file

Top comments (0)