Dynamic Vue.js configuration
2021-10-27You are building a web application and want to easily swap an API endpoint URL, set API tokens or just don’t want to trigger a build pipeline for changing that one string - you need dynamic configuration.
Let’s get right to it. Here are three ways of doing dynamic configuration using Vue.js.
HTML data-* attributes
Utilise HTML data-attributes to pass configuration values to your Vue app.
<div id="app"
data-some-api-key="ey.cafebabe"
data-base-url="http://example.org"></div>
Within your main.js you are able to access these values via document.querySelector("#app").dataset.someApiKey;. All
data attribute values are contained as camel cased properties of the dataset property.
From there you are able to pass these values to your main component, pass them to your Vuex store or do whatever else these values are intended for.
const dataset = document.querySelector("#app").dataset;
new Vue({
render: h => h(App),
store: createStore(dataset.baseUrl, dataset.someApiKey),
}).$mount('#app')
When to use this approach?
This kind of configuration is easy to understand for non-tech people. Imagine creating something like the Google tracking code: You would distribute your app by instructing people to paste the HTML snippet above, accompanied by a script tag and tell them to insert their site identifier and customer token. People like it, if they understand and do stuff by themselves!
Also, this approach is useful, if a backend templating engine is serving the HTML in which the Vue app is included. In that case you can use the configuration mechanism of your backend framework to configure the frontend application.
When running in a Docker Container, the same mechanism can be utilised through an entrypoint script that reads environment variables and inserts them in the HTML data attributes.
config.js
Start by creating a config file like below. Store it as public/config.js so it is not included in your Webpack build
and served as a static file.
const config = (() => {
return {
someApiKey: "ey.cafebabe",
baseUrl: "http://example.org"
};
})();
Include the config through a script tag.
<!DOCTYPE html>
<html lang="">
...
<body>
...
<div id="app"></div>
<script src="<%= BASE_URL %>config.js"></script>
<!-- built files will be auto injected -->
</body>
</html>
When reading the config values, make sure to define a default value as there is no guarantee that the config.js will
be loaded in all circumstances.
let value = process.env.VUE_APP_SOME_API_KEY;
// eslint-disable-next-line no-undef
if (typeof config != "undefined") {
// eslint-disable-next-line no-undef
value = config.someApiKey;
}
When to use this approach?
Use this approach, if you want to provide the configuration in a file external of the application. You would be able to
change the config.js on your web server, provide it via deployment tools or generate it from environment variables in
a container entrypoint script.
Remote config(.js)
This one is similar to the previous case, where the config.js is distributed alongside the application. Instead of
placing the file on the same web server as the application, you call an external location, where the config resides.
I am feeling almost stupid to include this approach, but there are some differences in the usage. For one, you have to be careful about security. Make sure that only trusted parties are able to change the config and no one is providing a malicious config to you. For another, you are able to use external config systems like Spring Cloud Config, Consul, etc. In these cases you would most likely process some structured data format like JSON though.
When to use this approach?
Use this approach, if you have a configuration management system in place and want to use it for the frontend application, too.
Also, this approach might prove useful, if there are some restrictions on the deployment itself. Maybe you are not able to change environment variables, the HTML or trigger a new deployment? This approach is for you.
Do you really need dynamic runtime configuration?
Before implementing the runtime configuration think twice: is the added complexity really worth the configuration need?
Can your configuration needs be dealt with via .env files? That would make things way easier. Put your development
configuration values into .env your production ones in .env.production and let your build and distribution process
take care of the configuration.
If this suffices, go that direction! It is straight forward, everyone knows how to find the values and everything stays predictable.
© 2021 Dennis Stritzke
Code samples are public domain unless otherwise noted.