Size of bundled ReactJS app - reactjs

I am trying to reduce the size of my reactjs application bundle.js file. For a relatively simple app i have its browserified js file size - 452Kb.
To build it, i use NPM with respective package.json file:
{
"name": "MyApp-React",
"version": "0.0.1",
"description": "My App Description",
"main": "app.js",
"scripts": {
"watch": "watchify app.js -o public/js/bundle.js -v",
"browserify": "browserify app.js | uglifyjs > public/js/bundle.js",
"build": "npm run browserify",
"start": "npm install"
},
"author": "",
"dependencies": {
"axios": "^0.14.0",
"body-parser": "^1.15.2",
"clipboard": "^1.5.12",
"express": "~4.9.7",
"express-handlebars": "~1.1.0",
"express-session": "^1.14.1",
"highlight.js": "^9.7.0",
"node-jsx": "~0.12.4",
"react": "~15.3.1",
"react-dom": "^15.3.1",
"react-maskedinput": "^3.2.4",
"react-modal": "^1.4.0",
"react-router": "^2.8.1"
},
"devDependencies": {
"browserify": "~6.0.3",
"nodemon": "^1.2.1",
"reactify": "~1.1.1",
"uglify-js": "~2.4.15",
"watchify": "^3.1.1"
},
"browserify": {
"debug": false,
"transform": [
"reactify"
]
}
}
Not being an expert in Node JS/ ReactJS development i hope i do somethin wrong, but i cant find what.
For the time being i tried few things: app.js file has a line of code setting NODE_ENV variable to 'production'
process.env.NODE_ENV = 'production';
A second thing i have tried is to use npm prune command with --production parameter. Having this run, i see it removes a lot from node_modules folder, but then npm run build is failing to run as it misses devDependencies. What can i do?

One thing that you could do to lighten the download burden for your users is get react and react-dom from a CDN instead of putting them in your bundle.
Move them from the dependencies section of your package.json to a new section peerDependencies (see npm docs).
Then add tags to your HTML code for loading React and ReactDOM like so:
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react.min.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react-dom.min.js"></script>
→ See React on cdnjs.com
Then you need to change your Browserify config to recognize react and react-dom as external modules.
→ See related question on StackOverflow

Related

Nextjs + Expo in Monorepo "Invalid Hooks Call"

