React boilerplate - changing API url at runtime - node.js

I'm using react-boilerplate as the base for my project.
I'm currently defining my API url in webpack.base.babel.js like so:
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(process.env.NODE_ENV),
PIZZA_API_URL: JSON.stringify('https://some-ip:8081')
},
}),
However, this is only picked up at build time.
In create-react-app, you can use REACT_APP_PIZZA_URL. Anything that starts with REACT_APP* can be set at the start of runtime.
So I can do:
docker run -e "REACT_APP_DB_HOST=HELLOWORLD" -d -p3000:3000 pizza-supplier-ui:test
How do you do the same thing with react-boilerplate?
Thank you

Ok - here is the answer to my own question after hours of research and trial & error.
For production build, webpack will compile your js files and bundle them up in build/ directory.
The API URLs that are referenced as ${process.env.API_URL}/api/query/findPizzaById/ are baked into the compiled js files in the build/ directory.
Therefore this command:
docker run -e "API_URL=HELLOWORLD" -d -p3000:3000 pizza-supplier-ui:test
has absolutely no effect. It does however register API_URL as an environment variable on the running docker image. The problem here is that API_URL is defined at BUILD TIME, using the environment variable FROM where the build has run.
If anyone has struggled with this issue and have a solution I'd appreciate your enlightenment!
Thanks

Related

How to add environment variables to AWS amplify?

