1

I'm building SPA with Vue and serve it with nodejs and wrapping it in docker container. Here is the problem, I'm trying to stick to 12 factor app where for configuration it says keep in env file.

VueJS provides configs for different environment in config folder. But, according to 12 factor app config should not be in files based on environment.

In a twelve-factor app, env vars are granular controls, each fully orthogonal to other env vars. They are never grouped together as “environments”, but instead are independently managed for each deploy.

So how can I access nodejs environment variables in VueJS app?

EDIT: Thanks for the answers. The whole idea is to change for example api url on run time trough providing different env variable. If I commit the config file with api url, I would have to rebuild the container on commit and deploy it just for this small change.

I could also have a api access key that is different in dev and prod.

I'm looking for the best way possible to do this kind of things in SPA.

Lord Zed
  • 750
  • 7
  • 28
  • I think you got those principles completely wrong. The intention is clearly stated: *Apps sometimes store config as constants in the code. This is a violation of twelve-factor, which requires strict separation of config from code. Config varies substantially across deploys, code does not.* So you **violate** 12 factor app principle #3 if you allow your app access to environment variables. – connexo Feb 07 '18 at 20:28
  • 2
    Ummm, it clearly says in principle 3 `The twelve-factor app stores config in environment variables (often shortened to env vars or env).` – tehbeardedone Feb 07 '18 at 20:31
  • Yes, as part of the build process, not as part of the application itself. – connexo Feb 07 '18 at 20:37
  • I've updated question and tried to explain what I am trying to accomplish. – Lord Zed Feb 07 '18 at 20:53
  • Are you using a dockerfile to build the container? Checkout the answer here for how to do it on build https://stackoverflow.com/questions/19537645/get-environment-variable-value-in-dockerfile – tehbeardedone Feb 07 '18 at 21:05
  • @tehbeardedone this looks interesting. will try this. – Lord Zed Feb 07 '18 at 22:28
  • No not as part of the build process. As part of the *deploy* process. VueJS env.local / env.production / env.staging /etc is not compatible with that, and its kind of unfortunate that the binding at build time thing is baked in to the tool. This is though somewhat of a problem with JS running on the browser, but hey, thats why we are coders. – Shayne Jul 19 '22 at 08:25

3 Answers3

2

SPA applications nowadays usually go through a build step. This means compiling all of your files into [near to] one dist file and an index.html which may be served statically. This creates a clear separation between front-end (VueJS) and backend (NodeJS). The index.html and js files themselves continue to be static files nonetheless.

This is usually what you want since you can scale server and client independently: Serve static files, say, through s3 + cdn and run your nodejs server independently.

I think what you want is a way to pass runtime configuration to the client. I wouldn't get too caught up on the details of actually sharing the envvars per se.

In your case, I see two possible solutions:

1) Implement an API to access whitelisted envvars from your server - You can think of this as a /config endpoint

2) Render the index.html dynamically via nodejs with something like ejs with the prepopulated envvars - You'll have more coupling between frontend and server but you could extend this to much more than envvars and, say, preopolute the frontend with prefetched data.

Regardless on how you do it, you can consider this runtime configuration for the frontend which should not be attempted to be fixed at build time since otherwise you may be expose sensitive data into static files and it is not always guaranteed that you have all the data at this time.

Maroshii
  • 3,937
  • 4
  • 23
  • 29
  • I'm using Azure and Web Apps for Containers. Also I'm utilizing visual studio online build and release pipeline to build static files (index.html, js and css) and then using `Dockerfile` build container. Accessing api config on some other endpoint is not a good practice and it adds to complexity. If I could pass variables to `Docker` `env`, how can I make that available to `VueJS` app within `Docker` ran by `nodejs`? – Lord Zed Feb 07 '18 at 22:30
  • You can't. Docker env is passed as runtime configuration which at this point is useless since you already built your static files. – Maroshii Feb 07 '18 at 22:45
  • Also, I would argue that having a `/config` endpoint doesn't add complexity and is not a bad practice. You don't need less than what you actually need to solve the problem. How would you inject runtime configuration into,say, an iOS app? This is a similar problem since the frontend and backend are completely decoupled and from what I understand about your build system static files are already built – Maroshii Feb 07 '18 at 22:48
  • What about during the dockerfile build? – Lord Zed Feb 07 '18 at 23:12
  • You don't have access to `env` during docker build. You could use `--build-arg` and the `ARG` instruction in the dockerfile but again, you would have to re-build the image every time you make a change since you'd be imprinting the values in the static files. – Maroshii Feb 07 '18 at 23:29
  • @Maroshii Do we compile dist files locally or push build folder to server and have server compile into dist files? – redshift Jun 14 '18 at 14:43
  • @redshift it depends on your setup. Normally your CI/CD system would take care of that. Always worth mentioning.... your dist files shouldn't be tracked by git. – Maroshii Jul 05 '18 at 03:34
0

The way you access the env variables should be the same no matter which OS you are using. The way you set them is different though. On windows I would set an environment variable like so

set PASSWORD=somepassword

And then in the code I can access this variable by doing the following

var pw = process.env.PASSWORD;

You should be able to use this the same way in VueJS.

EDIT:

If you use docker-compose you can set the endpoint on the fly by using environment variables too. Then whenever you docker-compose up the endpoint will be updated with the current value of your environment variable. In your shell update the api endpoint to whatever you want it to be.

set API_URL=http://my-api-endpoint

Then in the docker-compose.yml you would access this value like so

version: '3'
services:
  app:
    image: 'myapp'
    environment: 
    - API_URL=${API_URL}

You would still access the variable in your code using process.env.API_URL as I mentioned in my example above.

tehbeardedone
  • 2,833
  • 1
  • 15
  • 23
  • No, you're not. The browser has no `process.env`. Aside from ***This is a violation of twelve-factor, which requires strict separation of config from code.*** – connexo Feb 07 '18 at 20:38
  • He asked how to access the node env variables. That is how you do it. No one said anything about the browser. Being that he specifically asked how to access the `node` environment variable you can assume he is asking how to do it using javascript. – tehbeardedone Feb 07 '18 at 20:41
  • OP also clearly states he's developing an SPA. Show me an SPA that does not require a browser. – connexo Feb 07 '18 at 20:42
  • Show me a SPA that doesn't have the majority of the code written in Javascript...which is clearly how he would need to access the environment variables. – tehbeardedone Feb 07 '18 at 20:43
  • Because you clearly missed the last question in his post `So how can I access nodejs environment variables in VueJS app?` The example I posted is how you would do it. – tehbeardedone Feb 07 '18 at 20:44
  • I'm using `Dockerfile`. Anyhow, how can I access `env` variable from `docker` in `VueJS` app? – Lord Zed Feb 07 '18 at 22:33
0

our devops team will use https://github.com/tinou98/vue-12factor However it's really a big question mark how VueJs does not consider that as a mature frontend/spa framework.

We used to build React Apps since more than 6 years with a built-in support of externalizing env.js file ( create-react-app )

Abdennour TOUMI
  • 87,526
  • 38
  • 249
  • 254