2

I am using PKG, to make a executable .exe file for my Appolo GraphQL Server + React client bundled all into one exe file. It's working, and now there is requirement: app should read from somewhere an IP address and use it as constants for host, port, etc.

From server side I am using fs.readFileSync - which is okay. I can read any text file as it's nodejs server side. And now the requirement is to pass that IP to the client files -> into the static folder (marked *), where I have constant.js with IP of client to connect inside (compiled static/js..). Server side files (NodeJs+React):

├───build
│   └───static
│       ├───css
│       ├───*js*
│       └───media
├───config
├───src
│   ├───core
│   ├───graphql
│   ├───guardServer
│   └───pg
└───SSL

Client React files tree:

├───.idea
├───.vs
│   └───React
│       └───v16
├───build
│   └───static
│       ├───css
│       ├───js
│       └───media
├───public
└───src
    ├───components
    │   ├───core
    │   │   ├───functions
    │   │   └───modal
    │   └───modules
    │       ├───account
    │       ├───adminPanel
    │       │   └───pages
    │       ├───archive
    │       ├───hr-department
    │       │   └───pages
    │       ├───logs
    │       ├───monitor
    │       └───reports
    ├───config
    └───images

So my actions are: npm run build a clent. Then I taking the folder build and replacing a server side files: server/build folder. Then I'm doing on the server side - npm run build and receiving an exe file. WHERE a server part (/server/index.js) of this exe can read a settings.txt, but not that part (client) which is inside /server/build/static/js...

My question is: is it possible by modifying webpacker somehow, and server environment variable will be accessible (and will be dynamic) from client side with command process.env.myvar?

If not, if there are any tricks I can utilize in this case? Please note that PKG's fs.writeFileSync is now allowed due to the filesystem shapshot restriction.

Code of server side:

let fileContent = fs.readFileSync("D:\\settings.txt", "utf8");
let getIp=JSON.parse(fileContent); //fine working, got IP

Client using Apollo Client and exactly for him I need to pass that IP from server side, any ideas please?

Update for Ajeet Shah. What I did:

On my server.js - var __SERVER_DATA__ = "192.168.0.111";

in index.html of client - <script>
      window.SERVER_DATA = __SERVER_DATA__;
    </script>

in index.js of client - console.log(window.SERVER_DATA);

Update:

I think I will end up for a while with the tiny http server, which will run on localhost:port. And from there I can freely read any settings. Thank you All for usefull answers.

I've chosen the answer with more options and there was advise about localStorage. Thank you all much for heads up. Still trying to implement offered methods.

Update.

I've finishied doing this. I've used an html variable window.SERVER_DATA = __SERVER_DATA__ as described here - https://create-react-app.dev/docs/title-and-meta-tags/#injecting-data-from-the-server-into-the-page. I will decide later on what to do with best answer, if nobody will post extra ones.

noszone
  • 190
  • 1
  • 14
  • Could you please show a simple example? I can't reproduce server variable on client side. I got undefined. – noszone Apr 01 '21 at 11:42
  • Because of many offered options, I am learning them and trying to implement, also yours. I did a tiny http server, but the bad thing inhere that it's usefull only for localhost. In my case the host url is allways unknown. For example in you method I can't access the url due of this fact. – noszone Apr 05 '21 at 09:19

2 Answers2

1

As described in docs, you can create server side variables that can be injected in your front end code.

Here is what you need to do:

  1. Create a JS script, say myConfig.js, and place it on the server at a public location so that frontend can load it.
  2. Define config data in this file, e.g:
const myConfig1 = "foo bar"
const myConfig2 = "anythng else"
  1. Add below lines in the <head> section of index.html file in your frontend app. It will read load/data from the server and set those in global window object.
<script src="http://path/to/file/on/server/myConfig.js" type="text/javascript"></script>
<script>
  window.myConfig1 = myConfig1
  window.myConfig2 = myConfig2
</script>
  1. Now you can access those config vars (which came from server) in your ReactJS app using global window object as window['myConfig1'] and window['myConfig2'].

Using this method, you don't need to rebuild the frontend app using npm run build when you change your config vars as these are defined, separately from frontend, on the server. To change these config vars, you just need to change those on the server and do a refresh in browser.

Ajeet Shah
  • 18,551
  • 8
  • 57
  • 87
  • Thank you for answer, I think your solution isn't dynamic, I am unsure fully. Imagine the schema: D:\settings.txt=>react nodejs server side files. React client<=react nodejs server<=D:\settings.txt. The IP address in the settings.txt can be changed anytime and I need to pass it to both server and client side. Additional requirement is that all these files are packed to *.exe and write operaions are unavailable. However, I am trying to make to do a const myConfig1 = "foo bar" to be a const myConfig1 = some var linked with settings.txt. I will add also a full client tree to the Q area. – noszone Apr 02 '21 at 03:38
  • 1
    Although this answer isn't 100% describing the way of usage dynamic NodeJS, it's most correct answer to use as guidance idea. – noszone Jun 14 '21 at 11:28
1

In backend technologies, everything is solved with environment variables which is a good practice when you have to move your app through stages( dev, staging, prod).

In client side technologies( react, vue, angular or simple js) the obtainment of these values dynamically is complicated.

Check this answer to understand how variables work in js client side or how to inject dynamic values

https://stackoverflow.com/a/54271114/3957754

REACT_APP

One strategy is use the REACT_APP variables

https://create-react-app.dev/docs/adding-custom-environment-variables/

So if you create this variable in your server side

export REACT_APP_remote_ip

React library will create a variable for you. You can use thia var in any react file

process.env.remote_ip

Webpack

Similar to REACT_APP webpack offer an option to expose server side variables as global javascript variables ready to use in any .js file

new webpack.DefinePlugin({
  API_BASE_URL: JSON.stringify(process.env.API_BASE_URL)
})

/settings

Another option is to create an endpoint in your nodejs server side. This endpoint has access to the environment values, so you can return anything you want:

res.json({
  "ip1": process.env.remote_ip_1
});

After this, you just need to call or invoke this endpoint /settings in the most early js or entrypoint of your react or javascript files.

Finally, the return of /settings could be exposed as global javascript values or stored in localstore of browser

JRichardsz
  • 14,356
  • 6
  • 59
  • 94
  • Thank you for anser. I updated the Q with notes. My situation is complicated due of exe file. – noszone Apr 02 '21 at 06:09
  • 1
    If your solution was hardcoded **var __SERVER_DATA__** in your client side js, I think **webpack.DefinePlugin** is the solution for you because you are able to use **fs.readFileSync**. In another way, when you run your .exe what should happen? Start your express (nodejs & server side) with some endpoints which render a web page using react (js client side) and use some graphql operations ? – JRichardsz Apr 02 '21 at 17:16
  • Yes, it's like you described. After running exe a cmd window appears. Then you can go to browser and type IP 192.168.0.34 and you are seeing the page apollo-cleint, express-js as herein in index.js (no space here, updated Q). – noszone Apr 05 '21 at 03:12