read environment vars in a simple react app - reactjs

I create an app with create-react-app module, and in a component, I'm trying to read an env. var, like this
<p style={textStyle}>Environment: { process.env.AWS_ENV || process.env.NODE_ENV }</p>
I start the app with AWS_ENV=live npm start and it never reads this var. the result is always development. I noticed tho, if I build the app with npm run build, the output will be production, but anyway I cannot read the AWS_ENV var

create-react-app using https://github.com/motdotla/dotenv. To load ENV into Webpack and to pass it in browser, run this commands in console:
echo -e 'REACT_APP_AWS_ENV=live' > .env
npm start
Note REACT_APP_ prefix special to create-react-app.
Then in your components:
...
{ process.env.REACT_APP_AWS_ENV }
...

you should set AWS_ENV var in your webpack.prod.js.
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('production'),
'AWS_ENV': JSON.stringify('live npm start')
}
}),

Related

Environment variables Laravel Mix in Docker

We have a Laravel 8 application with Laravel Mix 6.0.49 and a React frontend. The application runs inside a docker container in production and development. Up until now, the frontend was compiled outside the docker container for some reason, but since we are moving to a fully dockerized environment, we are required to call the frontend scripts from inside the container. This all works fine, except for an environment variable we are setting in package.json, which allows us to pass the version of the app as a mix variable. Here is the current setup:
// package.json
"version": "0.1.1",
"scripts": {
...
"watch": "cross-env APP_VERSION=$(node -pe 'require(\"./package.json\").version') mix watch",
...
// .env
...
MIX_APP_VERSION="${APP_VERSION}"
...
// MyComponent.jsx
...
<div>version {process.env.MIX_APP_VERSION}</div>
...
The environment variable worked fine when the watch script was called outside the docker container.
Has anyone any idea of why it suddenly does not work anymore? I'm open to other ways of approaching this too.
I fixed this issue in the end by removing the variable related stuff from package.json including the cross-env dependency and setting the environment variable through the webpack config instead (webpack.mix.js)
...
.webpackConfig({
plugins: [
new webpack.DefinePlugin({
'process.env.APP_VERSION': JSON.stringify(
process.env.npm_package_version,
),
}),
],
})

How can I exclude React Refresh from the Create-React-App production build?

Uncaught Error: React Refresh runtime should not be included in the production bundle.
By default, when you do a npm run build, it changes the environment to 'production'. After looking at react-refresh, if the environment is in production, it throws an error that it shouldn't be included.
I have setup a .env file with these environment variables but when I build and serve it locally, I still get the issue. After reading up on the issue, I noticed that setting the environment variables should resolve the issue but it is not working for me.
FAST_REFRESH=false
REACT_APP_FAST_REFRESH=false
Can someone please help me with this issue?
Inbabel.config.js, you should add:
const isEnvDev = process.env.NODE_ENV === 'development'
if (isEnvDev) {
config.plugins.push('react-refresh/babel')
}
Inwebpack.config.js, you should add:
const isEnvDev = process.env.NODE_ENV === 'development'
if (isEnvDev) {
config.plugins.push(
new ReactRefreshWebpackPlugin({
overlay: false,
}),
)
}
and theconfig.pluginsis webpack's config

Environment variables in manifest.json - Chrome Extension

Is it possible to set environment variables in the manifest.json file of a Chrome Extension?
Like wOxxOm said, I used webpack to proccess manifest.json.
In my case, I needed to set version automatically on manifest file.
I added to webpack script:
plugins: [
new CopyWebpackPlugin([
{
from: "public/manifest.json",
to: "manifest.json",
transform(content, path) {
return modify(content)
}
}
]),
]
And the modify function replaces version on file for the parameter:
function modify(buffer) {
var manifest = JSON.parse(buffer.toString());
let argv = process.argv[2];
if (argv) manifest.version = argv.split("=")[1];
let manifest_JSON = JSON.stringify(manifest, null, 2);
return manifest_JSON;
}
So, I build like "yarn build --version=x.x" and webpack do what I need.
PS: if you're going to use this, remember to change:
the manifest.json directory, if necessary;
the value in the modify function, in my case it was version
As the OP has mentioned in her answer, using the copy-webpack-plugin in the webpack.config.js file is the way to go if you're building your Chrome Extension with React. However, if your React app is based on create-react-app, directly editing the webpack.config.js file (which is located in node_modules/react-scripts/config) is not recommended.
In such a case, use craco, which is an npm package that can be used to customize an app based on create-react-app. Here's how you do it:
Install craco into your project using npm i #craco/craco.
Install copy-webpack-plugin as a dev-dependency in your project using npm i --save-dev copy-webpack-plugin.
Let's suppose we're creating a development and a production build of our Chrome Extension. Let's also suppose we've already assigned "version": "0.1.0" in our Chrome Extension's manifest.json. Depending on the build type, we'd like to assign accordingly the version_name field in our Chrome Extension's manifest.json, e.g., "version_name": "0.1.0 dev" for development and "version_name": "0.1.0" for production. In your React app's package.json, introduce two fields (the script names can be whatever you wish) as follows:
"scripts": {
...
"build-dev": "CRX_ENV=dev craco build", // or "set CRX_ENV=dev&& craco build" in the case of Windows
"build-prod": "CRX_ENV=prod craco build", // or "set CRX_ENV=prod&& craco build" in the case of Windows
...
}
Create a new file called craco.config.js in the root of your project. As per your need, do something similar to the following in the craco.config.js file:
const CopyPlugin = require("copy-webpack-plugin")
module.exports = {
webpack: {
plugins: [
new CopyPlugin({
patterns: [
{
from: "public/manifest.json",
to: "manifest.json",
transform(content, path) {
return modifyManifest(content)
},
},
],
}),
],
},
}
function modifyManifest(buffer) {
const manifest = JSON.parse(buffer.toString())
if (process.env.CRX_ENV === "dev") {
manifest.version_name = `${manifest.version} dev`
} else if (process.env.CRX_ENV === "prod") {
manifest.version_name = `${manifest.version}`
}
const manifestJson = JSON.stringify(manifest, null, 2)
return manifestJson
}
Run npm run build-dev. It will create a folder called build in your project root. This build folder is your unpacked Chrome Extension, which you can load into Chrome using the "Load unpacked" button on the chrome://extensions page. Once loaded, you should be able to see 0.1.0 dev as the version name of your Chrome Extension.
Delete the build folder created from the previous step and run npm run build-prod, and repeat the same steps. You should be able to see 0.1.0 as the version name of your Chrome Extension on the chrome://extensions page.

React analyze bundle size

I have a question - how to analyze bundle size?
I want to get informations how bundle files change in case i will push the commit in gitlab.
I was looking for something like danger.js but it probably doesn't support gitlab.
You can use this script to analyze, without ejecting create-react-app
Put analyze.js in root of your project ( where the package.json is located )
npm install progress-bar-webpack-plugin
npm install webpack-bundle-analyzer
analyze.js
process.env.NODE_ENV = 'production';
const webpack = require('webpack');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const webpackConfigProd = require('react-scripts/config/webpack.config')('production');
// this one is optional, just for better feedback on build
const chalk = require('chalk');
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
const green = text => {
return chalk.green.bold(text);
};
// pushing BundleAnalyzerPlugin to plugins array
webpackConfigProd.plugins.push(new BundleAnalyzerPlugin());
// optional - pushing progress-bar plugin for better feedback;
// it can and will work without progress-bar,
// but during build time you will not see any messages for 10-60 seconds (depends on the size of the project)
// and decide that compilation is kind of hang up on you; progress bar shows nice progression of webpack compilation
webpackConfigProd.plugins.push(
new ProgressBarPlugin({
format: `${green('analyzing...')} ${green('[:bar]')}${green('[:percent]')}${green('[:elapsed seconds]')} - :msg`,
}),
);
// actually running compilation and waiting for plugin to start explorer
webpack(webpackConfigProd, (err, stats) => {
if (err || stats.hasErrors()) {
console.error(err);
}
});
Now simply put node ./analyze.js in the package.json scripts
"scripts": {
.....
"analyze": "node ./analyze.js"
},
after that run npm run analyze
You can also accomplish this using webpack stats json file, supported by create-react-app and webpack-bundle-analyzer.
When running your build with create-react-app, add the --stats flag:
yarn build --stats
This will create a build/bundle-stats.json file, with webpack stats, allowing you to use the webpack-bundle-analyzer CLI to analyze this stats.
yarn run webpack-bundle-analyzer build/bundle-stats.json
reference:
https://www.npmjs.com/package/webpack-bundle-analyzer#user-content-usage-as-a-cli-utility
tested with CRA latest version at the time: v4
You can use and configure webpack-bundle-analyzer library and use it in your React App WITHOUT EJECTING
Add some dependencies by executing npm install --save-dev progress-bar-webpack-plugin webpack-bundle-analyzer
Create a new folder named scripts at the root of your React App.
Create a new file analyze_build_bundle.js in the scripts folder and add the below code in that file
// script to enable webpack-bundle-analyzer
process.env.NODE_ENV = 'production';
const webpack = require('webpack');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const webpackConfigProd = require('react-scripts/config/webpack.config')(
'production'
);
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
webpackConfigProd.plugins.push(new BundleAnalyzerPlugin());
webpackConfigProd.plugins.push(
new ProgressBarPlugin({
format: `analyzing... [:bar] [:percent] [:elapsed seconds] - :msg`,
})
);
// actually running compilation and waiting for plugin to start explorer
webpack(webpackConfigProd, (err, stats) => {
if (err || stats.hasErrors()) {
console.error(err);
}
});
Add the analyze-build-bundle command in your package.json file to run the webpack-bundle-analyzer as below:
"scripts": {
"analyze-build-bundle": "node scripts/analyze_build_bundle.js",
"start": "react-scripts start",
.....
...
}
Now execute command npm run analyze-build-bundle. This will build your app and then start the analyzer local server and you should be able to see the screen as shown in below image

create-react-app .env: process not defined

create-react-app is supposed to inject your .env variables into your React app. I have used the REACT_APP_ prefix with my variables in my .env and .env.development.
However, when debugging the code I've found that process itself is undefined. So when trying to access an environment variable with process.env.REACT_APP_SOMETHING_URL, the root process variable is undefined.
So at the time I misunderstood how process.env works in create-react-app. I expected this to be available at runtime. However, because React is a frontend library and process is a Node backend entity you cannot directly access process.env while executing code in the browser.
This makes sense because in-browser executed Javascript doesn't know about Node; therefore, process.env isn't available.
What happens instead is that during a webpack build, webpack will inject the corresponding environment variables into your frontend asset code. So if you have a production .env file, those variables are provided during the build.
$ yarn add --dev react-app-env
or
$ npm install react-app-env --save-dev
well let me begin by saying process is an eventEmitter what lives in the nodejs world if you log it in a browser, no matter if it is angular, CRA, Vue, jquery all of them will print undefined because in the context of a browser it does not exist.
now on a CRA you is able to use process.env.YOW_VAR, basically bcuz CRA creates an Obj call process.env that is the reason behind why you need to add a prefix to them env vars which I think is REACT_APP.
const YOW_VARS = Object.keys(process.env)
.filter(key => REACT_APP.test(key))
.reduce(
(env, key) => {
env[ key ] = process.env[ key ];
return env;
},
{
NODE_ENV: process.env.NODE_ENV || 'development',
}
);
const s = {
'process.env': Object.keys(YOW_VARS).reduce((env, key) => {
env[ key ] = JSON.stringify(YOW_VARS[ key ]);
return env;
}, {}),
};
more or less they have something like that
The react-app-env package suggested on another post on this page is deprecated, as described in its repo: https://github.com/tuchk4/react-app-env
I recommend using dotenv instead.

Resources