I've created a monorepo with 4 packages like so:
.
├── lerna.json
├── package.json
├── packages
│   ├── admin-> Basic CRUD for backend with Nextjs
│   ├── mobile-> Expo app
│   ├── server-> GraphQL server
│   ├── shared -> Yup Schemas, GraphQL stuff
│   └── tsconfig.json
├── README.md
├── yarn-error.log
└── yarn.lock
8 directories, 6 files
I'm still working on getting everything configured, so I haven't done much yet besides a test graphql query, but I'm having trouble with my Expo and Nextjs app. This is the error output when I start it.
Unhandled Runtime Error
Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
I know there might be trouble when two versions of React are in the same repo, but I don't know which package's version I should downgrade or upgrade for them to match properly.
This is the package.json for my mobile package, which is an Expo app.
{
"name": "#bt/mobile",
"main": "__generated__/AppEntry.js",
"version": "1.0.0",
"keywords": [
"react",
"expo",
"template",
"typescript",
"nativebase"
],
"license": "MIT",
"scripts": {
"start": "expo start",
"dev": "expo start --clear",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
"eject": "expo eject",
"postinstall": "expo-yarn-workspaces postinstall"
},
"dependencies": {
"#bt/shared": "^1.0.0",
"#apollo/client": "^3.4.15",
"expo": "~42.0.0",
"expo-status-bar": "~1.0.4",
"graphql": "^15.6.0",
"native-base": "3.2.0",
"react": "16.13.1",
"react-dom": "16.13.1",
"react-native": "https://github.com/expo/react-native/archive/sdk-42.0.0.tar.gz",
"react-native-safe-area-context": "3.2.0",
"react-native-svg": "12.1.1",
"react-native-web": "~0.13.12",
"styled-components": "^5.3.0",
"styled-system": "^5.1.5"
},
"devDependencies": {
"#babel/core": "^7.9.0",
"#types/react": "~16.9.35",
"#types/react-native": "~0.63.2",
"expo-yarn-workspaces": "^1.5.2",
"typescript": "~4.0.0"
},
"bugs": {
"url": "https://github.com/GeekyAnts/nativebase-templates/issues"
},
"homepage": "https://github.com/GeekyAnts/nativebase-templates#readme",
"author": "Aditya Jamuar",
"private": true
}
And this is the package.json for my admin package, which is a Next app.
{
"name": "#bt/admin",
"version": "1.0.0",
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
"dependencies": {
"#apollo/client": "^3.4.15",
"#bt/shared": "1.0.0",
"#chakra-ui/icons": "^1.0.5",
"#chakra-ui/react": "^1.4.2",
"#chakra-ui/theme-tools": "1.1.2",
"#emotion/react": "11.1.5",
"#emotion/styled": "11.1.5",
"formik": "^2.2.9",
"framer-motion": "^4.0.3",
"graphql": "^15.6.0",
"next": "latest",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"yup": "^0.32.9"
},
"devDependencies": {
"#types/node": "^14.6.0",
"#types/react": "^17.0.3",
"#types/react-dom": "^17.0.3",
"typescript": "4.3.2"
}
}
I also tried using nohoist in the root's package.json.
{
"name": "BT",
"version": "1.0.0",
"license": "MIT",
"private": true,
"workspaces": {
"packages": [
"packages/**"
],
"nohoist": [
"**/react",
"**/react/**"
]
},
"devDependencies": {
"lerna": "^4.0.0"
},
"scripts": {
"dev": "lerna run dev",
"build": "lerna run build",
"build:shared": "lerna run build --scope=#bt/shared",
"bootstrap:": "lerna run yarn",
"clean": "lerna run clean"
}
}
This is the output for yarn why react
yarn why v1.22.10
[1/4] Why do we have the module "react"...?
[2/4] Initialising dependency graph...
[3/4] Finding dependency...
[4/4] Calculating file sizes...
=> Found "#bt/mobile#react#16.13.1"
info Reasons this module exists
- "_project_##bt#mobile" depends on it
- in the nohoist list ["/_project_/**/react","/_project_/**/react/**"]
info Disk size without dependencies: "244KB"
info Disk size with unique dependencies: "244KB"
info Disk size with transitive dependencies: "244KB"
info Number of shared dependencies: 5
=> Found "#bt/admin#react#17.0.2"
info Reasons this module exists
- "_project_##bt#admin" depends on it
- in the nohoist list ["/_project_/**/react","/_project_/**/react/**"]
info Disk size without dependencies: "356KB"
info Disk size with unique dependencies: "356KB"
info Disk size with transitive dependencies: "356KB"
info Number of shared dependencies: 3
Done in 5.54s.
Here's a repository for reproducing this error: https://github.com/Je12emy/monorepo-error
I had some issues with this, I had a project with Next 13.1 and another project with Expo 47, and it was only solved through unifying their React and React DOM versions (It was 18.2 in one, and 18.1.0 on another).
Maybe it's too late, but It can help someone else :)
I issue the same problem when I start playing with monorepo.
In your root package.json, nohoist should be [**].
Without that, you'll have collisions conflicts between expo and nextjs. (and more trouble if your shared packages have common dependencies with your apps package.json).
I choose a different folder structure (/apps, /packages), but I have a working example in github ;)
In this demo you will find some customizations on metro.config.json and webpack.

Module not found: Error: Can't resolve `pp-shared-components` - React Shared Library of Components in Jenkins

