Include only used imports in the packaged bundle ReactJS - reactjs

I wanna use only one component from Material Ui library . I know i can import only one component using ES6 import but does webpack treeshake and remove other components from the library or include them in production .
Please help me.

Webpack from v2 onwards eliminates unused exports in two steps:
First, all ES6 module files are combined into a single bundle file in which exports that were not imported anywhere are not exported, anymore.
Second, the bundle is minified, while eliminating dead code. Therefore, entities that are neither exported nor used inside their modules do not appear in the minified bundle. Without the first step, dead code elimination would never remove exports.
Unused exports can only be reliably detected at build time if the module system has a static structure.
Webpack doesn't perform tree-shaking by itself. It relies on third party tools like UglifyJS to perform actual dead code elimination.
To do that, you would install it using
npm install --save-dev uglifyjs-webpack-plugin
And then adding it into the config:
webpack.config.js
const path = require('path');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new UglifyJSPlugin()
]
};
So when you add this config, your unused exports are not longer present in the minified build.

Webpack 5 comes with terser-webpack-plugin out of the box, hence you can just import it and configure as you wish.

Related

How to make a path alias in CRA TypeScript in 2022?

I just initiated CRA npx create-react-app my-app --template typescript and I want to make an alias when calling components, like:
import components from '#components'
where the components is located at src/components.
I've tried to config in tsconfig.json by adding:
{
"compilerOptions": {
...
"baseUrl": "./src",
"paths": {
"#utils/": ["./utils/"],
"#utils/*": ["./utils/*"]
}
}
}
Also in webpack.config.js by adding:
// const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin')
const path = require('path')
module.exports = {
resolve: {
// plugins: [new TsconfigPathsPlugin()],
alias: {
'#utils': path.resolve(__dirname, './src/utils/'),
'#utils/*': path.resolve(__dirname, './src/utils/*')
}
}
}
But it's still doesn't work.
Anyone could help me to solving these problem? But, I don't wont to use other libraries like #craco/craco.
The issue is that CRA uses its own Webpack config under the hood. Simply making a new webpack.config file doesn't actually point CRA to it, unless you run npm run eject.
Doing so is irreversible, but will add the config files to your project. From there, you should be able to modify your build settings to fit your needs.
Reminder that this cannot be undone in your project, barring perhaps a git reset, and may be more than you bargained for.
This issue with aliases seems to be a known one. Something people deemed possible earlier seems to no longer be working, or supported. Some people are speculating this could have something to do with the recent update of Webpack to version 5. And while some people claim that craco doesn't work for them, I was able to get it to work in a brand new CRA app with minimal changes. I know you're not interested in that so I won't post it here.
Alternatively, CRA allows the use of absolute imports via the src baseUrl. This will point both VSCode and Webpack to your final files, but you won't be able to set up custom paths.
"baseUrl" : "."
Using multiple index.ts files and exporting nested code up to the highest level in the directory, I'm able to keep the import paths as short as an alias:
import { persistor, store } from "src/state-management";
This could be good enough for you. If not, consider adding a package to override some of CRA's Webpack settings, or ejecting and taking matters into your own hands.

Why .js [file Extension] is not added while importing a component in reactJS?

We are creating different components in reactJS,
Example:
App.js
index.js
LandingPage.js
.....
While importing this component in another component, we are not adding the extension .js
Example:
index.js:
import App from './App'
// here './App' we are not adding .js
Does anyone know the reason why?
Your Webpack config is taking care of resolving the common extensions (ie: .js or .jsx). If your project is using create-react-app, then this is already done for you behind the scenes.
Create-react-app already resolves the following extensions automatically:
extensions: [".web.js", ".mjs", ".js", ".json", ".web.jsx", ".jsx"],
More info here
https://github.com/webpack/docs/wiki/Configuration#resolveextensions
It all done by webpack module resolution, a resolver is a library which helps in locating a module by its absolute path.
The dependency module can be from the application code or a third-party library. The resolver helps webpack find the module code that needs to be included in the bundle for every such require/import statement. webpack uses enhanced-resolve to resolve file paths while bundling modules.
Once the path is resolved based on the above rule, the resolver checks to see if the path points to a file or a directory. If the path points to a file:
If the path has a file extension, then the file is bundled straightaway.
Otherwise, the file extension is resolved using the resolve.extensions option, which tells the resolver which extensions are acceptable for resolution e.g. .js, .jsx.
Resolve extensions: These options change how modules are resolved. webpack provides reasonable defaults, but it is possible to change the resolving in detail.
In webpack.config.js
module.exports = {
//...
resolve: {
enforceExtension: false
}
};
If the value is true here, it will not allow extension-less files. So by default require('./foo') works if ./foo has a .js extension, but with this (enforceExtension) enabled only require('./foo.js') will work.
Add .js to resolve/extensions in webpack.config.js
resolve: {
extensions: [".ts", ".js", ".mjs", ".json"],
symlinks: false,
cacheWithContext: false,
},

Syntax Error In IE 11 for this node_moduels

