Are all packages from package.json included in React build? - node.js

I created a react app that both server and client shares the same package.json:
├───build
│ └───static
│ ├───css
│ ├───js
│ └───media
├───server (backend code)
├───src (client code)
├───package.json (shared)
My question is very simple, are all packages from package.json included in the final production React build?
For example, I use express for server. Is it included in the React build?
If so, is there any way to avoid it? Or did I choose a wrong architecture?
Edit:
Im using create-react-app, default mode

No* (in the common case).
The most popular react build tooling will use webpack (or other bundlers which do similar things). Webpack receives some "entry point filepaths", from those entry points he crawls for dependencies. Then webpack packs everything into a single output file (or a set of files, depending on the settings).
If you didn't import express from any of your frontend files, it won't go into the bundle.

Im not sure about combining the package.json for both your express and React app, I dont see an advantage to doing this since React uses webpack and combining the express server might mess up some of the default settings, I will share with you how I do it.
When you are in a development build you will have 2 separate apps running independently. Both the create-react-app and the node/express server will be running independently of each other and they will have their own separate package.json.
In production however you will run npm run build on your React app and it will be served as a static file from your express server. A built React app does not have a package.json
I have implemented both of these scenarios you can check it out here
Dev build:
https://github.com/iqbal125/react_hooks_fullstack_skeleton
Produiction Build:
https://github.com/iqbal125/react-prod9