I have a React library called pp-shared-components. It lives on a github repo, so to install it I do the following in my package.json file.
"dependencies": {
"pp-shared-components": "git+ssh://git#github.com/{org}/pp-shared-components.git#master",
}
In the pp-shared-components repo, I have an index.js file that imports React components and then exports then like so.
import ContentHeader from './components/content-header/ContentHeader.js';
import Wizard from './components/wizard/Wizard.js';
export {
ContentHeader,
Wizard
}
I use rollup to build my library.
My package.json in the pp-shared-components is as follows.
{
"name": "pp-shared-components",
"version": "1.0.0",
"description": "PP Shared Library for Components.",
"main": "build/index.cjs.js",
"module": "build/index.esm.js",
"browser": "build/index.js",
"style": "build/index.css",
"files": [
"build"
],
"scripts": {
"build": "rollup -c",
"watch": "rollup -c --watch",
"lint": "eslint --ext .js,.jsx .",
"prepare": "npm run build"
},
"repository": {
"type": "git",
"url": "git+https://github.com/{org}/pp-shared-components.git"
},
"publishConfig": {
"access": "public"
},
"devDependencies": {
...
"rollup": "^1.17.0",
"rollup-plugin-babel": "^4.3.3",
"rollup-plugin-commonjs": "^10.0.1",
"rollup-plugin-filesize": "^6.1.1",
"rollup-plugin-json": "^4.0.0",
"rollup-plugin-local-resolve": "^1.0.7",
"rollup-plugin-node-builtins": "^2.1.2",
"rollup-plugin-node-externals": "^2.0.1",
"rollup-plugin-node-globals": "^1.4.0",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-peer-deps-external": "^2.2.0",
"rollup-plugin-postcss": "^2.0.3",
"rollup-plugin-scss": "^1.0.2"
},
"peerDependencies": {
...
},
"dependencies": {
...
}
}
I can then import the components in another project like so
import { ContentHeader, Wizard } from 'pp-shared-components';
This all works fine locally, however, when I run this through Jenkins, I get the following error in the console
[INFO] ERROR in ./screens/main/Main.js
[INFO] Module not found: Error: Can't resolve 'pp-shared-components' in '/var/lib/jenkins/data/workspace/pp/src/main/client/screens/main'
[INFO] # ./screens/main/Main.js 6:15-55
[INFO] # ./app/App.js
[INFO] # ./index.js
Looking at the pp-shared-components folder in the node_modules folder within Jenkins, all the folders and files are exactly the same as they are in my local version?
I did notice that while in VSCode, there is a little tooltip that exclaims
module "/Users/{users}/git/pp/node_modules/pp-shared-components/build/index.cjs"
Could not find a declaration file for module 'pp-shared-components'.
'/Users/{users}/git/pp/node_modules/pp-shared-components/build/index.cjs.js' implicitly has an 'any' type.
Try `npm install #types/pp-shared-components` if it exists or add a new declaration (.d.ts) file containing `declare module 'pp-shared-components';`ts(7016)
Now, I don't use typescript anywhere in my pp-shared-components project.
Will I need to add a .d.ts file somewhere in the project and while I need to use typescript throughout my whole project?
Sort of lost at the moment and need some direction of what do next and if it is a case of adding a .d.ts file, what is involved in doing so? Is it as simple as adding declare module 'pp-shared-components' and that's that?
Any help would be greatly appreciated.

How to disable cache babel/webpack react visual studio

I am working on React application with Asp.Net core from Visual Studio .I have used this tutorial at https://blog.pusher.com/how-to-use-react-with-visual-studio-and-asp-net-web-api/ to get started and the sample application works with babel and webpack. However the changes i make in the jsx file does not seem to reflect on the browser when i run the application .After some research i found that babel caches the data and their website advises to disable it using the following command
BABEL_DISABLE_CACHE=1 babel-node script.js
Here is the link -- https://babeljs.io/docs/en/babel-register/#babel-cache-path
I have no idea on how to do that.This is as far as i went before looking for help : i included the following line inside scripts section in my package.json file hoping it would work.
"start": "BABEL_DISABLE_CACHE=1 babel-node script.js"
But no luck.Any help would be appreciated.Here is my package.json file
{
"version": "1.0.0",
"name": "ASP.NET",
"private": true,
"devDependencies": {
"webpack": "1.13.1",
"babel": "6.5.2",
"babel-preset-es2015": "6.9.0",
"babel-preset-react": "6.11.1",
"babel-loader": "6.2.4",
"babel-core": "6.2.4"
},
"dependencies": {
"react": "15.2.1",
"react-dom": "15.2.1"
},
"scripts": {
"build": "webpack --config webpack.config.js",
"start": "BABEL_DISABLE_CACHE=1 babel-node script.js"
},
"-vs-binding": { "AfterBuild": [ "build" ] }
}

React Native XcodeBuild fails on header import in CI

