React analyze bundle size - reactjs

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

Related

How can I disable the overlay for warnings in a React app?

I’m using react-app-rewired and I want to disable the overlay for Typescript warnings that appears every time I compile. For reasons I don't understand, warnings that the VSCode Typescript checker doesn't pick up appear on the overlay; webpack is being a stricter enforcer (stricter than I want it to be in fact).
Anyway, I tried react-app-rewired start --no-client-overlay and I tried this for my config-overrides.js file:
module.exports = {
webpack: function (config, _) {
config.devServer = {
client: {
overlay: false
}
}
return config
}
}
Neither has any effect. It would be good to know how to disable the overlay but an equally good solution would be how to have the compiler use the same level of strictness that VSCode does.
create-react-app generates a separate Webpack configuration for use with the dev server, so you need to use the devServer function, like so:
module.exports = {
devServer: function (configFunction) {
return function (proxy, allowedHost) {
// Create the default config by calling configFunction with the proxy/allowedHost parameters
const config = configFunction(proxy, allowedHost);
config.client = {
overlay: false,
};
return config;
};
},
};
From the react-app-rewired docs:
Webpack Dev Server
When running in development mode, create-react-app does not use the
usual Webpack config for the Development Server (the one that serves
the app pages). This means that you cannot use the normal webpack
section of the config-overrides.js server to make changes to the
Development Server settings as those changes won't be applied.
Instead of this, create-react-app expects to be able to call a
function to generate the webpack dev server when needed. This function
is provided with parameters for the proxy and allowedHost settings to
be used in the webpack dev server (create-react-app retrieves the
values for those parameters from your package.json file).
React-app-rewired provides the ability to override this function
through use of the devServer field in the module.exports object in
config-overrides.js. It provides the devServer function a single
parameter containing the default create-react-app function that is
normally used to generate the dev server config (it cannot provide a
generated version of the configuration because react-scripts is
calling the generation function directly). React-app-rewired needs to
receive as a return value a replacement function for create-react-app
to then use to generate the Development Server configuration (i.e. the
return value should be a new function that takes the two parameters
for proxy and allowedHost and itself returns a Webpack Development
Server configuration). The original react-scripts function is passed
into the config-overrides.js devServer function so that you are able
to easily call this yourself to generate your initial devServer
configuration based on what the defaults used by create-react-app are.
If you are using Webpack v4 (CRA v4), this should be the documentation you are looking for https://v4.webpack.js.org/configuration/dev-server/#devserveroverlay
module.exports = {
webpack: function (config, _) {
config.devServer = {
overlay: {
warnings: true,
errors: true
}
}
return config
}
}
The config you provided above is for Webpack v5 (CRA v5), so make sure you are using CRA v5 (and also check that react-app-rewired supports that version).

Upgrading react-scripts gives error on running react-scripts start

After updating react-scripts to version 3.4.0 and on running react-scripts start in windows I get this error:
Must use import to load ES Module: C:\Users\myUser\Desktop\Projects\myproject\frontend\src\setupProxy.js
require() of ES modules is not supported.
require() of C:\Users\myUser\Desktop\Projects\myproject\frontend\src\setupProxy.js from C:\Users\myUser\Desktop\Projects\myproject\frontend\node_modules\react-scripts\config\webpackDevServer.config.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename setupProxy.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from C:\Users\myUser\Desktop\Projects\myproject\frontend\package.json.
And this is the file setupProxy:
const proxy = require('http-proxy-middleware');
module.exports = function(app) {
const proxyTarget = process.env.REACT_APP_API || 'http://localhost:8089';
console.log(`proxying /backend/api/* to ${proxyTarget}/backend/*`);
app.use(proxy('/backend/api', { target: proxyTarget}));
};
Why do I get this error after upgrading react-scripts, and it only displays on windows, if I run the same command on mac, then I don't get this error. How can I fix this for windows?

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.

How to connect to a sqlite db from a React app?

