Vars living medium in an isomorphic reactor

I created an isomorphic React application based freely on the starter kit in this repo . It uses webpack to create production code.

Thing is, I need to set the value of several environment variables on the server for client code in the browser without rebuilding production code. I want to be able to change the value of env vars, and get the client to refresh the next page without rebuilding anything. And I don't want to complicate testing to do this.

I found several solutions, none of which are great:

  • Use DefinePlugin for webpack to hard-code the value of certain environment variables in production code. Similar to what is described here
  • Create an API to pull env variables into the client.
  • Write a special .js file that is outside the webpack system. This file will be templated so that it is modified before it is served by the client. It is probably required that the values ​​of the env variable be stored in special global variables in a "window" or something like that.

Problems with these approaches:

  • REJECTED. It just doesn't do what I want. If I change the value of the env variable, I need to rebuild the code.
  • Not necessarily complicated. I do not need this API for anything else. Is the whole API just for serving 2 or 3 values ​​that rarely change? Complexity is required to ensure that values ​​are pulled from the API as soon as possible at boot time.
  • Nearest, but curious. I do not want to go beyond the webpack / React / Flux system if I can avoid this. Creating special global variables in a window object will work, but it will introduce complexity for testing components / stores / actions that use these global variables.

In the past I did 2 and 3 and was never really intellectually satisfied with these decisions.

Any suggestions? This seems to be a common / resolved issue. Maybe I just overdid it, and 3 is the way to go.

+6
source share
3 answers

So the solution that I came up with is pretty simple. I just wrote single line javascript to save the value for local storage in a script tag. Then read this local storage from my flex storage when starting the application.

This is the corresponding tag added to index.html:

<script type="text/javascript"><%= config %></script> 

This is the line that I insert in index.html using templates before serving it:

 let configJs = 'localStorage.setItem(\'ADMIN_API\', JSON.stringify(\'' + process.env.ADMIN_API + '/v3/' + '\'));'; const html = template({config: configJs}); res.status(200).send(html); 

Then I read it with this as soon as the application starts:

 import ls from 'local-storage'; .... let api = ls.get('ADMIN_API'); 
0
source

Using a plate with express cubes, you can give the server variable env to the client using the expression "local".

 var serverVariable = 'this is a server variable' app.get('/somelink', function (req, res, next) { res.locals.data = { FluxStore: { serverlocal: serverVariable } } next() }) 

Then you pass the local one either through React.renderToString, which will be selected by FluxStore on the client. In another method, you can use the data fetching api, for example falcor, which can be selected by the Action Store client file via falcor-http-datasource, you do not need express-local for falcor, which you create using falcor-express and falcor-router

+2
source

This uses the global window variable in window to pass values, but gives you a universal interface for accessing values ​​in the browser and node.

In publicEnv.js :

 // Env variable to push to the client. Careful on what you put here! const publicEnv = [ 'API_URL', 'FACEBOOK_APP_ID', 'GA_ID' ]; // These 2 lines make sure we pick the value in the right place on node and the browser const isBrowser = typeof window !== 'undefined'; const base = (isBrowser ? window.__ENV__ : process.env) || {}; const env = {}; for (const v of publicEnv) { env[v] = base[v]; } export default env; 

In the HTML page template file, I have:

 import publicEnv from 'publicEnv.js'; ... <script> window.__ENV__ = ${stringify(publicEnv)}; // Other things you need here... window.__INITIAL_STATE__ = ${stringify(initialState)}; </script> 

So, now I can get the values ​​of env variables for both frontend and backend with:

 import publicEnv from 'publicEnv.js'; ... console.log("Google Analytic code is", publicEnv.GA_ID); 

Hope this helps.

0
source

All Articles