Where is the variable named "global" coming from - reactjs

I am refactoring a React 15 application (built with Webpack 2 and Babel) and I have noticed a lot of references to a global variable called global e.g. global.location. It's an alias for window, but I cannot find any code or configuration where the assignment occurs.
The Chrome devtools console can't access global so it is contained inside the modules that webpack generates. It's a very overloaded search term and I haven't had any luck tracking it down on Google.
Where is global coming from? Is there any benefit using it in a web application over window?

The global variable is handled specially by Webpack, not by Babel. Webpack's configuration file may contain a node section, which controls the polyfilling of various node objects, like global. Unless otherwise specified, global will be rewritten by webpack to mean window.
Example webpack.config.js turning off global rewriting:
module.exports = {
node: {
global: false
}
}
Documentation from project wiki.

Related

How to have Nx environment variables in React app per environment?

Context
I have a three projects inside my Nx workspace, two applications which are react apps (both of them have shared logic, however they are intended for different platforms web and microsoft teams and must be separated) and a library which contains logic for an api client, which both of the applications use.
The api client project requires the variable base URL which is environment specific.
I can define environment variables and introduce file replacements in the build process for .ts files (e.g. environment.ts is replaced with environment.production.ts, when configuration is production), however I do not want to reference this file (environment.ts) in the api client project so as not to introduce two way dependencies.
What have I tried
From the api project I was not able to extract the logic which depends on the URL variable as this is tied to some code generation which is changeable.
I succeeded in providing this variable by using .env file in the root of the application project, the variable is in the format NX_MY_URL, and could be accessed with process.env.NX_MY_URL.
However I was not able to change this variable when changing the build configuration (e.g. development, test, production). I have tried adding a fileReplacements task such as
"configurations": {
"development": {
"fileReplacements": [
{
"replace": "apps/ra-web/src/environments/environment.ts",
"with": "apps/ra-web/src/environments/environment.development.ts" //<----- This works fine
},
{
"replace": "apps/ra-web/.env",
"with": "apps/ra-web/.development.env" //<----- This does not work, .env values remain
}
],
Question
How can .env files be replaced based on Nx target's configuration?
Why the mentioned approach does not work?
The reason of why the fileReplacements approach is not working is because those replacements are meant for the building process, which is the bundler the one in charge (webpack or vite, etc). That file content replacement is actually working, yet it doesn't happen at file system level but at memory level (for the bundling process). As your application code does not "import" that .env file (and you should not directly depend on it), then those file replacements make no difference in the build output.
On the other side, Nx is in charge of reading the .env file (at file-system level) and loading the data as environment variables so that when the bundling process starts, those are available. This a completely separate process than the fileReplacements done by the bundler.
How to achieve what you are looking for?
If you think about projects in libs as shareable/re-usable code, then you can imagine those are external dependencies added to your apps (or other libs). As those dependencies are external, they should rely on their implementor to get the data needed for them to work.
Having the above in mind, your lib public API (the main index.ts file) should be parametrized to receive that base URL that will depend on each application. With that you can keep working with the environment.ts file replacements, get the value in the app and pass it down to the lib.
Example:
// app's main.tsx
import { environment } from './environments/environment';
import { apiClient } from '#myorg/api-client';
apiClient.init({ baseUrl: environment.baseUrl });
// api-client's index.ts
export { apiClient } from './lib/api-client';
// api-client's api-client.ts
export const apiClient = {
init: ({ baseUrl }) => { ... }
};
If you still need to work with the .env file (not trying to replace it), just the the env vars in the environment.ts as work with it as mentioned above.

How to get environment variables in the aAPI side from the UI?

React noob here. I'm currently migrating an app from Next.js to React.
In Next, we had certain environment variables (such as root URLs) defined in our Jenkinsfile that would be called from our UI via process.env.[var].
Now that we're migrating to React, I can't use process.env in the UI side, as this is a Node property. I also can't store these environment variables on the API side and call them from the UI side, as React doesn't allow references to be made outside the UI's /src directory.
Is there a way to use our environment variables (defined in Jenkinsfile) from our UI? I'm considering creating a GET endpoint in the API side to return the environment variables to the UI when it loads, but would like to know if there are any alternative solutions.
Probably obvious, but here's the basic layout of our app
-api
-src
-ui/react
-src
-utils
constants.js <- trying to store the env vars here
jenkinsfile
Technically, we can't use environment variables in browser context, that's why we usually use DefinePlugin or EnvironmentPlugin in webpack based projects like CRA and Vue-CLI to statically replace process.env.* with environment variables.
But this way will forces us to rebuild the whole application multiple times for different stages.
To fix this, without compromises., I recommend trying import-meta-env.
During production, this plugin statically replaces import.meta.env.* with placeholders (we use import.meta because process.env is a Node specific object), then we can run the built-in script and replace the placeholders with real environment variables later.
I also created an example for Docker. For Jenkins, I think it can be done in the same way.
Hope this helps someone who needs it.
If you are using create-react-app you can define your env variables in the .env file, just prefix them with REACT_APP_.
If not, you can use build tools like webpack to add them for you

Gatsby, Environment variables not accessible in browser

I want to use environment variables. I created .env.development file and I put some variables. Then I include the dotenv plugin to read the variables in gatsby-config.js:
require('dotenv').config({
path: `.env.${process.env.NODE_ENV}`
});
The content of my .env.development:
GATSBY_APP=MYAPP
It's working in gatbsy-node.js but in browser (REACT) it's empty. I display console.log(process.env) and it return empty object.
Even if I install and configure gatsby-plugin-env-variables.
It looks like you're combining two approaches, and that might be where you're running into trouble.
Gatsby comes out-of-the-box with support for defining environment variables in environment-specific .env.[environment] files (e.g. .env.development), provided these files are in the root of your project (i.e. your-project/.env.development). Documentation for this feature. You do not need to install or configure dotenv for this to work.
Another approach is to use dotenv, which will allows you to use a general .env file. You need to then import and configure the tool, which is generally done at the very top line of gatsby-config.js and looks like this:
require("dotenv").config()
Note that you do not specify the environment name (e.g. development) in this scenario, and you would not commit the .env file to your repository.
The other issue you might run into is that part of your code runs server-side, using Node, and part runs client-side (in the browser). Since process.env is only available in Node, Gatsby does some additional work to make it available in the browser. We don't want all of these variables, which frequently hold secrets, to be provided to the browser, though, so Gatsby only copies over those that whose names begin with GATSBY_. Finally, as a side effect of the way that these variables get copied over, you must explicitly reference them for your build to work:
// this is okay everywhere
const GATSBY_APP = process.env.GATSBY_APP
// this won't work in code that runs client-side, but will work
// in `gatsby-node.js` and other files that only run in Node
const { GATSBY_APP } = process.env
If you wanted to whitelist your own environment variables, either as a prefix (shown here) or have a list of them, you can add something like this in the gatsby-node.js file:
exports.onCreateWebpackConfig = ({ actions, getConfig }) => {
const config = getConfig();
// Allow process.env.MY_WHITELIST_PREFIX_* environment variables
const definePlugin = config.plugins.find(p => p.definitions);
for (const [k, v] of Object.entries(process.env)) {
if (k.startsWith("MY_WHITELIST_PREFIX_")) {
definePlugin.definitions[`process.env.${k}`] = JSON.stringify(v);
}
}
actions.replaceWebpackConfig(config);
};
I was running into the same issue and just found out what I was doing wrong. It looks like you're doing the same thing.
The explanation both the documentation and #coreyward give are correct, however, note that while corey implies they're two different approaches and the issue might be that they're conflicting, they're not, they do different things - so that code of yours is fine.
What's wrong, though, is that you're console logging process.env. And as it turns out, this will always output an empty object even though the variables might be there.
You have to console.log(process.env.GATSBY_APP) directly to see any value.
(Reference)
This is essentially an extension of what Corey pointed out in his "finally as a side-effect" section, however, the way he's written it implies it's an issue with destructuring - but it's not limited to that.
In my case, I was doing the above error AND not exposing the variables with GATSBY_ properly, then while testing I started logging the whole env object like you while I searched for the cause. This meant that even after I added the correct GATSBY_ prefix I still couldn't see anything.
So in short, it's probably only your console.log line that's an issue - access the variable directly, not the env object as a whole.
The Gatsby site as a well documented section on working with environment variables. The gist is that the environment variables are only available during build time when the internal nodejs server is server rendering your site. In order, get those environment variables in the browser you need to programmatically embed them using the special gatsby-*.js files. The example they provide seems to be close to what you want to achieve.

Importing Google Maps API JS file with React

I'm trying to integrate the polygon containsLocation function into my react app. This currently appears to only be supported by the actual JS library imported with the maps.googleapis.com script tag added. That being said, I keep getting the no-undef error when attempting to use the maps.Polygon constructor (I'm currently using create-react-app with the default settings). Is there anyway to prevent this from happening?
Code causing the issue:
var addedPoly = {
polygon: maps.Polygon({
paths: parsedCoords
})
}
create-react-app uses Eslint in order to lint your code. Given you've included the google maps library through a script tag, it is available globally, while create-react-app (with its eslint configuration) doesn't expect globals, unless they are declared as such.
You can see in eslint documentation the no-undef error
There are a couple of choices to fix this issue. First, if it is global, it will be available through window variable.
const maps = window.maps;
That way, it becomes a local variable.
Otherwise, you could add a .eslintrc file (if it does not exist already), where you set maps as global
"globals": {
"maps": true
}
last, but not least, you could add at the top of your file the following comment
/*global maps*/
which will also work.
The advantage of the second option over the others is that you only need to implement it once, the other two options imply changes in each file where maps is used. It is up to you

Fallback for webpack external libraries

Is there a way to specify a fallback for webpack external, for example if I can't find angular then try to search for it in your node_modules?
You can reference parts 2 of the answer to this Webpack question.
You can use the provide plugin and set an alias for the global. As stated:
Most legacy modules rely on the presence of specific globals, like jQuery plugins do on $ or jQuery. In this scenario you can configure webpack, to prepend var $ = require("jquery") everytime it encounters the global $ identifier.
The angular global will be treated the same way. Therefore if you don't have angular in node modules but loaded via external script, Webpack will allow you to use it the same way as if it was living in your node modules.

Resources