I'm trying to build a page using Create React App, plus the sqlite3 module. In their default configurations, the two things don't seem to be compatible out of the box. I'm new to React and JS in general, so I'm hoping there's something obvious I'm missing here.
Using npx v6.9.0 and Node v12.4.0, I can reproduce this by typing npx create-react-app test, cd test, npm start.
So far so good. I type: npm install sqlite3, and receive an npm warning that I should install typescript. OK, I type npm install typescript. All good. I start up the app, and it compiles so far. Great!
I open up App.js, and per sqlite3's readme doc, under the import lines, I type var sqlite3 = require('sqlite3').verbose();
This is probably where I'm doing something wrong. My app now fails to compile, telling me:
./node_modules/sqlite3/node_modules/node-pre-gyp/lib/info.js
Module not found: Can't resolve 'aws-sdk' in '/Users/brendanlandis/Desktop/test/node_modules/sqlite3/node_modules/node-pre-gyp/lib'
I try npm install aws-sdk, which gets me a little farther. My app still won't compile, but now the error is:
TypeError: stream is undefined
./node_modules/set-blocking/index.js/</module.exports/<
node_modules/set-blocking/index.js:3
1 | module.exports = function (blocking) {
2 | [process.stdout, process.stderr].forEach(function (stream) {
> 3 | if (stream._handle && stream.isTTY && typeof stream._handle.setBlocking === 'function') {
4 | stream._handle.setBlocking(blocking);
5 | }
6 | });
In googling around, I haven't yet figured out what I'm doing wrong. Any help would be appreciated. Thanks!
As the other answer mentioned, this is probably not recommended. You should really stick your database on the backend somewhere.
However it is possible to do this using sql.js. I had no luck with the sqlite3 module.
Here is the example I used: https://github.com/sql-js/react-sqljs-demo
Start by installing Craco. This is needed for bundling the wasm file.
npm install #craco/craco --save
replace your react scripts with Craco scripts in package.json:
"scripts": {
- "start": "react-scripts start",
- "build": "react-scripts build",
- "test": "react-scripts test",
"start": "craco start",
"build": "craco build",
"test": "craco test"
}
Make a craco.config.js file in the root of your project and place this code inside:
module.exports = {
webpack: {
configure:{
// See https://github.com/webpack/webpack/issues/6725
module:{
rules: [{
test: /\.wasm$/,
type: 'javascript/auto',
}]
}
}
}
};
Then install sql.js
npm install sql.js --save
You probably need to do some more backend setup after this, but for now import the package:
import initSqlJs from 'sql.js';
// Required to let webpack 4 know it needs to copy the wasm file to our assets
import sqlWasm from "!!file-loader?name=sql-wasm-[contenthash].wasm!sql.js/dist/sql-wasm.wasm";
I had to disable eslint to get the second import to work. Really not ideal, but eslint throws errors if you try using file-loader. These are the lines to remove in package.json:
"eslintConfig": {
"extends": "react-app"
},
Now call the library!
const response = fetch("example.com/sqlitedatabase");
const buf = await response.arrayBuffer();
const SQL = await initSqlJs({ locateFile: () => sqlWasm });
const db = new SQL.Database(new Uint8Array(buf));
You can then query the database; The following code runs a query and then puts it into a more useable form than the default response.
const query = db.exec(`
SELECT
*
FROM
table;
`);
const columns = query[0].columns;
const values = query[0].values;
let rows = [];
values.forEach(element => {
let row = {};
for (let i = 0; i < columns.length; i++) {
row[columns[i]] = element[i];
}
rows.push(row);
});
That should work, but as I mentioned above, you might need to mess with the backend a little. Often times single page applications have trouble with CORS when dealing with bundled files. To fix this on AWS Amplify, I added the following code in a file called customHttp.yml to the root of my project:
customHeaders:
- pattern: '**/*'
headers:
- key: Access-Control-Allow-Origin
value: '*'
- pattern: '*.wasm'
headers:
- key: Access-Control-Allow-Origin
value: '*'
(Edit: Added a more generic pattern to the file, didn't work without it.)
Note that it may take some time for the custom headers to update, even though it looks like they update immediately.
Also related to single page applications, wasm files need to be added to the list of files exempted from redirects:
Source address: </^((?!.(css|gif|ico|jpg|js|png|txt|svg|woff|ttf|json|map|wasm)$).)*$/>
Target address: /index.html
Type: 200 (Rewrite)
ReactJS is mostly a front end framework, you should create a backend server.
Some NPM packages are not compatible with front-end JS application.
Your react application will call the server and the server manipulate the DB transactions. You can for example use express js. Useful docs below :
ExpressJS - SQLite doc
API Request from react app

read environment vars in a simple react app

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')
}
}),

Resources