I have a React/Node app which i am trying to host on AWS amplify. first try, my app deployed but i saw some pages are not loading due to lack of the environment variables.
i have added them to the AWS console before deploying and it did not work. then i did some search and i saw that i need to modify "amplify.yml" file to:
build:
commands:
- npm run build:$BUILD_ENV
but not only it did not work, also the app is not working anymore.
any ideas?
As this question specifically references React, here are the steps you need to use environment variables in your React based application in AWS Amplify.
In your client-side JS:
const BUILD_ENV = process.env.REACT_APP_BUILD_ENV || "any-default-local-build_env";
The key thing to note here is my pre-fix of REACT_APP_ which is covered the Create-React-App docs: here
Now, in your Amplify console, under App Settings > Environment variables:
Finally, you also need to add this reference under App Settings > Build Settings:
Note: "BUILD_ENV" can be any string you wish. Within the environment variables you can provide the necessary DEV / PROD overrides.
DO NOT store SECRET KEYS using this method, AWS provide a secrets manager for this. This method is for publishable keys, like connecting to Firebase or Stripe and the key is fine to be public.
The Amplify documentation on Environmental Variables has a section on "Accessing Environmental Variables".
Per that documentation, in your Amplify.yml (either in the console or by downloading it to the root of your project), you can use a command to push Amplify Environmental Variables into your .env. If you created an Environmental Variable in Amplify called "REACT_APP_TEST_VARIABLE" you would do...
build:
commands:
- echo "REACT_APP_TEST_VARIABLE=$REACT_APP_TEST_VARIABLE" >> .env
- npm run build
Once in your .env you can access them through process.env...
console.log('REACT_APP_TEST_VARIABLE', process.env.REACT_APP_TEST_VARIABLE)
If you are using Create React App, you already have dotenv, or see Adding an .env file to React Project for more info.
Obligatory reminder to add your .env to your .gitignore, and don't store anything in .env that is sensitive.
To get #leandro's answer working I had to wrap the AWS environment variable names in curly braces:
build:
commands:
- npm run build
- VARIABLE_NAME_1=${VARIABLE_NAME_1}
Probably better as a comment but I don't have enough points to post one.
#A Zarqam Hey man, I ran into this issue ans spent a decent amount of time on it. What worked for me was:
On my React code, use process.env.VARIABLE_NAME
On my webpack.config.js use the following plug-in:
new webpack.EnvironmentPlugin(['VARIABLE_NAME_1', 'VARIABLE_NAME_2'])
On the Amplify environment variables put the VARIABLE_NAME_1,etc and then the values, just like in the docs says.
Last on the build settings:
build:
commands:
- npm run build
- VARIABLE_NAME_1=$VARIABLE_NAME_1
(the one with $ is a reference to the one you put in amplify. Also I think you must have no spaces between the = symbol)
Then trigger a build, and cross your fingers.
Just to add to other comments regarding Secret keys, since SO doesn't let me comment until 50 rep... If you're not using those Env Variables in your front-end app such as process.env.<var_name>, and only use them during build time, you're fine. Those files will not be bundled into your front-end app.
I know this question is related to frontend apps but its title appeared in search engines for me even though I was looking for build variables only, so it might be useful for other people too.
An add on to #leandro's for anyone checking for this in the future I just want to simplify what you need to do since I was completely lost on this:
In your code reference all API keys as process.env.EXAMPLE_API_KEY_1
Run this in your root folder terminal npm install react-app-rewired --save-dev
Add config-overrides.js to the project root directory.(NOT ./src)
// config-overrides.js
module.exports = function override(config, env) {
// New config, e.g. config.plugins.push...
return config
}
Set your variables in AWS Amplify with your key and variable, pretty self-explanatory.
In your build settings make it look something like this (I personally don't add npm build in here but you can if you need to.)
frontend:
phases:
build:
commands:
- EXAMPLE_API_KEY_1=${EXAMPLE_API_KEY_1}
- EXAMPLE_API_KEY_2=${EXAMPLE_API_KEY_2}
Start or restart your build.
I used #leandro's answer and mixed in an answer from this question to get it to work for me.
This worked for me to deploy React to Amplify
amplify.yml
version: 1
frontend:
phases:
preBuild:
commands:
- npm install
build:
commands:
- npm run build
artifacts:
baseDirectory: build
files:
- '**/*'
cache:
paths:
- node_modules/**/*
in App.js
const client = new ApolloClient({
uri:
process.env.NODE_ENV !== 'production'
? 'http://localhost:1337/graphql'
: process.env.REACT_APP_ENDPOINT,
cache: new InMemoryCache(),
});

Docker Hostnames not resolving in next.js prod but working in dev mode (Error: getaddrinfo ENOTFOUND)

I'm running a next.js react app in a docker container. It's being composed with several other contains: one running Ghost (I'm using the API), one running mysql, and one running NGINX. I've got everything running in development mode.
It works perfectly when run using next dev. But when I run it by doing next build and next start, I start seeing errors like Error: getaddrinfo ENOTFOUND ghost-api when I try to make server-side HTTP requests to my Ghost API container. I'm not entirely sure what the issue is but it seems like there's some issue with how Node is making requests after being built. I've been digging through a lot of Docker/Node questions trying to figure this one out but haven't had any luck.
The entire project can be found here: https://github.com/MichaelWashburnJr/react-cms
The problem may exist in the environment variable that you are using. In both getGhostApi and getGhostApiKey function, you are using the environment variable.
In NextJs you'll have to specify a next.config.js in which you define the variables that you need for
Ex. next.config.js
module.exports = {
serverRuntimeConfig: {
// Will only be available on the server side
mySecret: 'secret',
secondSecret: process.env.SECOND_SECRET, // Pass through env variables
},
publicRuntimeConfig: {
// Will be available on both server and client
staticFolder: '/static',
},
}
You can also refer to the next documentation for the same.
https://nextjs.org/docs/api-reference/next.config.js/runtime-configuration
I'm not able to reproduce the error. How are you starting the frontend container in prod mode?
From the error it appears like you might be trying to start the frontend container or the frontend app as a separate process without starting it as part of the compose project. If that is the case, the name ghost-api won't be resolvable and you would get the Error: getaddrinfo ENOTFOUND ghost-api error.
I've changed the command key of frontend container as follows:
command: [ "yarn", "start-prod" ]
Changed the "start-prod" script in frontend/package.json as follows:
"start-prod": "next build && NODE_ENV='production' next start"
and everything worked as it worked in dev mode. I got some UNKNOWN_CONTENT_API_KEY error in both dev and prod mode but definitely there is no ghost-api name resolution error.
After cloning your repos:
$ grep -R ST_API *
frontend/.env.development:GHOST_API_URL=http://ghost-api:2368
frontend/.env.production:GHOST_API_URL=http://ghost-api:2368
frontend/src/constants/Config.js:export const getGhostApi = () => process.env.GHOST_API_URL || 'http://localhost:8000';
ghost-api is not a domain name: to make it work you need to edit your hosts file or (for a real production environment) to change http://ghost-api:2368 in frontend/.env.production file with the real deploy domain name.
If you are asking why you can't trust on docker compose networking, the answer is: you can, but only in the containers; while the front end will run in the browser of your application client, which is outside the containers.
Hope this helps.
It seems that Docker's hostname resolution does not work during build time. That is why ghost-api is not found.
Instead of referencing the other container by its name (ghost-api), on Mac you can try host.docker.internal. On Linux, using host networking during build worked for me:
nextjs-app:
build:
network: "host"
# ...
network_mode: "host"
This way, you can reference the other container using localhost.

Please ensure that your service worker file contains the following:/(const precacheManifest =)\[\](;)/

I am quite new to react React workbox. I am trying to make my Electron react App have the ability to cache all images and data to be made available while it is offline.
This is exactly what I am trying to accomplish as in this youtube video. from 14:00 to 21:00 minutes: Building PWAs with React and Workbox, /watch?v=Ok2r1M1jM_M
But this command is giving
"start-sw":"workbox injectManifest workbox-config.js && workbox copylibraries build/ && http-server build/ -c 0"
This error:
C:\Users\rajesh.ram\Desktop\Day\K\demok\client>npm run start-sw
> client#0.1.0 start-sw C:\Users\rajesh.ram\Desktop\Day\K\demok\client
> workbox injectManifest workbox-config.js && workbox copylibraries build/ && http-server build/ -c 0
Using configuration from C:\Users\rajesh.ram\Desktop\Day\K\demok\client\workbox-config.js.
Service worker generation failed:
Unable to find a place to inject the manifest. Please ensure that your service worker file contains the followin
g:/(const precacheManifest =)\[\](;)/
Please help me fix this or suggest alternative packages/repositories/videos to make it possible.
In newer workbox versions including 5.1.3 current at time of this post , the parameter which specifies the injectionPoint for the precacheManifest has changed from regex to string. The name of the parameter has also changed and as far as I can tell this is not backwards compatible...meaning it doesn't work to use the regex anymore.
module.exports = {
"globDirectory": "build/",
"globPatterns": [
"**/*.{json,ico,html,png,js,txt,css,svg}"
],
"swDest": "build/sw.js",
"swSrc": "src/sw.js",
"injectionPoint": "injectionPoint"
}
Changing that parameter as per above worked for me following the rest of the video.
Then several other updates affected how sw.js is written also...
importScripts("workbox-v5.1.3/workbox-sw.js");
workbox.setConfig({ modulePathPrefix: "workbox-v5.1.3/" });
const precacheManifest = [injectionPoint];
workbox.precaching.precacheAndRoute(precacheManifest);
You have to remove the .supressWarnings() command. It has been removed. A good video...needs some updates.
Link to the presentation github which needs an update so...
https://github.com/mikegeyser/building-pwas-with-react
Link to the manual: https://developers.google.com/web/tools/workbox/reference-docs/latest/module-workbox-build
#MegPhillips91
By changing the parameter of precacheAndRoute as below it worked for me
workbox.precaching.precacheAndRoute(self.__WB_MANIFEST);
If you're following the video strictly, make sure that the custom sw.js file that you create in the src folder is exactly:
importScripts("workbox-v4.3.1/workbox-sw.js");
workbox.setConfig({ modulePathPrefix: "workbox-v4.3.1/" });
const precacheManifest = [];
workbox.precaching.suppressWarnings();
workbox.precaching.precacheAndRoute(preCacheManifest);
and workbox-config.js
module.exports = {
globDirectory: "build/",
globPatterns: ["**/*.{json,ico,html,png,js,txt,css}"],
swDest: "build/sw.js",
swSrc: "src/sw.js",
injectionPointRegexp: /(const precacheManifest = )\[\](;)/
};
make sure the workbox version matches the version you have in the video he uses 3.6.3 but now its 4.3.1.....hope this helps.

Unexpected token import - using react and node

I'm getting an error when running my react app: Uncaught SyntaxError: Unexpected token import
I know that there are a plethora of similar issues on here, but I think mine is a little different. First of all, here is the repository, since I'm not sure where exactly the error is: repo
I'm using create-react-app, and in a seperate backend directory I'm using babel (with a .babelrc file containing the preset es2015). The app worked fine until I added another file in a new directory in the backend folder (/backend/shared/validations/signup.js).
I was using es6 before that too, and it was working perfectly fine. First I thought it was some problem with windows, but I cloned the repo on my Ubuntu laptop and I'm getting the same error there.
Some things I tried already:
Move the entire folder from /backend to the root folder
Move just the file (signup.js) just about everywhere
So no matter where the file is, the error stays the same. If I remove the entire file and all references to it the app works again.
I think this error is pretty weird, considering I'm using es6 everywhere else in the app without trouble. It would be great if anyone could help me with this error.
edit: If you want to test this on your own machine just clone the repo and run npm start in the root folder (and also npm start in the backend folder, but that isn't required for the app to run, or for the error to show up).
That's what's happening:
Your webpack is set to run babel loader only in the src folder (include directive).
To change that, one approach is:
1) extract webpack configuration with npm run eject (don't know if there is another way to override settings in react-create-app). From the docs:
Running npm run eject copies all the configuration files and the
transitive dependencies (Webpack, Babel, ESLint, etc) right into your
project so you have full control over them.
2) in config/paths.js, add an appShared key, like that:
module.exports = {
/* ... */
appSrc: resolveApp('src'),
appShared: resolveApp('backend/shared'),
/* ... */
};
3) in config/webpack.config.dev.js, add the path to the babel loader, like that:
{
test: /\.(js|jsx)$/,
include: [ paths.appSrc, paths.appShared ],
loader: 'babel',
/* ... */
},
It works now!

Vue.js Webpack Template in a Docker Container: How do I add Webpack-Dev-Server --watch-poll flag?

I am running the webpack / webpack-dev-server portion of the base Vue.js Webpack template (https://github.com/vuejs-templates/webpack/) inside of a docker container I created. The container also contains the vue CLI in order to create new projects (you can get my container here if you want: https://hub.docker.com/r/ncevl/webpack-vue/).
Hot-reload does not work after moving from the webpack-simple template to this one.
Everything was working using the Webpack-Simple template which you can clone / see over here: https://github.com/vuejs-templates/webpack-simple
I was able to get the simple template running (with hot-reload working as intended) with the following webpack-development-server launch command:
webpack-dev-server --hot --inline --progress --host 0.0.0.0 --watch-poll
That said the full (not simple) version of the webpack template does not appear to use a webpack-dev-server launch command and instead appears to use additional middleware as referenced in build/dev-server.js (https://github.com/vuejs-templates/webpack/blob/master/template/build/dev-server.js) and the webpack dev config.
Since the --watch-poll was the key to getting the WDS hot-reload functionality to work within a docker container in the last project, my thinking is that I need to do something similar with the webpack-hot-middleware but I dont see anything in their docs (over here: https://github.com/glenjamin/webpack-hot-middleware) that talks about changing to a polling based approach.
I am not 100% sure the polling flag will do the trick since I can see the container recompile my source when I make a change. I can also see the change in my browser if I refresh it manually.
Whats stranger still is if I inspect my page in browser within chrome dev tools, and then head over to network / XHR I can see that the browser actually does receive information from the webpack-dev-server, but visually it does not update.
Give the above I assume websockets (or socket.io which I think is used) are working and communicating between the browser and the WDS so maybe this is a browser caching issue of some sort?
I checked in my console and found this so it is looking like a header issue:
For reference the text error from that image (to make it easier for anyone having the same issue to find this post) is:
EventSource cannot load http://__webpack_hmr/. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://0.0.0.0:8080' is therefore not allowed access.
Again the Hot-Reload / Hot Module Reload was working with this identical container setup when using the webpack-simple Vue.js template.
I am wondering if anyone has run into anything similar or has any ideas on how to add the polling option . I guess my alternative would be roll back to a more basic webpack config and rebuild that portion of things to use the traditional webpack-dev-server / webpack config but give the above I am not sure that is going to fix it.
I am adding this as a separate answer since it more specifically answers the question in the title, while my other answer more specifically explains what solved my actual problem.
The vue.js webpack template project (which can either be init'd from the Vue CLI or pulled from its repo over here: https://github.com/vuejs-templates/webpack) separates its config files into several different directories.
I am posting this answer so that anyone who runs into the need to add polling to their project will be able to understand how / where to do that.
The base project structure for a Vue.js webpack template project looks like this:
The files that you care about if you are messing with trying to get hot module reload working are related to creating your server primarily with webpack-dev-middleware. The most important files related to that are highlighted here:
Basically if you want to add the polling code to the webpack-dev-middleware server you need to be in the /build/dev-server.js file on lines 20 to 24 that look like this:
var devMiddleware = require('webpack-dev-middleware')(compiler, {
publicPath: webpackConfig.output.publicPath,
quiet: true
})
To add polling you would add it just before or after quiet: true. As a side note, if you are having trouble with HMR I would change "quiet:true" to queit false to get a more verbose read out of whats going on from webpack-dev-middleware. I have included verbose and polling modifications to the above code here:
var devMiddleware = require('webpack-dev-middleware')(compiler, {
publicPath: webpackConfig.output.publicPath,
quiet: false, //Changed to for additional verbosity
watchOptions: { //Add Polling
aggregateTimeout: 300,
poll: 1000
}
})
My other answer is in regards to what ended up solving my problem, not necessarily how to actually add polling (which might be necessary for someone else but did not end up being needed to make my dockerized setup work).
It should also be noted that sometimes when HMR (webpack hot module reload) is not detecting changes it is due to the fact that webpack-hot-middleware or webpack-dev-middleware is running into an issue whereby some invisible characters are / were added to the name of the base project directory (probably by someone building the base Vue project) and therefore webpack on certain OSes is not able to see the changes.
If that happens to you and you are on OSx or running webpack inside of a docker container and you can't get HMR to detect changes, try to rename your vue-webpack project directory and it should work.
Ok. So I can't really take credit for this one since it was actually answered by Discuss user Cristian Pallarés over here: http://webpack.github.io/docs/webpack-dev-server.html#combining-with-an-existing-server
Christian says:
I was just trying the same. I just use "php artisan serve" on localhost:8000, and Webpack Dev Server on localhost:3000. You should make this:
set your webpack config "output.publicPath" as "http://localhost:3000/static/" instead of "/static/"
make your php application load this:
The key is the output.publicPath being absolute. Now, you should run "php artisan serve" and launch your webpack dev server too (in my case I use gulp).
Basically I took that and dug through the Vue.js Webpack Template files to locate the config file where webpack was looking for the public path. the public path setting ended up being in the index.js file located in the /config directory of the template.
I changed my code to look like this:
assetsSubDirectory: 'http://localhost:8080/static/', //!!Changed from /static/
assetsPublicPath: 'http://localhost:8080/', //!!Changed from /
As opposed to the previous setting which DID NOT WORK and looked like this:
assetsSubDirectory: '/static/',
assetsPublicPath: '/',
After that I was able to see my changes hot reload while running the vue.js Webpack template from within my docker container.

Resources