set environment variable on build React.js - node.js

I am trying to have a custom environment variable on build with React, by default it's set to production but I'm trying to have a custom QA build with a custom variable.
Ps : Project is ejected, is there anyway I can manage to do that without messing with my webpack configs.

This is how I do it (I am using react-scripts) :
In package.json I have those scripts :
"build:prototype": "env-cmd -f ./.env.prototype npm run-script build",
"build:demo": "env-cmd -f ./.env.demo npm run-script build",
"build:local": "env-cmd -f ./.env.local npm run-script build",
"build:production": "env-cmd -f .env.production npm run-script build",
and I call them just like any other : npm run build:prototype for example
Hope it helps
Edit: of course I have those .env files at the root of the project

Use webpack's Define Plugin
new webpack.DefinePlugin({
"CUSTOM_VARIABLE": JSON.stringify("whatever you want to set it to")
})
And wherever you need to change certain things in your app, you can check the value of process.env.CUSTOM_VARIABLE and act according to its value. If there are only a few places that depend on this variable, this will work fine. If there are more, it might be worth looking into other approaches, such as React's Context Hook API

Related

How to make Angular watch multiple libraries for changes and recompile when needed

This question is much the same as Make angular app watch for libraries changes and update itself. But, that question was never successfully answered as applies to the use of multiple libraries. I also reviewed Angular library and live reload and surveyed the answers and links from both questions.
My app is using two libraries: lib-1 and lib-2. When those files are edited, they are ignored and the app does not recompile. To see changes, I have to restart the server which really slows things down.
My expectation is that the app should be recompile when library files are edited, just like when other app-internal files are edited.
This is an Angular project that I have inherited, and the original author is no longer available. I am using Angular v10 and npm 6.14.11
The initial npm scripts are:
"start:staging": "ng serve --configuration-staging --host 0.0.0.0 --port 8080 --disableHostCheck",
"build:lib-1": "ng build lib-1 && cpx projects/lib-1/src/lib/theme.scss dist/lib-1",
"build:lib-2": "ng build lib-2 && cpx projects/lib-2/src/lib/theme.scss dist/lib-2",
"build:libs": "npm run build:lib-1 && npm run build:lib-2",
With those, I first run npm run build:libs, then npm run start:staging. As mentioned, this does not "watch" my libraries for changes.
I reviewed the suggestions and the other SO questions (above), have ensured that the npm-run-all, wait-on and rimraf libraries are now installed.
I have written these new npm scripts:
"clean": "rimraf dist",
"start-app": "wait-on dist/lib-1/fesm2015 dist/lib-2/fesm2015 && start:staging --poll 2000",
"watch:lib-1": "npm run build:lib-1 --watch",
"watch:lib-2": "npm run build:lib-2 --watch",
"watch-libs": "npm-run-all --parallel watch:lib-1 watch:lib-2",
"watch-all": "npm-run-all clean --parallel watch-libs start-app"
And, I am using the pre-existing start:staging script, as written.
I run npm run watch-all.
The script runs and proceeds to the point of building the libraries in parallel (bad idea?), and then throws error: sh: start:staging: command not found.
I removed the --parallel switches and tried again, and got the same error.
The start:staging script is indeed in the scripts object, and I cannot figure out why it's not being found.
I'm hoping to get some sage advice on correcting my syntax so that the app will compile and watch my library files along with the other files that are inside the app's src folder.
After a lot of sleuthing, I came across Nikola Kolev's Angular 6: build — watch multiple dependent libraries in one shell post.
While I don't have it down to one npm script like Nikola was able to do, I am able to do it by running two scripts (there are 7 total scripts involved), and that's good enough for now. I'll work on condensing to one when I get more time.
First, be sure to have wait-on, rimraf and npm-run-all installed. We're also using cpx; but, that's not about getting the libraries to be "watched" -- just including to be overly thorough.
Here are all the scripts:
"clean": "rimraf dist",
"watch-lib:lib-1": "ng build lib-1 --watch",
"watch-lib:lib-2": "ng build lib-2 --watch",
"watch-libs": "npm-run-all clean --parallel watch-lib:*",
"copy-styles:lib-1": "cpx projects/lib-1/src/lib/theme.scss dist/lib-1",
"copy-styles:lib-2": "cpx projects/lib-2/src/lib/theme.scss dist/lib-2",
"start-staging": "ng serve --configuration-staging --host 0.0.0.0 --port 8080 --disableHostCheck",
"watch-staging": "npm-run-all copy-styles:* start:staging"
When I want to work on the libraries and have them be "watched", I run npm run watch-libs in one terminal. When that is finished, I run npm run watch:staging in a second terminal. Then, I'm able to launch the app in a browser, and any edits to any of the code, in libraries or in the app itself are caught, and the app recompiles as desired.

