How to use .env file in JavaScript applications with webpack
Giuseppe
Posted on April 24, 2020
It's been awhile I haven't written a post on the blog and, since I must #StayAtHome due to the COVID-19 Pandemic, I would like to write about an interesting topic.
Table of Contents
Introduction
As you have already read from the title, I'm going to show you how it's possible to read env variables from a .env file in a JavaScript application.
I guess, at this point, that many of you are asking themselves:
"WTF?! Why should I put variables in a file?! It would be better to use them inside the code!"
Well, usually an application could have different variables based on the environment. For instance: on development, staging and production it could have different URLs, different API keys, different users and so on...
So, to do that, you just need to create a .env file in the root of your project, define your variables and read them in your JavaScript code, especially to avoid to change the source code everytime you need to have different configuration.
N.B. This must be done for each environment, meaning that .env files mustn't be committed!
A real example
Let's try to create a simple front end application reading environment variables from a .env file.
npm init
First of all, we need to create the package.json file by running:
npm init
N.B. I'm going to call my app "webpack-env", but you can choose whatever you want: it doesn't matter.
webpack, babel and dotenv
Now we need to install webpack to build our application, babel-loader to compile .js files and dotenv to read and parse the .env file.
npm install webpack webpack-cli @babel/core babel-loader dotenv --save-dev
If you have done everything correct, you should have a package.json like this one:
{
"name": "webpack-env",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.9.0",
"babel-loader": "^8.1.0",
"dotenv": "^8.2.0",
"http-server": "^0.12.1",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.11"
}
}
You can copy it and run npm install
to avoid all the previous steps.
Project structure
At this point we can start crafting our project.
If every worked correctly, you should have two files:
- package.json (created by running
npm init
) - package-lock.json (created by running
npm install
)
Let's go deeper creating something else.
webpack.config.js
This is the webpack's configuration file. Just use the following configuration:
const path = require("path");
const webpack = require('webpack');
const dotenv = require('dotenv').config( {
path: path.join(__dirname, '.env')
} );
module.exports = {
entry: "./src/app.js",
output: {
path: path.resolve(__dirname, "public"),
filename: "app.js",
},
module: {
rules: [
{
test: /\.js?$/,
exclude: /(node_modules)/,
include: path.resolve(__dirname, "src"),
use: {
loader: "babel-loader"
}
},
]
},
plugins: [
new webpack.DefinePlugin( {
"process.env": dotenv.parsed
} ),
],
};
Let's see what we have just written.
const dotenv = require('dotenv').config( {
path: path.join(__dirname, '.env')
} );
We use dotenv library to read the .env file from the root of the project.
plugins: [
new webpack.DefinePlugin( {
"process.env": dotenv.parsed
} ),
],
By using the webpack.DefinePlugin
, we parse and inject the whole .env file's content which is converted into a JavaScript object and assigned to the "process.env"
variable.
From now on, we can use "process.env"
object inside our application.
.env file
Now it's time to add our .env file.
Let's create it in the root of the application with the following variables:
- APP_TITLE = "My application title"
- APP_BASE_URL = "https://foobar.test"
- APP_API_USER = "amazing_webpack"
- APP_ENV = "production"
- APP_TIMEZONE = "Europe/Rome"
src/app.js
This is the source code which will be compiled by webpack:
// `process.env` is the one defined in the webpack's DefinePlugin
const envVariables = process.env;
// Read vars from envVariables object
const {
APP_TITLE,
APP_BASE_URL,
APP_API_USER,
APP_ENV,
APP_TIMEZONE
} = envVariables;
/**
* @const _getRowString
* @description Concatenate `description` and `envVar` for creating a row text.
* @param description
* @param envVar
*
* @returns {string}
*/
const _getRowString = (description, envVar) => {
return `<p>${description}: <strong>${envVar}</strong></p>`;
}
// Append rows to `.env-vars` class
document.querySelector('.env-vars').innerHTML = `
${_getRowString('App title', APP_TITLE)}
${_getRowString('Current environment', APP_ENV)}
${_getRowString('API user', APP_API_USER)}
${_getRowString('Base URL', APP_BASE_URL)}
${_getRowString('Timezone', APP_TIMEZONE)}
`;
// Expose envVariables to the window object
window.envVariables = envVariables;
As defined in webpack.config.js, the final bundle will be put inside the public/ folder => public/app.js.
public/index.html
This file is meant be our app's entry point. It's just a simple HTML file:
<html>
<head>
<title>webpack env</title>
</head>
<body>
<h1>Just some env variables read from a .env file!</h1>
<div class="env-vars"></div>
<script src="app.js"></script>
</body>
</html>
If everything went good, this should be the final structure:
Build and serve the app
Now it's time to compile and serve our application.
First of all we need to install a server to serve our app.
We're going to use http-server.
Let's install it:
npm install http-server --save-dev
Once we have installed it, let's define two npm scripts:
-
npm run build
(to build the app) -
npm run serve
(to serve the app)
We can do it by adding two scripts in the package.json scripts object.
Let's replace the whole scripts object with the following one:
"scripts": {
"build": "webpack --mode=production",
"serve": "./node_modules/.bin/http-server"
},
N.B. Since we don't need to run unit tests, we can remove the test
scripts.
Now it's possible to compile the app and serve it by running:
npm run build && npm run serve
In your console, you should see something like this:
If everything went good, we should see our application working; just open the url provided by http-server.
Conclusion
As you can easily understand, this approach allows you to use variables based on the environment without changing your harcoded variables each time.
You just need to set your env vars, build the app and... that's all!
Follow me on
If you liked the post, you might offer me a ☕️ on PayPal. 🙂
Posted on April 24, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.