Using DefinePlugin to Define API URLs in Webpack
Tags: webpack, node, javascript, webdev
Published: 2020-04-18 17:22:24

In today's development cycle, there are multiple environments for any API. For example, the dev API is available at `dev.domain.com` and production API is available at `prod.domain.com`. 
While writing a front end library or a front end modern JavaScript application that consumes the API we use webpack to build our applications. For each environment (dev or prod) we write a different `npm script` to build application for that environment.
`package.json`
```json
... any other configuration
"scripts": {
    "dev": "webpack --env=dev --mode=development",
    "prod": "webpack --env=prod --mode=development"
  },
...rest of file
``` 

Now let's say our code consumes an API `${env}.domain.com` where env can be either dev or prod or any other environment that our API is available at.

`JavaScript Code`
```javascript 
 // this code gets some data from the api
let url = `http://dev.domain.com`
fetch(url)
  .then(response => response.json())
  .then(res => console.log(res))
```
 

### So how do we make the fetch to make a request to `prod.domain.com` instead of `dev.domain.com` when we build our application for production??

We will use a webpack plugin called `DefinePlugin` to achieve this.
So let's write our webpack configuration and then we will modify the JavaScript Code above to work in different environments.

`webpack.config.js`
```javascript
const path = require('path'
const webpack = require('webpack')
/* we are creating our webpack configure as a function that takes env 
as parameter which is passed from npm scripts and can be dev or prod 
as defined in npm scripts
*/
module.exports = (env) => {
 const envConfig = {}
  switch(env) {
    case 'dev': 
      envConfig.domain: 'http://dev.domain.com'
    case 'prod'
      envConfig.domain: 'http://prod.domain.com'
  }

  return {
    entry: path.resolve(__dirname, './src/index.js')
    output: {
      path: path.resolve(__dirname, 'dist')
      filename: 'bundle.js'
    },
    plugins: [
      new DefinePlugin({
        API_DOMAIN: JSON.stringify(envConfig.domain)
      })
   ]
  }
}
```
##### Let's see what we just did in our webpack configuration
We just created our webpack configuration and inside it an object `envConfig` that contains a domain property on it. Depending upon what's the value of `env`, the value of domain will vary. 
Then we used DefinePlugin to define a `API_DOMAIN` constant. Now in our code this `API_DOMAIN` can be used and we do not have to worry about the `url` that we used in our JavaScript code.

`Modified JavaScript Code`
```javascript
  let url = API_DOMAIN
  fetch(url)
  .then(response => response.json())
  .then(res => console.log(res))
```

PS: I have added `switch` statement in the webpack file itself for clarity. You can add the logic in a separate file and then import it in the webpack configuration.

That's how we can use webpack to handle the API domains for us based on the environment we are building our code for. Similarly we can have any other constants configured as well.

The GitHub repository for the code is available at [Webpack Manage Environment Domains](https://github.com/vyasriday/webpack-manage-environment-domains)