I am getting a syntax error in IE when this component of react is loaded in the webpage. Has anybody got the same problem? This is an inherited package, and a syntax error from node_modules makes no sense?
"use strict";
/* WEBPACK VAR INJECTION */(function(module) {
const colorConvert = __webpack_require__(/*! color-convert */ "./node_modules/color-convert/index.js");
const wrapAnsi16 = (fn, offset) => function () {
const code = fn.apply(colorConvert, arguments);
return `\u001B[${code + offset}m`;
};
const wrapAnsi256 = (fn, offset) => function () {
const code = fn.apply(colorConvert, arguments);
return `\u001B[${38 + offset};5;${code}m`;
};
If you are using newer versions of Node/NPM, check your package.json file -> "browserslist" section.
This is the default "browserslist" created for you if you do not have one defined:
In this case, if you run "npm start" on your LOCAL Environment, Babel will not create Polyfills for IE11 because its not included as a target browser in "development". To get this working, I deleted my node_modules directory completely, ran 'npm install', updated package.json with:
and ran 'npm start.
The reason why this fails is that babel or your other favorite transpiler might ignore node_modules (if that's how its configured), so you need to include it manually because IE does not support arrow function syntax.
First, if you search for wrapAnsi16 or wrapAnsi256 function names online it'll point you to common npm packages, such as: ansi-styles, chalk or color-convert, debug, strip-ansi, etc.
If you are using Webpack you can add the following to your rules:
module: {
rules: [{
exclude: /node_modules\/(?!(color-convert|ansi-styles|strip-ansi|ansi-regex|debug|react-dev-utils|chalk)\/).*/
}]
}
or, easier to read:
module: {
rules: [{
include: [
path.resolve(__dirname, 'node_modules/ansi-styles'),
path.resolve(__dirname, 'node_modules/strip-ansi'),
... other's here...
path.resolve(__dirname, 'src'),
]
}]
}
Hope this helps somebody in the future ;)
TLDR; you don't need this library, just run
npm run build
And it will be excluded from your build.
I have same problem with create-react-app, and I solve it (no). From my discovery, this library should not appear in browser, because it was designed for nodejs environment. Also I found, this library come to me as dependency of jest, and jest is dependency for tests and it come as dependency for react.
So, I run
npm run build
server -s build
And try my application in IE. And it work. So, when you run
npm start
It make file including dev dependencies and other garbage that should not appear in production and in browser at all. When you run
npm run build
It make file only with required project libraries.
I had similar issue #punkbit solution and installing 'react-app-polyfill'
and importing it at the top of the index.js file solved it
import 'react-app-polyfill/ie11';
import 'react-app-polyfill/stable';
If it still does not work delete node-modules and reinstall also clear cache in IE.
All the best :)
This problem occurs because your compiled code contains (modern) ES6 syntax whilst IE11 only supports ES5.
A way to fix this is to instruct webpack to specifically compile the mentioned packages into ES5;
module: {
rules: [{
test: /\.(tsx?|js)$/,
include: [
// These dependencies have es6 syntax which ie11 doesn't like.
// Whenever you see a "SyntaxError" that crashes IE11 because of a new lib, add it here.
path.join(__dirname, 'node_modules/react-intl'),
path.join(__dirname, 'node_modules/pkce-challenge'),
path.join(__dirname, 'node_modules/fuse.js')
],
use: [{
loader: 'ts-loader', // Or whatever loader you're using
}]
}]
}
for me this was: fuse.js, pkce-challenge and react-intl.

Multiple webpack alias configurations can't resolve modules

I am working on an Angular 2 application written in Typescript, that is using webpack in conjunction with ts-loader to bundle everything together.
I am relying heavily on webpack's resolve.alias to cater for different build outputs and I have come across an issue.
When running a specific build, ts-loader is throwing an error saying it can not find a module that is used in the current build. This, I would assume, is due to the alias pointing to a different file.
eg:
file: myApp.ts
import {Logger} from 'logger';
export class myApp {}
I have two alias JSON files, one is setup to point 'logger' at remoteSystemLogger.ts, and another which points at consoleLogger.ts
Build A will use remoteSystemLogger,
Build B will use consoleLogger
Now each logger class will import their relative dependencies. For instance:
file: remoteSystemLogger.ts
import {HTTP} from 'http';
export class Logger {}
The problem is, that when I run build B, I am getting an error saying:
ERROR in remoteSystemLogger.ts
error TS2307: Cannot find module 'http'.
http as well as remoteSystemLogger is currently not specified in the alias JSON file for Build B, as Build B should have no dependency on it.
The alias file that get's used for the webpack build is determined at build time via a param.
Here is an example of the resolve used in webpack config
let moduleAliasingConfig = `./alias/${buildType}.json`
// ....
resolve: {
root: [
path.resolve('.'),
path.resolve('node_modules')
],
alias: moduleAliasingConfig,
extensions: ['', '.ts', '.js']
},
And here is the ts-loader config:
loaders: [
{test: /\.ts$/, loaders: ['ts'], exclude: [/\.(spec|e2e)\.ts$/]}
]
I am not sure if maybe I have miss-configured something, or this is an issue with either the loader, webpack's resolver, or just my understanding of how the aliasing works.
As my understanding is, that webpack will traverse through my import/dependency tree, based on the alias file and my entry point.
Additional env info:
package.json setup:
"ts-loader": "^1.2.1",
"webpack": "^1.13.0"

Prevent web pack from bundling react

How do I prevent webpack from bundling react?
Currently I am writing a library that causes a You've loaded two copies of React on the page. error after distribution. I suspect that webpack starts bundling all dependencies, including devDependencies.
Is there any way around that?
In my case it should be possible for the library to get React out of node_modules.
So what I basicly want is, instead of webpack resolving the require('React), it should just leave require('React) untouched.
You can use webpack externals.
externals: {
// Use external version of React
"react": "React"
}
UPD Detailed docs on the resulting code generated for externals.
To make webpack "leave require('React) untouched" you need the following config
{
output: { libraryTarget: 'commonjs' },
externals: { react: true }
...
}
Moelalez, just like Yury Tarabanko stated, externals option allows you import an existing API into applications. For context, say you want to use React from a CDN via a separate tag and still declare it as a dependency via require("react") in your application, you would use externals option to specify that.

Resources