GENERATE_SOURCEMAP=false Issue

In windows when I tried to build react app I am getting error saying 'GENERATE_SOURCEMAP' is not recognized as an internal or external command.
I have added below line in my package.json file
"build": "GENERATE_SOURCEMAP=false react-scripts build"
Keep this in package.json:
"build": "GENERATE_SOURCEMAP=false react-scripts build",
"winBuild": "set \"GENERATE_SOURCEMAP=false\" && react-scripts build",
Use npm run build for creating build on Linux.
Use npm run winBuild for creating build on Windows.
Another solution is to create a new file in your project's root directory named .env and include the following inside the file. This will remove any .map files from your build/static/js folder the next time you run build.
GENERATE_SOURCEMAP=false
Use cross-env to safely set environment variables across multiple operating systems:
"build": "cross-env GENERATE_SOURCEMAP=false react-scripts build"
Also you can try the below setting in your scripts if you are running on windows
"build": "set \"GENERATE_SOURCEMAP=false\" && react-scripts build"
For windows
use "set" and
use "&&" in between,
like
"build": "set GENERATE_SOURCEMAP=false && react-scripts build"
,this command also can be used to remove .map files after generated
"build": "react-scripts build && del build/static/js/*.map"
maybe something like this would help you, create new app:
npx create-react-app app
cd app
and then run:
GENERATE_SOURCEMAP=false yarn build
For Cross Platform: Just open .env and add GENERATE_SOURCEMAP=false
Linux: GENERATE_SOURCEMAP=false
Windows:
set \"GENERATE_SOURCEMAP=false\"
create a file name .env
add this code to the file : GENERATE_SOURCEMAP=false
On Heroku, go to Settings -> Config vars -> add GENERATE_SOURCEMAP with value false
On Vercel, go to Settings -> Environment Variables -> add GENERATE_SOURCEMAP as key and False as value, set environment Production -> Save
If you are using Heroku, you have to add this in the Config Vars inside the settings of your App. This is the way is supposed to be set from the documentation documentation

Cross platform package json

I want to create a cross platform package json which needs to work in both mac and windows.
I have a scripts object
"scripts": {
"dev": "npm run cleanup && webpack --watch",
"build": "npm run cleanup && NODE_ENV=\"production\" webpack",
"lint": "eslint ./main/content/jcr_root/etc/designs/digital/clientlibs/src/js --fix -f table --ext .js --ext .jsx || true",
"cleanup": "rm -rf ./main/content/jcr_root/etc/designs/digital/clientlibs/dist"
},
I have tried everything but cannot set it as cross platform. Please help me with this.
Your best bet would be to rely on node modules to do the job.
For rm -rf there is a node package called rimraf.
Install the package via
$ npm i -D rimraf
And adjust your script to use it:
"scripts": {
"clean": "rimraf ./main/..."
}
Since node packages are mostly cross-OS, this should work.
You might also want to take a look at cross-env to set your NODE_ENV.
Let me know, if any additional help is required. :-)
Edit:
Since you are using webpack, there are also plugins for clean tasks as well as linting. For further information please take a look at:
clean-webpack-plugin
eslint-loader

How to set host environment variables inside npm scripts(package.json)

Imagine I have an environment variable
export NODE_ENV=production
when I do
echo $NODE_ENV //--> shows production which is correct
Problem:
Inside my package.json
scripts: {
...
"build": "export REACT_APP_NODE_ENV=${NODE_ENV:-development};
npm run build-css && react-scripts build",
...
}
Now when I do npm run build REACT_APP_NODE_ENV is getting set to development...but it should have been production as NODE_ENV is present.
If I do
scripts: {
...
"build": "export REACT_APP_NODE_ENV=production;
npm run build-css && react-scripts build",
...
}
It works correctly as expected i.e. all scripts access the REACT_APP_NODE_ENV with expected value that is production.
Goal
I wish to avoid hardcoding in my package.json
How can I set REACT_APP_NODE_ENV with value ${NODE_ENV}
"build": "export REACT_APP_NODE_ENV=${NODE_ENV};
npm run build-css && react-scripts build",
You probably want to ensure that this is cross-platform which will save you some headaches later on.
That problem has already been solved in the npm package cross-var.
Then, assuming you've already exported NODE_ENV, you use it this way:
"scripts": {
"build": "REACT_APP_NODE_ENV=${NODE_ENV}"
}

