dotenv doesn't work in monorepo's packages folder

678 views Asked by At

I am using monorepo structure using yarn berry(3.6) workspace.

Since our API URLs are almost identical, we plan to create and use API EndPoints inside the packages.

However, in the process of using the API instance, I confirmed that the .env file did not work normally.

I would be grateful if you could tell me how to solve it.

The project that uses that axios instance module is the next.js project.

/packages/common-utils/http/core.ts

import axios, { AxiosInstance } from "axios";
import {config} from 'dotenv';
config()
console.log(process.env.BASE_URL);//undefined
const request: AxiosInstance = axios.create({
  baseURL: process.env.BASE_URL, //it is not working, undefined
  timeout: 2500,
  withCredentials: true,
  headers: {
    accept: "application/json"
  }
});
export default request;
services/next-app/src/pages/index.jsx

import { core } from "@common/common-utils";
...

Below is my project structure.

my-workspace/
  ├── packages/
  │    ├── common-utils/
  │    │    ├── http/
  │    │    │    └── core.ts 
  │    │    ├── index.js
  │    │    ├── package.json
  │    │    └── .env
  ├── services/
  │    ├── next-app/
  ├── package.json
  └── yarn.lock

The part I doubt is that when I import it from next.js, I feel like I can't find it when it's built in the process.

I'm wondering is there any other way to use .env??

Or do I have to go through a separate build process?

1

There are 1 answers

0
Ankur Sharma On

Looks like you are trying to load env vars in next js. Your code is not working because you are using dotenv incorrectly. Next js loads all env vars when server is started. You are trying to load them on client side. If you want to load your env files from another directory then you have two options.

Option 1

Add following line in next config:

// Using EJS
require('dotenv').config({ path: 'path/to/your/.env' })

// Using ES6
import { config } from 'dotenv';
config({ path: 'path/to/your/.env' });

Note that if you want to expose variables to the browser, you should prefix them with NEXT_PUBLIC_. These can be added to your custom .env file like so:

NEXT_PUBLIC_MY_VARIABLE=my_value

Option 2

You need to write a custom nextjs server file inside your root directory with name server.js and add following code

const { createServer } = require('http')
const { parse } = require('url')
const next = require('next')
const dotenv = require('dotenv')
dotenv.config({path: '../path-to-env-file'}) 
const dev = process.env.NODE_ENV !== 'production'
const hostname = 'localhost'
const port = 3000
// when using middleware `hostname` and `port` must be provided below
const app = next({ dev, hostname, port })
const handle = app.getRequestHandler()
 
app.prepare().then(() => {
  createServer(async (req, res) => {
    try {
      // Be sure to pass `true` as the second argument to `url.parse`.
      // This tells it to parse the query portion of the URL.
      const parsedUrl = parse(req.url, true)
      const { pathname, query } = parsedUrl
 
      if (pathname === '/a') {
        await app.render(req, res, '/a', query)
      } else if (pathname === '/b') {
        await app.render(req, res, '/b', query)
      } else {
        await handle(req, res, parsedUrl)
      }
    } catch (err) {
      console.error('Error occurred handling', req.url, err)
      res.statusCode = 500
      res.end('internal server error')
    }
  })
    .once('error', (err) => {
      console.error(err)
      process.exit(1)
    })
    .listen(port, () => {
      console.log(`> Ready on http://${hostname}:${port}`)
    })
})

In package.json, apply following changes

{
  "scripts": {
    // Replace
    "dev": "next dev"
    // with
   "dev": "node server.js"
  }
}