I am attempting to build a React Native application on an Os X CircleCI box.
My circle.yml is as follows:
machine:
xcode:
version: 8.3.3
environment:
PATH: '$PATH:$HOME/node/node-v4.4.3-darwin-x64/bin'
dependencies:
pre:
- brew install node
- npm install -g react-native-cli
- npm install
- react-native link
test:
override:
- set -o pipefail && xcodebuild -project 'ios/myApp.xcodeproj' -scheme 'myApp' clean build test -sdk iphonesimulator -destination 'platform=iOS Simulator,OS=9.0,name=iPhone 6' CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY= PROVISIONING_PROFILE= | tee $CIRCLE_ARTIFACTS/xcode_raw.log | xcpretty --color --report junit --output $CIRCLE_TEST_REPORTS/xcode/results.xml
Which fails with:
/Users/distiller/my-app/ios/myApp/AppDelegate.m:12:9: 'React/RCTBundleURLProvider.h' file not found
#import <React/RCTBundleURLProvider.h>
My package.json is follows:
{
"name": "myApp",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"test": "jest",
"test-watch": "jest --watch",
"test-coverage": "jest --coverage"
},
"dependencies": {
"#turf/circle": "^4.5.2",
"#turf/envelope": "^4.5.2",
"#turf/helpers": "^4.5.2",
"gl-react-native": "^2.42.3",
"react": "~15.4.0-rc.4",
"react-addons-test-utils": "^15.4.2",
"react-dom": "^15.6.1",
"react-native": "0.39.2",
"react-native-config": "0.5.0",
"react-navigation": "^1.0.0-beta.11",
"react-test-renderer": "^15.6.1"
},
"devDependencies": {
"babel-jest": "20.0.3",
"babel-preset-react-native": "2.0.0",
"enzyme": "^2.9.1",
"enzyme-to-json": "^1.5.1",
"jest": "20.0.4"
},
"rnpm": {
"assets": [
"assets/fonts"
]
},
"jest": {
"preset": "react-native",
"collectCoverageFrom": [
"src/**/*.{js,jsx}"
],
"coverageDirectory": "__coverage__",
"snapshotSerializers": [
"./node_modules/enzyme-to-json/serializer"
],
"transformIgnorePatterns": [
"node_modules/(?!react-native|native-base|react-navigation|react-native-fabric)"
],
"setupFiles": [
"./test-setup.js"
]
}
}
By running a build with ssh enabled and inspecting the version, I can say that react-native-cli is installed at 2.0.1
Interestingly, this behaviour does not exhibit when the project is built (with the exact same command) on my machine (localhost)
By googling, I have found things like: React Native 0.40.0 : RCTBundleURLProvider.h” file not found - AppDelegate.m
Describing my problem exactly, however they are all limited to RN 4.0, while my package.json is explicitly pegged at 3.9.2
Any help would be greatly appreciated!
The solution seemed to be to delete my ios/build directory. Once I did so, I started having the same behavior locally as in CircleCi (which I could then fix by simply taking React out of the import path like so:
#import <RCTBundleURLProvider.h>
I had this problem because my test script wasn't running yarn install. So a fresh clone and build would fail. You could add something like this to your config.yml file:
- run:
name: Install React Native
command: yarn install

Why npm tries to find package.json in the wrong directory?

I'm having a web app with TypeScript, Angular and several dependencies.
npm of course is here also.
package.json was introduced to the project from the begging by npm init and right now it looks like that:
{
"name": "myApp",
"version": "0.0.8-d",
"description": "Web App",
"author": "Author",
"license": "ISC",
"repository": {
"type": "git",
"url": "MYURL"
},
"bugs": {
"url": "MYURL"
},
"homepage": "MYURL",
"browserify": {
"transform": [
"debowerify"
]
},
"dependencies": {
"malihu-custom-scrollbar-plugin": "^3.1.3"
},
"devDependencies": {
"browserify": "~13.0.0",
"connect-history-api-fallback": "^1.2.0",
"connect-modrewrite": "^0.8.2",
"debowerify": "~1.2.0",
"gulp": "^3.9.1",
"gulp-autoprefixer": "^3.1.0",
"gulp-clean-css": "^2.0.4",
"gulp-concat": "^2.6.0",
"gulp-connect": "^3.2.2",
"gulp-less": "^3.0.5",
"gulp-ng-annotate": "^2.0.0",
"gulp-sass": "^2.2.0",
"gulp-sourcemaps": "^1.6.0",
"gulp-typescript": "^2.12.2",
"gulp-uglify": "^1.5.3",
"jasmine": "^2.4.1",
"run-sequence": "^1.1.5",
"typescript": "^1.8.9",
"vinyl-source-stream": "^1.1.0"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
}
}
Also my file structure is like this:
Root
|-- tscode
|-- compiled
|-- html_files
|-- node_modules
|-- libs
| package.json
This think is that npm seems to work fine, everything is installed correctly I can add/remove dependencies BUT always I'm getting this working:
npm WARN enoent ENOENT: no such file or directory, open '/Projects/MyApp/tscode/package.json'
package.json is on the root folder as it should but still I'm getting this warning which is very annoying. As you can see npm searching for the json file in a folder one level inside instead on the root.
Also if I do:
npm list --depth=0
Then I'm getting a correct list of my dependencies BUT also: -> /Projects/MyApp/innerfolder extraneous error: ENOENT: no such file or directory, open '/Projects/MyApp/tscode/package.json
Any ideas?
Node version: v5.10.1
npm version: 3.8.5
Note: This is happening to everyone in my team regardless OS.
UPDATE: It seems that there is a bug with npm. There are some open issues at npm repository such as:
https://github.com/npm/npm/issues/9633
https://github.com/npm/npm/issues/10004
If something change I'll update the question with an answer (if provided)
Try this :
Delete node_modules folder
Then run :
$ npm cache clean
$ npm install

Resources