VueJS & Webpack: ENV var unaccessible from built project - docker

I'm working on an app with vuejs frontend and nodejs backend. My frontend makes API https requests to the backend. I've started my projet with vue-cli and webpack.
I need to get the backend API url from env variable (BACKEND_URL).
Since i'm using webpack, I added this line to config/prod.env.js :
module.exports = {
NODE_ENV: '"production"',
-> BACKEND_URL: JSON.stringify(process.env.BACKEND_URL)
}
It works flawlessly in dev mode using webpack-dev-server. I pass the env var throught docker-compose file:
environment:
- BACKEND_URL=https://whatever:3000
But when I run build, I use nginx to serve the static files (but the problem is the same using visual studio code live server extension). I send BACKEND_URL env var the same way as before. The thing is now the process.env.BACKEND_URL is undefined in the app (but defined in the container)!! So I cant make backend http calls :(
I'm struggling finding the problem, please don't be rude with the responses. Thank you

They aren not "translated" during build time, this is what is happening with you. On a node environment, when you ask for process.env it will show all environment variables available in the system, that is true. But a web application does not have access to process.env when it is executing. You need a way to translate them during build time.
To achieve that you have to use DefinePlugin. It translates anything during build time and writes a magical string where this other thing was.
Using you own example:
module.exports = {
NODE_ENV: '"production"',
BACKEND_URL: JSON.stringify(process.env.BACKEND_URL)
}
If you do this during build time, without DefinePlugin, webpack won't know what to do with it, and it is going to be a simple string.
If you use DefinePlugin:
new webpack.DefinePlugin({
"process.env.BACKEND_URL": JSON.stringify(process.env.BACKEND_URL)
});
By doing this, you are allowing webpack to translate this during build time.

Give this a shot: https://www.brandonbarnett.io/blog/2018/05/accessing-environment-variables-from-a-webpack-bundle-in-a-docker-container/
If I'm understanding your problem correctly, you're serving a webpack bundle using nginx, and trying to access an environment variable from that bundle.
Unfortunately, it doesn't quite work that way. Your JS file has no access to the environment since it's a resource that has been delivered to the client. I've proposed a solution that also delivers those env variables alongside the bundle in a separate JS file that gets created on container start.

From VueJS Docs: https://cli.vuejs.org/guide/mode-and-env.html
Using Env Variables in Client-side Code
Only variables that start with VUE_APP_ will be statically embedded into the client bundle with webpack.DefinePlugin. You can access them in your application code:
console.log(process.env.VUE_APP_SECRET)
During build, process.env.VUE_APP_SECRET will be replaced by the corresponding value. In the case of VUE_APP_SECRET=secret, it will be replaced by "secret".
So in your case, the following should do the trick. I had the same problem once in my project, which I started with vue/cli and vue create project ...
VUE_APP_BACKEND_URL=https://whatever:3000

Related

Using .env.local file. Getting process.env.NEXT_PUBLIC_VERCEL_ENV is undefined on client

I'm using Next.js with Vercel. This is my .env.local file:
# Created by Vercel CLI
VERCEL="1"
VERCEL_ENV="development"
VERCEL_URL=""
VERCEL_GIT_PROVIDER=""
VERCEL_GIT_REPO_SLUG=""
VERCEL_GIT_REPO_OWNER=""
VERCEL_GIT_REPO_ID=""
VERCEL_GIT_COMMIT_REF=""
VERCEL_GIT_COMMIT_SHA=""
VERCEL_GIT_COMMIT_MESSAGE=""
VERCEL_GIT_COMMIT_AUTHOR_LOGIN=""
VERCEL_GIT_COMMIT_AUTHOR_NAME=""
I have a component that is trying to access: process.env.NEXT_PUBLIC_VERCEL_ENV to make sure it is on development environment.
This is what I'm getting when running npm run dev.
Logs from the server:
The logs above make perfect sense. Since it's running on the local server to render the pages.
But when my client code tries to do the same, I'm getting:
This is how I'm trying to acess it:
console.log(`process.env.NEXT_PUBLIC_VERCEL_ENV: ${JSON.stringify(process.env.NEXT_PUBLIC_VERCEL_ENV)}`);
console.log(`process.env.VERCEL_ENV: ${JSON.stringify(process.env.VERCEL_ENV)}`);
On client, the VERCEL_ENV should be undefined, but NEXT_PUBLIC_VERCEL_ENV should be development, right?
What could be happening?
UPDATE
I even tried to add NEXT_PUBLIC_VERCEL_ENV="development" to the .env.local file. But so far, the result is the same.
NEXT_PUBLIC_VERCEL_ENV="development"
You will have access to this everywhere (in the browser and Server).
VERCEL_ENV="development"
You only have access to this in the server, in the browser it will show undefined.
Please note after you add or make any changes in the .env.local file you have to restart your server otherwise it will show undefined if you console.log the variables.
Make sure Automatically expose System Environment Variables is checked in your Project Settings.
System Environment Variables
More info in docs

NextJS: Prevent env vars to be required on build time

We are working on a Dockerized NextJS application that is thought to be built once and deployed to several environments for which we will have different configuration. This configuration is to be set in the Docker container when deployed as environment variables.
In order to achieve this, we are using next.config.js file, splitting the vars on serverRuntimeConfig and publicRuntimeConfig as suggested here, and we are getting the values for the environment variables from process.env. i.e.:
module.exports = {
serverRuntimeConfig: {
mySecret: process.env.MY_SECRET,
secondSecret: process.env.SECOND_SECRET,
},
publicRuntimeConfig: {
staticFolder: process.env.STATIC_FOLDER_URL,
},
}
The problem we have is that these variables are not set on build time (when we run next build), as they are environment specific and supposed to be set on deployment. Because of this, the build fails complaining about the missing variables.
Making a build per environment is not an option: as referred before, we want to build it once (with next build), put the output of the build in a docker container, and use that docker container deploy in several environments.
Is there any way to solve this so that the application builds without environment vars and we pass them afterwards on runtime (deployment)?
We finally found the issue.
We were importing code in a helper that was being used in the isomorphic side and was relaying on serverRuntimeConfig variables, being then required on build time in order to create the bundle.
Removing the import from the helper fixed the issue.

Nuxt environment variables exposed in client when uploaded to Zeit/Now

I am deploying a Nuxt App with Zeit/Now. In the development phase I was using a .env file to store the secrets to my Contentful CMS, exposing the secrets to process.env with the nuxt-dotenv package. To do that, at the top of the nuxt.config I was calling require('dotenv').config().
I then stored the secrets with Zeit/Now and created a now.json to set them up for build and runtime like so:
{
"env": {
"DEMO_ID": "#demo_id"
},
"build": {
"env": {
"DEMO_ID": "#demo_id"
}
}
}
With that setup, the build was only working for the index page and all of the Javascript did not function. Only when I added the env-property to the nuxt.config.jsfile, the app started working properly on the Zeit-server.
require('dotenv').config()
export default {
...
env: {
DEMO_ID: process.env.DEMO_ID
},
...
modules: [
'#nuxtjs/dotenv'
],
...
}
BUT: When I then checked the uploaded Javascript files, my secrets were exposed, which I obviously don't want.
What am I doing wrong here? Thanks for your help.
You aren't necessarily doing anything wrong here, this is just how Nuxtjs works.
Variables declared in the env property are used to replace instances of process.env.MY_ENV, but because Nuxt is isomoorphic, this can be both on the server and client.
If you want these secrets accessible only on the server, then the easiest way to solve this is to use a serverMiddleware.
As serverMiddleware is decoupled from the main Nuxt build, env variables defined in nuxt.config.js are not available there.
This means your normal ENV variables should be accessible, since the server middleware are run on Node.
Obviously, this means these secrets won't be available client side, but this works if you have something like a Stripe secret key that you need to make backend requests with.
We had a similar problem in our project. Even, We created a nuxt project from scratch and checked to see if there was a situation we skipped. We noticed that, while nuxt building, it copies the .env variables into the utils.js in the nuxt folder. Through the document here, we changed the modules section in nuxt.config.js as follows,
modules: ['# nuxtjs / apollo', '# nuxtjs / axios', ['# nuxtjs / dotenv', { only: ['']}]],
Then we noticed that .env variables are not exposed.
I hope it helped.
Our nuxt version is "nuxt": "^ 2.13.0".
Also, some discussion over here.

Assets folder resolution: Running an application within a project not picking up assets

I created an application within an Angular workspace. When running
ng serve [application-name]
Picks up images and files in asset folder fine. Now I want to run the workspace with just
ng serve
I would expect through having the application lazy loaded the path would resolve but instead I get
zone.js:3243 GET http://localhost:4200/assets/terms.txt 404 (Not Found)
What is the proper setup to access assets of an application within a workspace?
EDIT After talking offline I think we've found a solution. I'll post it here and leave the below for reference even though the original answer I posted doesn't really apply to the problem.
You're trying to run multiple Angular apps and route between them via something like Firebase where you can direct different routes to different apps.
To get this to work locally for development you will need to run each Angular app separately on it's own port. I suggest you control the destination of the route in the environment files. This way when you are running locally you can point to the port the app is running on and then point to the endpoint Firebase uses in production.
Example environment.ts file in your root app
{
...,
OTHER_APP_URL: 'localhost:4201'
}
prod.environment.ts
{
...,
OTHER_APP_URL: '/otherApp'
}
Then in your component
....
import {environment} from '<path to environments file>';
#Component({
selector: 'my-component',
template: '<a [href]="otherAppUrl"></a>'
})
export class MyComponent implements OnInit {
otherAppUrl: string;
ngOnInit() {
this.otherAppUrl = environment.OTHER_APP_URL;
}
}
You will probably need to do something similar in the other apps so you can route from them to the root app or other child apps. You will probably also need to build the other apps with the --baseHref flag when you build for production so their assets are available. See here for more info from the docs: https://angular.io/cli/build
Old answer - doesn't really apply to the question
Looking at your repo I don't see the terms.txt in your root project's assets folder. I checked to see if it was in one of the other libraries in the repo but wasn't able to find it there either.
If this is an asset that is included or referenced by a component or service in one of your libraries you will need to copy that over to the library's output folder as part of your build process since that functionality isn't currently supported by the Angular CLI.
An example of a build script that might do this for you is:
ng build my-lib-with-assets --prod && cp -r projects/my-lib-with-assets/src/assets dist/my-lib-with-assets && ng build --prod
Don't forget that you need to build your libraries before you build your main project.

React-native run-ios loading environment variables

I want a modern way to manage environment variables for a react native mobile app.
The answer here explains the twelve-factor method style (which I love) which involves installing a babel plugin that transpiles references to
const apiKey = process.env.API_KEY;
to their corresponding values as found in the process's environment
const apiKey = 'my-app-id';
The problem is that in order to run this with a populated environment, I need to set it like
API_KEY=my-app-id react-native run-ios
If I have a .env file with 10-20 environment variables in it, this method becomes unwieldy. The best method I've found so far is to run
env $(cat .env | xargs) react-native run-ios
This is a bit undesirable because developers who want to work on this package have to set up custom shell aliases to do this. This isn't conducive to a good development environment, and also complicates the build and deploy flow for releases.
Is there a way to add a hook to the react-native-cli (or a config file) that populates the process environment first? Like an npm "pre" script, but for react-native.
You can use react-native-config which is a native library and requires a link to work or react-native-dotenv which works just like react-native-config but doesn't require any native link.
It'll work fine with .env files set up, e.g. .env.development with environment variables for process.env.NODE_ENV === 'development'.

Resources