Skip to content

Instantly share code, notes, and snippets.

@MilosPaunovic
Last active March 22, 2024 11:43
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save MilosPaunovic/1da784b83466197196b4b0fd6448c0b1 to your computer and use it in GitHub Desktop.
Save MilosPaunovic/1da784b83466197196b4b0fd6448c0b1 to your computer and use it in GitHub Desktop.

Multiple environments

This document contains an explanation of how you can create and maintain multiple environments for your Quasar projects. It will be an expansion of the official documentation located here for Webpack and here for Vite. Bear in mind that this guide is applicable to both versions of Quasar.

1. step

Create a variables folder in the project root, with a parser.js file inside. This will allow you to have all environment related files in a single place, which will improve readability.

2. step

Set the contents of newly created parser.js file to be the following:

const dotenv = require('dotenv');

const files = {
  ...dotenv.config({ path: 'variables/.env' }).parsed,
  ...dotenv.config({ path: `variables/.env.${process.env.ENVIRONMENT}` }).parsed,
};

module.exports = () => {
  Object.keys(files, (key) => {
    if (typeof files[key] !== 'string') {
      files[key] = JSON.stringify(files[key]);
    }
  });
  return files;
};

As you can see, parser requires dotenv package, so the npm i dotenv command needs to be ran for it to work properly.

3. step

You could create multiple environment files in the variables folder, like .env.development, .env.testing, .env.staging, .env.production or whatever you need for the particular project. The .env file is the one you should use for all of the common variables. It's always a good practice to create a separate .env.example file which will contain the list of all the variables expected in the other files for application to run properly.

Below is the default content of the files I use to start almost all of the projects with. I use comments as well, just as a precaution for new developers to be aware of what each variable does.

# Variable which separates environments
ENVIRONMENT =

# Sentry DSN tells the SDK where to send the events to
SENTRY_DSN =

# Base URL to which all API endpoints will be forwarded
BASE_URL =

4. step

In the quasar.config.js file you need to import the parser and set env property of the build attribute to it:

const PARSER = require('./variables/parser')();

build: {
  env: PARSER
}

5. step

In your .gitignore file add the following lines to exclude all sensitive files from ending up on source control, except the .env.example one.

# Exclude all environment files except example one
.env*
!.env.example

6. step

What is left is to create custom scripts for all of the environments, so in your package.json file, under scripts, you should add scripts like this for every required environment:

  "dev:local": "cross-env ENVIRONMENT=local quasar dev",
  "build:local": "cross-env ENVIRONMENT=local quasar build --debug",

  "dev:production": "cross-env ENVIRONMENT=production quasar dev",
  "build:production": "cross-env ENVIRONMENT=production quasar build",

If you often switch workstations and OS types, I suggest that you install cross-env package which will save you a lot of time. So, running the command npm i cross-env should be done, as well.

Now you have successfully implemented a sturdy base for creating multiple environments in your Quasar applications.

@BenJackGill
Copy link

This looks interesting but this part won't work because Object.keys only takes one argument:

module.exports = () => {
  Object.keys(files, (key) => {
    if (typeof files[key] !== 'string') {
      files[key] = JSON.stringify(files[key]);
    }
  });
  return files;
};

Instead you can use this:

module.exports = () => {
  for (const [key, value] of Object.entries(files)) {
    if (typeof value !== 'string') {
      files[key] = JSON.stringify(files[key]);
    }
  }
  return files;
};

@MilosPaunovic
Copy link
Author

Try to run something like this in the browser console:

Object.keys({1: 1, 2: 2}, (key) => {
  if (typeof files[key] !== 'string') {
    files[key] = JSON.stringify(files[key]);
  }
});

And you'll see the result will be what is expected, array of strings as keys.

@BenJackGill
Copy link

BenJackGill commented Mar 8, 2023

You are correct, your version does work, although I'm not sure why because the MDN docs say Object.keys() only takes one argument.

@Mmontsheng
Copy link

Mmontsheng commented Mar 19, 2024

Support for overriding with CI/CD tools.
This will read from system variables

However, it will require variables to be prefixed with QUASAR so we don't parse all vars.
parser.js

const dotenv = require('dotenv');

const { env } = process;

const systemEnvs = {};

Object.keys(env).forEach((key) => {
  if (key.startsWith('QUASAR')) {
    systemEnvs[key] = env[key];
  }
});
const files = {
  ...dotenv.config({ path: '.env' }).parsed,
  ...dotenv.config({ path: `.env.${process.env.ENVIRONMENT}` }).parsed,
  ...systemEnvs,
};
module.exports = () => {
  Object.keys(files, (key) => {
    if (typeof files[key] !== 'string') {
      files[key] = JSON.stringify(files[key]);
    }
  });
  return files;
};

@mzorzella-simeon
Copy link

Thank you very much for sharing this @MilosPaunovic. This saved me a lot of time and works very well!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment