I am missing something about .env, could you explain it to me? - node.js

I have a very, basic, need: to store different endpoints for my APIs according to the environment. Suppose a simple file like this:
API_URL=http://localhost:8080
it should become, for my prod environment:
API_URL=http://myprodServer
and I'd like to have an integration test and a uat endpoint too!
Looking at my package.json I see:
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
So my idea is:
Put a command line argument near to "build" and "start" so to specify local and production enviroment files
Have a way to access to said configuration in my app, say config.API_URL
Now, I come from spring boot, and in spring boot I have a file per environment.
I though dotenv could be my solution but I see two strange things on their website:
Please don't commit your .env file --> so, how are my colleagues supposed to build my application? I usually at least push local and test environment, while keeping the uat and production files directly under the server
You should have just one .env file --> ok this one destroys me: if I just have one file how am I supposed to handle several environments???
What am I missing here? Could you help me solve my problem? I'm new to npm so I'm a little confused...

It looks like you are using CRA to develop your React app. If so, your env variables should be REACT_APP_API_URL=http://localhost:8080. Notice the prefix. If you are using CRA, you must use the prefix. More about that here. If you do this correctly, the variable should be available in your javascript by using process.env.REACT_APP_API_URL.
At work, we each have a copy of the .env files locally, since we don't check it in. We have different .env files for each environment - e.g - .env.production, .env.development, .env.stage. We then have a run and build script for each environment in our package.json. Using env-cmd package, our scripts might look like this:
{
...
...
"start": "react-scripts start",
"start:stage": "env-cmd .env.stage.local react-scripts start",
"start:production": "env-cmd .env.production.local react-scripts start",
"build": "react-scripts build",
"build:stage": "env-cmd .env.stage.local react-scripts build",
"build:development": "env-cmd .env.development.local react-scripts build",
...
...
}
Along with this, we also have a git branch per environment so that on stage branch we would run npm run build:stage and deploy to Stage environment. We would do the same for production.
After looking around for a multi-environment setup, this is what I settled on and it works ok. However, I'd be open to improving the process.

Related

Deploy NodeJS app to GCP AppEngine with customize start command

Here is my package.json
"scripts": {
"start": "react-scripts start",
"start:develop": "env-cmd -f env/.env.develop react-scripts start",
"start:stage": "env-cmd -f env/.env.stage react-scripts start",
...
}
env folder structure
env
├─ .env.develop (env=develop)
├─ .env.stage (env=stage)
When run on local (MacOS)
"yarn start" runs NodeJS app on local with default "env" = local (which is defined in other file)
"yarn start:develop" runs NodeJS app on local with "env" = develop
But now when I want to deploy this to GCP AppEngine, it's always deploy with "start" command (equivalent to "yarn start" on local)
How can I deploy "yarn start:develop" to AppEngine without declaring more environment variables in app.yaml?
From the documentation about what happens when you deploy your program,
Node.js modules are installed in the cloud as listed in your package.json and package-lock.json files and your service is started by using npm start.
I interpret the above to mean your project on the cloud is always run with start script and GAE will not/does not know how to use another script.
A possible workaround could be to deploy your app using a different version name e.g. dev i.e. you have
Your default version with "start": "react-scripts start"
dev version with "start": "env-cmd -f env/.env.develop react-scripts start"
Both of your versions use only the start script but they do different things

How to get .env from root project into React client

I'm trying to do something that should be REALLY simple but it's proving exceedingly difficult. I've burned 4 hrs on this today. I have a nodeJS project with server and client parts. I'm using concurrently to launch them both. I want to use the same .env for both server and client. Should be simple, right? Apparently not. The problem is that when I try to use dotenv in my React client, it never finds the .env no matter what I do, and the reason is that __dirname (and process.cwd()) always point to the root directory (i.e. /). I need it to be a relative path, or at least I need to pass somehow the explicit path to my react app.
I've even tried running the client directly by calling 'npm start' from my client directory - the process.cws() still defaults to the root partition and not my project directory.
My directory structure is as follows:
+project_root
- .env
- index.js
- package.json (for the server side)
+ client
- package.json (for client)
+ src
- App.js (this is where I'm trying to access .env)
My package.json for the server has the following in the scripts section:
"scripts": {
"start": "node index.js",
"start-watch": "nodemon index.js",
"dev": "concurrently \"npm run start-watch\" \"cd client && npm start\""
}
On the client side I have
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
}
I normally start all of this from the project root by calling 'npm run dev'. However, I thought to try and build a run script for it, and from my run script pass in environment variables of the form REACT_APP_
The above works, but in the absence of being able to actually get REACT to set itself to be in a directory other than root, I still cannot get React to read the project .env.
What I've been trying next is to have my run script output all the contents of .env as REACT environment variables. I so far haven't got it to work, here is the run script I tried:
!/bin/sh
export REACT_APP_CURR_DIR=`pwd`
grep -v '^#' .env | while read line
do
echo exporting line $line
VARNAME=REACT_APP_`echo $line | sed -E 's/(.*)=.*/\1/'`
VALUE=`echo $line | sed -E 's/(.*)=(.*)/\2/'`
echo $VARNAME
`export ${VARNAME}=${VALUE}`
done
npm run dev
When I do this, it barfs on some of the variables, but none of them make it into process.env within my react client.
Am I missing something very basic here? I feel like I've gone to extreme lengths just to have server and client use the same .env file so I'm not duplicating parameters everywhere. Even if I put a .env file in my client, the fact that even executing npm start is not giving the React app the right directory is problematic.
I can't believe no one has come into this before.

Create-React-App while attempting to run a Typescript mock api server (module loading error)

I have a client app created with create-react-app and it uses typescript. My directory structure is like this (apologies if it's confusing):
-MyApp (folder)
-node_modules (folder)
-package.json (has a script that runs the react client app and the mockApi using, 'ts-node mockApi/server.ts')
-tsconfig.json (this uses module:esnext because apparently CRA requires it?)
-src (folder)
-components
etc.
-MockApi (folder level with MyApp)
-tsconfig.json (uses module:commonJS for server.ts)
-server.ts (creates a json-server in express/node using import syntax)
-mockData (folder)
-index.ts (gathers domain types into single objects)
-someEntity.ts (domain type)
I have in my main package.json a couple scripts. One runs the command 'ts-node mockData/server.ts' to load my typescript mock api on its own port. The other script runs the normal react-scripts to load the react client on localhost:3000. I'm using a lib that allows scripts in parallel.
Before I added this to my existing app, I created the mock api in its own project with typescript and json-server to ensure it would work, and it did. But the "module" key in the api's tsconfig needs to be "CommonJS" to do the dynamic imports. I figured it would work in a create-react-app project if the mock api had its own tsconfig file set to CommonJS. But the script to load the api causes an error.
When I run it, it says "import xxxx is not a module" (in server.ts). The package.json script is using the tsconfig settings in my main project to load the server.ts file, using "module:esnext", instead of commonJS, as defined in my api tsconfig. How do I tell it to use the settings in the other tsconfig?
Here is my scripts section in my CRA package.json:
"scripts": {
"start": "run-p start:dev start:api",
"start:dev": "cross-env REACT_APP_API_URL=http://localhost:3000 react-scripts start",
"start:api": "ts-node ./mockApi/server.ts",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
And the start:api script is where it's blowing up in my server.ts (the first import):
import jsonServer from "json-server";
import mockData from "./mockData/index";
Is it just not possible to do what I'm trying to do with create-react-app? I've tried to research this but I cannot find anything that mentions this specific issue. Every json-server example is in JS. But json-server has #types for TS so I don't get why this issue isn't documented. Surely others use Typescript with Json-server and c-r-a.
Thank you
So in case anyone has this question, the answer was to have a script in my ui's package.json that goes to my mock api folder and runs a script in that folder's package.json to start the api, and then run my create-react-app script. So I changed my root/package.json to:
"scripts": {
"start:api": "cd mockApi && npm run start",
"start": "run-p start:api start:dev",
"start:dev": "cross-env REACT_APP_API_URL=http://localhost:3000 react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
then in my root folder, just run this to kick it off:
npm run start
And obviously in my mockApi/package.json I have
"scripts": {
"start": "ts-node server.ts"
}
This works great.

How to hide a section in .hbs and .js while taking an ember production build

Our Ember application is developed in 2.8 version and we follow POD structure.
We are generating two different builds as below
1) For our dev server : No change in code,just do build
2) For our test server: Delete a section in HBS and also remove a route from router.js then do build
And we take build using "npm run-scripts build" which is configured in our package.json as below
"scripts": {
"build": "ember build",
"start": "ember server",
"test" : "ember test"
},
I would like to know in ember 2.8v can i have a condition written to remove the section based on build.
Like if i give npm run-scripts buildDev it will do the regular build
and if i give npm run-scripts buildTest it will do sections removals and give a build
but in package.json both will be configured like
"scripts": {
"build" : "ember build",
"buildDev" : "ember build --environment=production",
"buildTest": "ember build --environment=production",
"start": "ember server",
"test" : "ember test"
},
Do you only want to disable a section or do you need to remove it from the build?
Its pretty easy if you want to only disable something:
First you can use environment variables in your config/environment.js. So something like this:
if(process.env.DEV_BUILD) {
ENV.disableSomething = true;
}
In your package.json you could do this:
"build": "cross-env DEV_BUILD=1 ember build",
This uses cross-env to set the env variable in windows and *nix systems.
You can then import the config and use it:
import ENV from 'hss/config/environment';
...
if(!ENV.disableSomething) {
this.route('foo');
}
...
However if you want to actually remove some code you could write your own addon for this to replace some variable with true or false. then the minifier will remove the code.

Google App Engine: Setting environment variables for React Production Build

I'm running a basic create-react-app production build on App Engine, but I'm not able to access my pre-defined environment variables. Is there any extra step I'm missing? I'm guessing it has something to do with the build process and serving a production build, but I'm not sure where to set the variable in this case.
app.yaml:
service: client-dev
runtime: nodejs10
env_variables:
TEST: "development"
package.json:
"scripts": {
"start": "serve -s build",
"start-dev": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
console.log(process.env.TEST) //undefined
According to CRA documentation, environmental variables are embedded during build time in a React app. They will not be available to static files during runtime.
In App Engine, contents of app.yaml are used during deployment which happens after React has finished building.
To make environmental variables available during build time, you can:
include them in a .env file in the root of your project if you are manually triggering the build process via yarn build or npm run build.
include them in a cloudbuild.yaml file for automatic builds using a continuous development platform like Cloud Build.
Note that the CRA documentation referenced above advises to begin every custom environment variable with REACT_APP_. For example your variable should be added like REACT_APP_TEST=development.

Resources