Previously answered,
According to Webpack doc, Webpack generates a dependency graph starting from entry point which is usually index.js.
And also if you use something like create-react-app that uses webpack under the hood, it will generate a package json like this:
{
"name": "my-app",
"version": "0.1.0",
"private": true,
"dependencies": {
"#testing-library/jest-dom": "^5.16.5",
"#testing-library/react": "^13.4.0",
"#testing-library/user-event": "^13.5.0",
"axios": "^1.3.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
"scripts": {
"build": "react-scripts build",
},
You can see there is no devDependencies! that means not all thing that you just put on the dependencies will be included in your final build.
Finally I've tested inside a new CRA my app:
pressed npm run build on the bare installed:
File sizes after gzip:
46.61 kB build\static\js\main.46f5c8f5.js
1.78 kB build\static\js\787.28cb0dcd.chunk.js
541 B build\static\css\main.073c9b0a.css
Installed axios via npm i axios, but never imported it.
output after running npm run build:
File sizes after gzip:
46.61 kB build\static\js\main.46f5c8f5.js
1.78 kB build\static\js\787.28cb0dcd.chunk.js
541 B build\static\css\main.073c9b0a.css
Nothin has been changed!
import axios from "axios", inside but never use it in the code:
import axios from "axios";
export default function App() {
return (
<div className="App">
</div>
);
}
This is the output:
[eslint]
src\App.js
Line 3:8: 'axios' is defined but never used no-unused-vars
File sizes after gzip:
46.61 kB build\static\js\main.46f5c8f5.js
1.78 kB build\static\js\787.28cb0dcd.chunk.js
541 B build\static\css\main.073c9b0a.css
Again nothing changed! but you can see eslint warning too!
Use one of it's functions e.g. get method only:
import axios from "axios";
export default function App() {
console.log(axios.get);
return (
<div className="App">
</div>
);
}
the output:
File sizes after gzip:
57.92 kB (+11.31 kB) build\static\js\main.4c83ea39.js
1.78 kB build\static\js\787.28cb0dcd.chunk.js
541 B build\static\css\main.073c9b0a.css
Conclusion:
If we don't use a package inside our app, it won't get into the final build.
Note:
Although extra packages won't affect production, don't forget to uninstall unused packages from time to time.
Running npm install still install every package defined in the package.json, no matter whether they are used or not. So having loads of unused packages will slow down deployment and affect your teammates (they need to run npm install as well!!.
Reference

Related

How to set up my native node module if it is imported by my host project?

I am developing 2 projects in TypeScript. First, a native node module called my-node-module. It is imported by my host project called host-project.
package.json of host-project
"my-node-module": "git+ssh://git#github.com:foo/my-node-module"
my-node-module is written in TypeScript. I want to import it within my host project.
Question 1
The main entry in the package.json of my-node-module is js/index.js. This file is created if I call npm run tsc in the root of my-node-module.
Can I directly import the project (src/index.ts) file via import myModule from 'my-node-module' or is the transpile step really necessary?
Question 2
If the question above is answered with yes, how would I ensure that npm i on the host project also executes the required transpile steps for my dependency module my-node-module?
I use similar approach in one of my commercial project. I have some common code used by all,
React JS frontend
React Native frontend
Express js based graphql server
Then there's another package which has UI components ready to import in React JS web and React Native mobile projects.
All of these projects are install as npm packages and hosted in remote git repos ( In my case, they are on remote Bitbucket repositories )
For example, I have following configuration for my shared logic project.
package #myorg/common-logics
{
"name": "#myorg/common-logics",
"version": "1.4.0",
"main": "./build/index.js",
"types": "./build/index.d.ts",
"private": true,
"files": [
"build/**/*"
],
"author": "Dilshan",
"license": "MIT",
"scripts": {
"clean": "rimraf build",
"build": "yarn run clean && tsc",
"test": "npx ts-node src/test/data.ts",
"version-upgrade": "yarn version patch",
"changelog": "standard-version"
},
"devDependencies": {
"#types/lodash": "^4.14.177",
"#types/uuid": "^8.3.3",
"rimraf": "^3.0.2",
"standard-version": "^9.3.2",
"ts-node": "^10.4.0",
"typescript": "^4.5.2"
},
"dependencies": {
},
"repository": {}
Previously I manually built this project by running yarn build because I was the only one works on this shared package. You can also use Husky or a pipeline as well.
If I had to push this to a npm registry, i would have built the code in a pipeline.
This worked until I had to manage multiple npm packages. It was getting harder to keep track all of them so Here I used https://nx.dev/ to manage all of my npm packages. Then I created separate repositories ( Because I didn't used a NPM registry ) just to hold the build code of each packages in NX mono repo.
So all I do is, do my development in NX mono repo and then push it to the repository. Then in a pipeline I build the libraries in NX project and push them to the read only repositories that just hold the latest build code of the source code.
I can say it works & currently the production system uses these shared libraries and I have been working with these custom shared libraries over 6 - 7 months now. I never had any issues unless this one problem with NX. Also never had a source code - build code sync issue so far.
If you cannot setup CI/CD pipelines, I guess you can do the same thing in your local machine with Husky and custom shell script to build and copy build code to readonly repos.
I normally use a SharedModule for using common modules across multiple projects.
you can create a shared module that has all these modules and components. Import them into a shared module and import this shared module into all feature modules. This will save imports and a lot of coding lines.
import { CommonModule } from '#angular/common';
import { NgModule } from '#angular/core';
import { FormsModule } from '#angular/forms';
import { CustomerComponent } from './customer.component';
import { NewItemDirective } from './new-item.directive';
import { OrdersPipe } from './orders.pipe';
#NgModule({
imports: [ CommonModule ],
declarations: [ CustomerComponent, NewItemDirective, OrdersPipe ],
exports: [ CustomerComponent, NewItemDirective, OrdersPipe,
CommonModule, FormsModule ]
})
export class SharedModule { }
Notice the following:
It imports the CommonModule because the module's component needs common directives
It declares and exports the utility pipe, directive, and component classes
It re-exports the CommonModule and FormsModule
By re-exporting CommonModule and FormsModule, any other module that imports this SharedModule, gets access to directives like NgIf and NgFor from CommonModule and can bind to component properties with [(ngModel)], a directive in the FormsModule.
Even though the components declared by SharedModule might not bind with [(ngModel)] and there may be no need for SharedModule to import FormsModule, SharedModule can still export FormsModule without listing it among its imports. This way, you can give other modules access to FormsModule without having to import it directly into the #NgModule decorator.

Module not found: Error: Can't resolve 'fs' in dotenv/lib

All of a sudden, when creating a react production build, I get this error.
> safe-courier#0.1.0 build
> react-scripts build
Creating an optimized production build...
Failed to compile.
Module not found: Error: Can't resolve 'fs' in '/workspace/safe-courier/client/node_modules/dotenv/lib'
I have searched on the web, found similar cases but different frameworks of which all were not of help in regards to this issue.
I have tried to uninstall dotenv and reinstall it again but i get the same error. I'm not sure what could be the problem understanding that fs module is part of nodejs and comes bundled with it
To solve this:
Create the .env file at the root level of you app
Name your variables beginning with REACT_APP_ // that's the key !!
Restart your server with npm start each time you change an env variable
Use your variable with process.env.NAMEOFYOURVARIABLE
No need of dotenv for your React app.
I solved the same problem;
npm install dotenv-webpack --save-dev
Create .env file under root folder
create env variable as
REACT_APP_YOURVARIABLE=itsvalue
Create webpack.config.js file under the root folder with following content
const Dotenv = require('dotenv-webpack');
module.exports = {
plugins: [
new Dotenv()
]
}
Then wherever you want to use variable in .env write
process.env.REACT_APP_YOURVARIABLE
There is no need to import dotenv. It is already done in webpack.config.js
1- As already mentioned by Stéphane Sulikowski, No need to use dot-env in react projects
Why?
"dot-env" uses some modules that are only supported by nodejs but not supported by "browser engines" like fs, os etc. React-code-bundle runs in the browser and the browser doesn't support module "fs", so if any modules reference the "fs" module will get the same error.
There is some inbuilt support by reactjs to use environment variables stored in a .env file and begins with REACT_APP_
2- If you have to use it for some reason use "env-cmd"
npm install env-cmd
3- create environment specific .env files like .env.local OR .env
4- In your "environment specific" OR .env file, add variables beginning with REACT_APP_
REACT_APP_API_BASE_URL="http://localhost:4000"
5- Use these environment variables in your code files
like console.warn (process.env.REACT_APP_API_BASE_URL)
6- OPTIONALLY...... configure package.json something like this
...
"scripts": {
"start": "env-cmd -f .env.local react-scripts start",
"build:staging": "env-cmd -f .env.staging react-scripts build",
"build:production": "env-cmd -f .env.production react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
}
Note - When you add a new variable in .env .... files, you have to run npm start OR related...
Just like Reno mentioned just create your .env at the root with the name prepended with REACT_APP and it will work out of the box
Example .env file
REACT_APP_GITHUB_API_URL=https://api.github.com/graphql
Usage:
process.env.REACT_APP_GITHUB_API_URL
If you are using create-react-app this article describes the behavior of environment variables: https://create-react-app.dev/docs/adding-custom-environment-variables/
Note that the document frequently reminds you of this warning:
WARNING: Do not store any secrets (such as private API keys) in your React app!
Environment variables are embedded into the build, meaning anyone can view them by inspecting your app's files.
To securely use secrets such as passwords and tokens, consider setting up a server that can deliver this data to the frontend via HTTP. For example, once users authenticate into your app you send their credentials to a microservice that can validate their identity and return an API key or session to be used for subsequent REST API calls.

npm script: browser opened using node, but not using babel

Early days in the development of my first npm script, and struggling somewhat. I'm on Ubuntu LTS with the latest nvm, node, npm and pnpm releases.
Node + npm have been installed using nvm, pnpm installed using npm, and several modules installed locally (i.e. without the -g flag) using pnpm. No sudo was necessary. The resulting package.json:
{
"name": "javascript-development-environment",
"version": "1.0.0",
"description": "JavaScript development environment cobbled together using various online sources",
"scripts": {
"prestart": "./node_modules/.bin/babel buildScripts/startMessage.js",
"start": "./node_modules/.bin/babel buildScripts/srcServer.js"
},
"author": "Laird o' the Windy Waas",
"license": "MIT",
"dependencies": {
"#babel/polyfill": "^7.0.0"
},
"devDependencies": {
"#babel/cli": "^7.1.5",
"#babel/core": "^7.1.6",
"#babel/preset-env": "^7.1.6",
"chalk": "^2.4.1",
"express": "^4.16.4",
"open": "^0.0.5",
"path": "^0.12.7"
}
}
With only Firefox 60.0.1 installed, on doing a 'pnpm start' using node, a browser window is opened "Hello World!" displayed, and terminal control has to be regained using a CTRL-C. -> All ok.
If I substitute in babel using the path as shown above (which results from the same issues described in this post), the buildScripts code is echoed to the terminal, but no browser window opens, and terminal control is released immediately on completion. The npm debugger provides no useful feedback. -> Something not working..
As the "Hello World!" code is traversed correctly using node (and remains unchanged for the babel traversal), it is not the source of the problem.
Here my babel config files:
.babelrc
{
"presets": [
"#babel/preset-env"
]
}
babel.config.js
const presets = [
[
"#babel/env",
{
targets: {
edge: "17",
firefox: "61",
chrome: "67",
safari: "11.1",
opera: "56"
},
useBuiltIns: "usage"
},
],
];
module.exports = { presets };
The problem looks to be that babel is not passing the transpiled code on to nodejs / express. Bound to be something simple, but I'm just going round in circles..
One thing I found myself asking is whether there might be a conflict between the various env presets across .babelrc, babel.config.js and package.json. Successive parking of the .babelrc and babel.config.js files, however, brought no change/advance.
I have also noticed that both (nvms) node and (ubuntus) nodejs are currently installed:
$ which node
/home/<myusername>/.nvm/versions/node/v10.13.0/bin/node
$ which nodejs
/usr/bin/nodejs
However, as everything to do with node and npm was installed using nvm, this shouldn't be a problem.
I could, I suppose, try installing babel globally, but with this widely frowned apon. I'd prefer a solution reflecting 'best practice'.
Thanks for any suggestions.
In earlier years, tutor material suggested babel-node would start npm / node (and hence express) on the user's behalf.
babel-node now no longer seems to be recognised. Attempts at using the babel-node command failed, and simply using node in it's place resulted in the transpiler output being dumped to the terminal.
babel, (in our case) pnpm, and node now have to be explicitly called, the latter referencing the transpiled code. node appears to handle interfacing with express.
After some experiment, therefore, the following changes (in package.json) appear to work fine:
"scripts": {
"prestart": "./node_modules/.bin/babel buildScripts/startMessage.js -d dist",
"build": "./node_modules/.bin/babel buildScripts/srcServer.js -d dist",
"start": "pnpm run build && node dist/startMessage.js && node dist/srcServer.js"
},
These result both in a tidy console output and result in "Hallo World!" being displayed in a freshly opened browser window.
Just hope this is of use to someone else.. ;-)

Warnings when building backend Express/WS Node app with Webpack

I am getting some confusing warnings when building a backend Node server with Webpack. I want to use Webpack to build my backend primarily for two reasons:
Webpack creates a single executable file, which is easier to deploy
Webpack includes all of my app's dependencies, so I can deploy my app to any compatible Node environment without needing to install dependencies first
Here are the warnings I'm getting:
WARNING in ./~/ws/lib/BufferUtil.js
Module not found: Error: Can't resolve 'bufferutil' in .../node_modules/ws/lib
# ./~/ws/lib/BufferUtil.js 35:21-42
# ./~/ws/lib/Receiver.js
# ./~/ws/index.js
# ./src/main.js
WARNING in ./~/ws/lib/Validation.js
Module not found: Error: Can't resolve 'utf-8-validate' in .../node_modules/ws/lib
# ./~/ws/lib/Validation.js 10:22-47
# ./~/ws/lib/Receiver.js
# ./~/ws/index.js
# ./src/main.js
WARNING in ./~/express/lib/view.js
80:29-41 Critical dependency: the request of a dependency is an expression
For the Critical dependency warning, I've found a good example explaining the problem and some documentation on how to use the ContextReplacementPlugin, although it's still unclear to me how to apply it to this situation. It looks like the warning is being caused by line 80 in node_modules/express/lib/view.js:
opts.engines[this.ext] = require(mod).__express
It is clear to me that the dependency cannot be resolved at build time, so how can I use the ContextReplacementPlugin to fix this dependency?
As for the Module not found warnings in the ws package, it's unclear to me what's going on. It looks like those dependencies exist in my global node_modules, and maybe they're not being pulled in by Webpack. I've tried adding them to my project's devDependencies, but then I just get Critical dependency warnings for them instead.
My application still runs after being built, so I suppose I could technically ignore the warnings, but I figure that these are widely used Node packages and Webpack is a popular build tool, so there must be a reasonable solution available.
Here are my dependencies in my package.json:
"devDependencies": {
"#types/cassandra-driver": "^0.8.10",
"#types/express": "^4.0.35",
"#types/uuid": "^2.0.29",
"#types/ws": "0.0.40",
"nodemon": "^1.11.0",
"typescript": "^2.3.1",
"webpack": "^2.5.1"
},
"dependencies": {
"cassandra-driver": "^3.2.1",
"express": "^4.15.2",
"uuid": "^3.0.1",
"ws": "^2.3.1"
}
And here's my webpack.config.js:
const path = require('path');
module.exports = {
entry: './src/main.js',
output: {
path: path.join(__dirname, 'dist'),
filename: 'main.js'
},
target: 'node',
node: {
__dirname: false,
__filename: false
}
};
I like keeping things minimal if possible. Thanks for reading.
The short answer
webpack can work with node, but it cannot extract follow require() statements. Modifications have to be made to ignore require() in order for it to work.
The long answer
It is actually possible to pull some files into a master file and run it in some instances.
One instance is if all the modules required are written in typescript and the modules are written in a away that the typescript plugin can parse the module in.
Another instance would be if you are using es6 babel plugins and using es6 style imports.
Even in the above scenarios the blunder may choose not to pull in certain files
The ultimate answer
It really should not matter too much about trying to perform the long answer because modules are stored in memory at boot and then referenced later from the cache. See the article below for more information.
http://fredkschott.com/post/2014/06/require-and-the-module-system/

Angular2 and express node.d.ts conflict

I am trying to configure an angular2+express project. I understand the cause of the problem, but not the correct solution. Here are the relevant parts of my package.json dependencies:
"dependencies": {
"angular2": "2.0.0-beta.0",
"express": "^4.13.3",
"tsd": "^0.6.5",
"typescript": "^1.4.1",
<...lots of peer dependencies>
}
Node 5.2.0 is installed globally. When I run tsd install, I get ./typings/node.d.ts pulled in, for what the comments claim to be v0.12.0 API. But this conflicts with angular2/typings/node/node.d.ts (which also claims v0.12.0). The .d.ts files are different, for example:
./node_modules/angular2/typings/node/node.d.ts
---> declare var global: NodeJS.Global;
./typings/node/node.d.ts
---> declare var global: any;
The result is a mass of TS2300: Duplicate identifier errors. I can hack around this by manually deleting ./typings/node and editing ./typings/express/express.d.ts to have:
/// <reference path="../../node_modules/angular2/typings/node/node.d.ts" />
Now everything works, but obviously this is just plain 'wrong'. What is the standard way to pull in expres.d.ts so it plays nice with Angular 2?

Resources