How do I deploy my Typescript Node.js app to Heroku?

When testing locally I was previously running:
"build-live": "nodemon --exec ./node_modules/.bin/ts-node -r dotenv/config -- ./index.ts"
I then figured my Procfile should be something like:
web: ./node_modules/.bin/ts-node -- ./index.ts
But it says module 'typescript' not found, even when it is in package.json. I read in a few places that ts-node is not the way to go to deploy to Heroku, so I am not sure what to do.
UPDATE: I think I am supposed to compile it, so I tried:
web: ./node_modules/.bin/tsc --module commonjs --allowJs --outDir build/ --sourceMap --target es6 index.ts && node build/index.js
This succeeds, however when actually running it, a bunch of the libs I'm using get "Cannot find module '...'".
Alternatively you can have the TypeScript compile as a postinstall hook and run node build/index.js as the only Procfile command:
Your package.json should contain a postinstall hint that gets executed after npm install and before the node process launches:
"scripts": {
"start": "node build/index.js",
"build": "tsc",
"postinstall": "npm run build"
}
You can then leave your Procfile as is:
web: npm start
This 'build on deploy' approach is documented by Heroku here.
The command you've given Heroku is to launch the web "process" by compiling index.ts and dependencies and starting node at index.js. Depending on how things are timed, index.js might or might not exist at the time node starts.
You need to already have your sources compiled by the time you want to start your app. For example, web should just be web: node index.js or similar.
Each build process is different, so you need to figure that out for your own setup. But, suppose you have a classical setup where you push to git and then Heroku picks up that change and updates the app with the new slug. You could just compile things locally and include index.js and any other build output in the repository, for it to be available in the slug for Heroku to use.
A better approach is to use a build server which has an integration with Heroku. After you do the build there, configure it to send the build results to Heroku. Travis has a straighforward setup like this. This way you don't need to include build outputs in your repository, which is considered an anti-pattern.
On a sidenode, try using a tsconfig.json to keep the tsc configuration. It will save you from having to write such long command lines all over the place.
Fabian said that we could do something like:
"scripts": {
"start": "node build/index.js",
"build": "tsc",
"postinstall": "npm run build"
}
As of me writing this, I tested this and can state: postinstall is not required since build script is ran by Heroku. If you want to do it without build script, then you can use heroku-postbuild which will run after dependencies are installed there you run tsc to compile.
My problem was about missing Typescript npm modules. The Typescript compiler tsc was not found when deployed the app to Heroku.
The Heroku deploy process (rightly) does not install development dependencies, in my case the Typescript module was part of devDependencies and thus the tsc command was not running on the Heroku platform.
Solution 1
Add typescript to dependencies: npm i typescript -s
Solution 2
Open Heroku console:
Select console type:
Run the command npm i typescript && npm run tsc
Install typescript as a dev dependency (cf. https://www.typescriptlang.org/download). Once built, your app does not need typescript anymore!
npm install -D typescript
Then in your package.json:
{
"main": "index.js", // <- file will be generated at build time with `tsc`
"scripts": {
"build": "tsc",
"start": "node ."
"start:dev": "ts-node index.ts" // idem, install ts-node as a dev dependency
}
}
The key point here is "build": "tsc".
Why?
Heroku does install all dependencies during build and remove the dev dependencies before the app is deployed (source here).
Node.js deployments will automatically execute an app’s build script during build (since March 11. 2019 source here)
In package.json
"scripts": {
"tsc": "./node_modules/typescript/bin/tsc",
"postinstall": "npm run tsc"
},
Works for me for Heroku deployment.
Installing typescript npm install -D typescript and writing tsc in the build script "build": "tsc", does not work for me. Also, try to run npm i typescript && npm run tsc in the Heroku console which also does not work.
In my case, I remove some dependencies from "devDependencies" to "dependencies", so it goes like this:
"dependencies": {
// The other dependencies goes here, I don't touch them.
// But all TS dependencies I remove to here.
"ts-node": "^9.1.1",
"tsconfig-paths": "^3.9.0",
"typescript": "^4.2.3",
"ts-loader": "^8.0.18"
},

Resources