Properly defining environment variables in Cloud Run for my React App - javascript

I am currently deploying a react application (front-end only) using Cloud Run, I have created a trigger for a cloud build to run which deploys the app using Cloud Run.
However, when I'm trying to create some environment variables to access in my components using cloud run UI I cannot access them due to the fact (from my understanding) that the environments are defined within the instance of the app and not the user's browser.
So my question is - How should I properly approach this issue?
I've tried perhaps building sort of "config.json", but I wasn't able to find a proper way to mount the files in different environments.

You'll want to do the following. First, install https://www.npmjs.com/package/env-cmd
Next, you can specify the .env to be used depending upon your environment as so. The below code allows you to specify configuration declaratively rather than imperatively. Now, when you say process.env.REACT_APP_ENV1 process.env.REACT_APP_ENV2 process.env.REACT_APP_ENV3, then depending on env the correct values will be transparently picked up.
"scripts": {
"start": "env-cmd -f env_anotherenv.env react-scripts start",
"start_vscode": "env-cmd -f env_vscode.env react-scripts start",
"build_staging": "env-cmd -f env_staging.env react-scripts build --profile",
"build_production": "env-cmd -f env_production.env react-scripts build --profile"
}
Example of env_production.env will be
REACT_APP_ENV1 = someenv1
REACT_APP_ENV2 = someenv2
REACT_APP_ENV3 = someenv3
Example of env_staging.env will be
REACT_APP_ENV1 = someotherenv1
REACT_APP_ENV2 = someotherenv2
REACT_APP_ENV3 = someotherenv3

I would suggest you bake in your environment variables in your build artifacts which you then access using process.env.VARIABLE_1 as described here.
Use a multi-stage docker build. In your build stage populate a .env file from build-args (e.g using envsubst) before running npm run build. Here is a sample using a template that you can push to your git repo.
ARG VARIABLE_1
ARG VARIABLE_2
COPY .env.template .
RUN /bin/sh -c "envsubst '\$VARIABLE_1 \$VARIABLE_2' < .env.template > .env"
.env.template
VARIABLE_1=${VARIABLE_1}
VARIABLE_2=${VARIABLE_2}
Depending on how your cloud build triggers are set up, the values for the build args can be sourced from substitution variables.
The final stage can be based on the nginx image, here you copy the built static files bundle and serve using nginx. See a full docker example here
This way you do not expose a .env file and there is no environment variables configuration to be done from the cloud run end.

Related

Prevent vue cli from deleting all files in dist

I am developing vue project and syncing dist folder with git. This worked well while using webpack. However, I have moved to #vue/cli --- using vue create myProject instead of vue init webpack myProj.
The issue is that every time i run npm run build, it deletes dist folder and recreates it -- all .git and other files gone.
How do I prevent new build from deleting required files in dist folder and only update the changes?
Assuming you have your own mechanism for cleaning up the old resources, vue-cli-service build comes with this option called --no-clean to instruct the compiler not to remove the "dist" directory before building the project.
So, add the switch/option to the build script on package.json:
{
"scripts": {
"build": "vue-cli-service build --no-clean"
}
}
Alternatively, if you use Yarn, you can pass additional argument(s) right after the script name. So there's no need to make any change to the script. To run it:
yarn build --no-clean
Thanks to answer by Yom S. the documentation here does provide way to keep older dist.
However, the you can't use --no-clean like npm build --no-clean. To use no clean mode from terminal you need to write following command instead
./node_modules/.bin/vue-cli-service --no-clean
Update
Instead you can also add --no-clean in package.json

How to hide API keys and secrets in React JS app deployed on Docker

I want to keep keys and secrets from showing up to the end-user in the React app final build. I found ways suggesting to keep secrets in the environment variable file in docker.
Below is the code so far which is not working. The REACT_APP_SOME_API is not accessible in React also I am not sure if using this method, secrets will be visible in the final build which I don't want.
Package.json in React:-
"scripts": {
"start": "rm -rf dist && webpack-dev-server --mode development --open --hot --port 8090",
"docker": "rm -rf dist && webpack --mode production && make docker-run",
"docker-push": "rm -rf dist && webpack --mode production && make docker-push --"
},
Makefile:-
docker:
docker build -t app .
docker-run: docker
docker run -it --env-file ./config.env -p "80:80" app
docker-push: TAG ?= latest
docker-push: docker
docker tag $(NAME) $(DOCKER_REPO):$(TAG)
docker push $(DOCKER_REPO):$(TAG)
config.env:-
REACT_APP_SOME_API=This-should-be-accessible-in-react-app
App.js in React app:-
return(
<>{process.env.REACT_APP_SOME_API}< />//This outputs undefined if console.log
);
You should never put an API Key inside a client app in the first place. API keys are meant for server to server communication. If there are some secrets, you can store it inside session storage when the user logs in as a token.
as in React documentation
React apps have no hidden code.You have to write a backend for it (where all hidden parts are) which provides public interface your React app can query.
You can try to obfuscate the code, but you cannot hide it.
That's the reason why some API's require you to also provide a domain for it so it provides another layer of limit about where people can use your API key at, even when published.
If something is utilized by your react application, it can always be accessed by the end-user. Even when talking about programs compiled to assembly, they can still be decompiled.
As a rule of thumb, do not expose API keys which are not supposed to be exposed to the end-users.
Create files for different environment like this inside your source directory like this:
env.dev
env.production
Inside your environment file define different Key like:
REACT_APP_SOME_API="http://test.com"
Run the command to read keys from different file at the time of running:
"start": "sh -ac '. $(pwd)/env.development; rm -rf dist && webpack-dev-server --mode development --open --hot --port 8090'"
You can access the keys inside your application by
process.env.REACT_APP_SOME_API
Hope it helps.

