Webpack 4 with Vue CLI 3.0 - Computed Environment Variables
Oct 16, 2018
Webpack 4 with Vue CLI 3.0

After over a year of development and extensive testing, Phase 2 recently launched a new software product for one of our clients. The product features a Ruby on Rails API and a web app built with Webpack , Vue , and Material Web Components. The main reason we chose this stack is efficiency. The Rails community practices convention over configuration , and provides a robust collection of battle-tested libraries. Vue and Webpack allow us to assemble modular components that can be easily reused, preventing large amounts of redundant code and greatly improving maintainability.

Once the product launched and customers began using the application, our team was afforded some time to address tech debt that had built up over the past year. One of our biggest priorities was upgrading from webpack 2 to webpack 4. Webpack 4 is faster and it transitions from having a monolithic configuration to what they're calling #0CJS (Zero-Config JS). In the end, we went from having sixteen configuration files to a single file: vue.config.js .

Vue recently launched their new Vue CLI 3.0 which goes hand in hand with webpack 4. Vue CLI 3.0 does an awesome job hiding nearly all framework specific configuration behind the curtains, and provides great documentation for any custom configuration. One common need is an environment variable that is available in the app code, for instance an API base URL. In our case this URL is dependent on environment and tenant, meaning we can't simply save it in a .env file like recommended . The documentation contains the following tip:

You can have computed env vars in your vue.config.js file.

Computing the API base URL is easy enough. We use something similar to the following code to do so:

switch(environment) {
  case 'development':
  case 'test':
    url = `http://${process.env.HOST_IP}:3000`
    break
  case 'staging':
    url = `https://api.staging.${process.env.NODE_TENANT}.DOMAIN.com`
    break
  case 'production':
    url = `https://api.${process.env.NODE_TENANT}.DOMAIN.com`
    break
  default:
    throw 'Unknown environment'
}

After searching the documentation further, we found that chaining allows one to tap into webpack's configuration rules and modify them, and Vue's inspect command enables verification of webpack's configuration. The inspect command is indispensable when customizing webpack 4 configuration with Vue. It allowed us to determine the exact webpack plugin to tap into and what options to set. We ended up with the following code to incorporate the API base URL:

chainWebpack: (config) => {
  config.plugin('define')
    .tap(([options, ...args]) => {
      const processEnv = Object.assign({}, options['process.env'])
      processEnv['VUE_APP_API_BASE_URL'] = JSON.stringify(url)

      return [
        Object.assign({}, options, {'process.env': processEnv}),
        ...args
      ]
    })
}

With this our app was able to continue clear communication with our API and we were able to shift focus from addressing tech debt to implementing Cypress end-to-end testing to guarantee that the app will always deliver a consistent and expected experience to our client and their customers.

Phil Reichelt, Phase 2 Developer
Phil Reichelt Author
I play keyboard for Phase 2 as a full stack developer, primarily working with Ruby and JavaScript for more than 6 years. Outside of work you can typically find me cooking and eating delicious foods with my fiancée, finding a balance between playing video games and working on personal software projects, and taking care of our clowder of cats.