I want to create page wise bundle for react redux project.
How can we achieve this using webpack?
For simple react application we follows following way for multi entry
module.exports = {
entry: {
'index' : './src/index.js',
'contact' : './src/pages/contact.js'
}
};
But how can we do same thing with react redux application.
I have a problem with using Lerna.
My folders structure are like shown below:
packages
myapp
shared
myapp represents a create-react-app structure and shared contains some functions that is returning as below:
import React from 'react'
import Card from '#material-ui/core/Card';
function Hello(){
return (
<Card>
This is a test
</Card>
)
}
When I use material ui components instead of DIV's i get error that says:
Invalid hook call. Hooks can only be called inside of the body of a function component.
But when I use div and other html elements it works fine.
Maybe I got this error because of babel loader? I don't know what to do and how to setup things.
This happens because you have multiple versions of React installed, and more than one get's bundled into the app.
Try to add this to your webpack config:
config.resolve.alias = {
'react': path.join(__dirname, '..', '..', '..', 'node_modules', 'react'), // Adjust for your path to root node_modules
};
I have my create-react-app bootstrap workspace setup to support module imports using #app/ as my root module.
I achieve this by adding this to my webpack config
alias: {
// Support React Native Web
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
'react-native': 'react-native-web',
'#app': path.resolve(__dirname, '../src')
},
However this does not seem to work with my jest tests. Anytime something is imported with #app the import is not resolved.
Anyone have a good solution to this
The Problem:
I'm trying to create a website (web app) with React and Material UI, it's working just fine using npm. But when I try to make them as externals and import them through a CDN instead, I get an error with Material UI (React works fine).
My Code:
I linked CDNs in index.html like this:
<script src="https://unpkg.com/react#16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/#material-ui/core/umd/material-ui.production.min.js"></script>
<script src="app.min.js"></script>
And in app.min.js, I imported them like this:
import { Component } from 'react';
import ReactDOM from 'react-dom';
import { Button } from '#material-ui/core';
My Attempt:
In the webpack.config.js, I tried the following (again, only Material UI causes an error):
Using a string:
externals: {
'react': 'React',
'react-dom': 'ReactDOM',
'#material-ui/core': 'Button'
}
gives:
Uncaught ReferenceError: Button is not defined
Using an object:
externals: {
'react': 'React',
'react-dom': 'ReactDOM',
'#material-ui/core': {
Button: '#material-ui/core'
}
}
gives:
TypeError: Cannot read property 'Button' of undefined
Doing it manually, so Material UI isn't in externals:
externals: {
'react': 'React',
'react-dom': 'ReactDOM'
}
Then removing minified Material UI code from app.min.js, this leaves the code incomplete and it doesn't run.
Searched through GitHub issue and SO questions without any luck, some links:
How should material-ui be externalized when bundling with webpack
Externals defined in webpack.config still getting error module not found
React CDN: Webpack externals library not resolved in code
Any idea how can I solve this?
Solution::
in webpack.config.js:
externals: {
'react': 'React',
'react-dom': 'ReactDOM',
'material-ui': 'window["material-ui"]'
},
then in app.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Button } from 'material-ui';
Explanation:
If you check the cdn version of material ui js, you will find it exports its content in to material-ui namespace.
if you config webpack like:
'material-ui': 'material-ui'
webpack will compile it to:
which leads to the code looking for material and ui in global environment which does not exist. So we have to specify window["material-ui"] explicitly
Might be a little late to the party but I will add an answer which worked for me.
step 1:
add the script tag from unpkg. The difference between this and cdnjs is that unkpg have an option for umd. May or may not be an issue in your particular situation. It is for me.
url:
https://unpkg.com/#material-ui/core#4.11.0/umd/material-ui.production.min.js
script tag:
<script src="https://unpkg.com/#material-ui/core#4.11.0/umd/material-ui.production.min.js"></script>
step 1b:
add the font and font icon external resources as described in the material-ui docs:
material-ui getting started - installation guide
roboto font:
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
font icons:
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
step 2:
destructure the elements you want to use from window.MaterialUI or use the square bracket notation (but unnecessary here since this package ditched the '-' char.
const { Button } = window['MaterialUI'];
step 3:
use the element as you 'normally' would
<Button variant="contained" color="primary">
Primary
</Button>
I have just solved this issue after spending way too much time on this issue while trying to build an app using a micro-frontend architecture.
TL;DR;
The solution is to put the following in the webpack.config.js:
module.exports = {
// rest of the config clipped for brevity
externals: {
'react': 'React',
'react-dom': 'ReactDOM',
'react-router-dom': 'ReactRouterDOM',
'#material-ui/core': 'MaterialUI'
}
};
Further details:
I was building a macro-frontend composed of multiple micro-frontends. Each of the micro-frontends was developed in React, exported as a web-component, and would be independently deployed such that each micro-frontend would be available via a URL like:
http://foo.example.com/main.js
http://bar.example.com/main.js
http://baz.example.com/main.js
These would be imported into the macro-app using a <script> tag.
The macro-app was hosted on a separate domain, e.g., http://example.com.
The issue I was facing was that Material UI (and possibly React as well) was being initialized multiple times in each of the micro-apps.
To avoid that, I had to externalize all these libraries using the webpack config block above.
I had to make 2 concessions.
I did not use create-react-app and react-scripts to scaffold the macro-app because that setup would hide the webpack config. In order to expose the webpack config, I could either eject the CRA project, or use some other modules, such as react-app-rewired, etc. That felt like too much work. The downside of this was that I could not use BrowserRouter and had to accept using HashRouter for client-side routing.
I could not use SvgIcon-based icons from #material-ui/icons, because I could not find a good way of externalizing Material UI Icons. Instead, I put in a link to Material UI Icons stylesheet, and opted to use Icon from #material-ui/core/Icon to render icons. using SvgIcon-based icons was causing Material UI to be initialized in the micro-apps too, which is what I was trying to avoid. One upside of the workaround is that Icon works with Font Awesome as well, so at least all icons would be written consistently in code.
Overall, I am happy with the end results.
TL;DR: I'm getting build files that are way too big. I want them to be small and use the React source files from a CDN.
My Gulp file contains this:
gulp.task('build', () => {
browserify({
entries: dirs.src + '/index.jsx',
extensions: ['.jsx'],
debug: false
})
.transform(babelify.configure({
presets: ["es2015", "react"]
}))
.bundle()
.pipe(source('index.js'))
.pipe(gulp.dest(dirs.dest));
});
And said index.jsx file contains:
import { Provider } from 'react-redux';
import slides from './stores/slides';
const store = slides();
ReactDOM.render(
<Provider store={store}>
<h1>Test</h1>
</Provider>,
document.getElementById('target')
);
React Redux is pretty small. And if I remove that part from the latter file the result is a mere 1 KB in size. Otherwise it'll turn into 700Kb+.
I already removed these two lines from that file:
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
Because I wanted to load React and ReactDOM from a CDN. Why are my files still this incredibly large?
You're currently using the development version of React. You have to build your own production version, for that the process.env.NODE_ENV flag has to be set to production.
If you're using browserify, you need envify: https://github.com/hughsk/envify
npm install envify --save-dev
Your Gulpfile.js
var envify = require('envify/custom');
//...
.transform(babelify.configure({
presets: ["es2015", "react"]
}))
.transform(envify({
NODE_ENV: 'production'
}))
//...
More resources: http://dev.topheman.com/make-your-react-production-minified-version-with-webpack/
I'm loading Ready through script tags from a CDN. I don't want to have the entire React codebase in my own local project files.
In this case, your production Webpack config should specify React in externals config option:
{
// ...
externals: {
"react": "React",
"react-dom": "ReactDOM"
},
// ...
}
Otherwise Webpack will bundle it.
Also verify that you don’t have a devtool option in the production config. It can bloat the code immensely if you use 'eval' or even inline sourcemaps.
I know uglify, but I don't want my code uglified
You should be using uglify for your code in production. This is the only way to have small builds.