Can I easily run a vue.js webapp in a sails.js assets directory?

I am learning how to use Sails.js and vue.js. So I'm trying to develop a small app where there's a vue.js application located inside the assets/ directory of sails.js. The idea is to serve both applications with the same server (command sails lift), but I'm getting some trouble to make it work.
The reason is because the sails server can serve the index file of my vue app (assets/web/dist/index.html), but other vue resources will 404, because my vue index.html file will ask for addresses like localhost:1337/static/etc instead of localhost:1337/web/dist/static/etc.
So I could make it work running npm run-script build in assets/web (my vue directory) and creating a copy of assets/web/dist in my assets directory. This way my vue app is served by the sails.js dev server. But I have to "compile" vue and copy it everytime I change something. It would be fine for production, but is terrible for developing.
Is there some easy way to develop this application using only one dev server, or should I split them in two apps and serve them separatelly (in dev environment) ?
I'm using sails v1.0.2 and latest bootstrap-vue (currently bootstrap ^4.0.0-beta.2 and vue ^2.5.2)
(it's available in https://github.com/lampsbr/projetao)
You should split it, e. g. frontend/backend directory, and it's better to have different terminal sessions for both servers because if not, it might get messy. In my example project with Vue.js and Sails.js, it's still possible to start both simultaneously. But that's only for very quick changes.
This is how I do it inside the package.json:
"scripts": {
"dev": "cd backend && npm run dev & cd frontend && npm run dev",
"install": "cd frontend && npm i && cd ../backend && npm i && cd .."
},
You have to compile your Vue.js application only when going production and, as you mentioned, it will be pushed into assets directory of Sails.js. That said, only your compiled Vue.js application should be located inside your assets directory, no source files!
Another common approach is to have a client directory inside your Sails.js directory.

JS serving and REST API from machine with changing IP address

I have an app using React that interfaces to a REST server via axios. The REST server (flask) is on the same machine that is serving the build of the JS project. The project being served is the output of npm run build. npm serve is then used to deploy this package. The web interface is then viewed from a remote machine of a different IP.
The issue I have encountered is that the IP of the machine that is serving the site and the REST API may change. How to I go about changing the IP that axios is calling dynamically? At the moment I have a script that searches for the IP string in the js build and replaces it with the machines current IP.
Using utilities like ip have only been returning localhost. I guess I need to find a way to get the IP of who is serving the script?
You can make use of env variables to solve these issues. One popular way is to use cross-env. Your package.json file would have a build command in the script section. You'll have to modify these to add the required configs as environment variables and use it in the code where required.
Example:
{
"scripts": {
"build:prod": "cross-env API_URL=http://myserverip.com NODE_ENV=production webpack --config build/webpack.config.js",
"build:dev": "cross-env API_URL=http://localhost:8000 NODE_ENV=development webpack --config build/webpack.config.js"
}
}
Then you can use different commands to build them. To build prod run npm run build:prod. To build dev run npm run build:dev.
In your code, you can use process.env.API_URL(in place where you write ip address/hostname) which will have different values based on the build. To allow webpack to replace these env variables, use webpack Define plugin as
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(process.env.NODE_ENV),
API_URL: JSON.stringify(process.env.API_URL),
}
})
If the REST server and the API share a common server, you could just omit the IP address entirely, so instead of
axios.get('http://123.4.567.89/user?ID=12345')
you can just
axios.get('/user?ID=12345')
Other than that, using DNS is usually a better way:
axios.get('http://my.domain/user?ID=12345')

How to create new environments with create-react-app?

I am using react-scripts v2 (beta) and I have read the documentation here.
We need to create many environments.
We want to store env file under folder config/env.
We might use javascript file in config/env/staging.js because .env seems to be only for root directory.
We have real environment :
default
development
staging
preproduction
production
We expect the default environment to be a default config under version control in config/env/default.js, it must be the default configuration used when doing npm start
We expect the user to be able to override with a file with no version control. (something like config/env/default.local.js
Basically that can be reduced to two issues :
Is it possible to relocate env location folder?
How can we create and select a new environment on npm start/build?
without ejecting.
Just copy the environment file to .env before starting / building. You can even put .env in .gitignore that way
"start": "cp $ENV .env && react-scripts start"
Then run it:
ENV=config/staging/.env npm start
There are lots of ways of doing what you want without ejecting, since it's all preprocessing (before your app starts / builds).

Categories