React Boilerplate's HMR very slow when editing dependency library (node module) - reactjs

I'm using React Boilerplate which utilizes HMR (Hot Module Reload) in a dev environment.
However, I also have a custom component library which I load as a dependency. It has about 20 React components or so. The library is a UMD module which I load as a dependency through package.json in the boilerplate. It's also being built by Webpack and a build for it takes about 2 seconds.
When working locally on both projects though, I have the library linked in my boilerplate project (with 'npm link'), so I can see most recent changes.
Now, any time I make a change to anywhere in that dependency library, HMR kicks in for the boilerplate project, and that's great. But even the simplest change like a CSS color in that will take HMR around 20 seconds (!!!) to rebuild webpack in the boilerplate project.
That happens everytime the dependency is rebuilt, so 20 seconds when I make minor changes is very detrimental.
Can anyone please tell me how to mitigate that time? I feel like I am missing something. I'm running the default webpack config for boilerplate as it comes out of the box.
The dependency's webpack config is very similar to the boilerplate one, with a different output:
output: {
path: __dirname + '/dist',
filename: 'index.js',
library: 'my-component-library',
libraryTarget: 'umd',
umdNamedDefine: true,
},
The babel and style loaders are pretty much the same.
Thank you all for any suggestions that you may have.

To answer my own question, I did this:
https://github.com/uber/react-map-gl/issues/165#issuecomment-275412920
internals/webpack/webpack.base.babel.js
## ##
loaders: [{
test: /\.js$/, // Transform all .js files required somewhere with Babel
loader: 'babel-loader',
- exclude: /node_modules/,
+ include: [
+ path.resolve(process.cwd(), 'app'),
+ path.resolve(process.cwd(), 'node_modules/mapbox-gl/js'),
+ ],
query: options.babelQuery,
## ##
resolve: {
modules: ['app', 'node_modules'],
extensions: [
'.js',
'.jsx',
'.react.js',
],
mainFields: [
'browser',
'jsnext:main',
'main',
],
+ alias: {
+ 'mapbox-gl$': path.join(__dirname, '../../node_modules/mapbox-gl/dist/mapbox-gl.js'),
+ },
},
package.json
"env": {
"production": {
- "only": [
- "app"
- ],
"plugins": [
"transform-react-remove-prop-types",
"transform-react-constant-elements",
"transform-react-inline-elements"
]
},

Related

Module Federation, React, and Apollo 3 warnings

I'm building an app with micro-frontends using webpack 5's module federation plugin. Everything was fine until I started adding react hooks into my remote app. At that point I received errors about "invalid usage of hooks", i.e. I discovered I had TWO versions of react loaded, one from the remote and one from the app consuming the remote.
That problem was solved by adding a shared key to the ModuleFederationPlugin section of my webpack config that marked React as a singleton. Now everything compiles and seems to run just fine.
However, the webpack compiler is throwing some annoying warnings at me now. Its saying:
No required version specified and unable to automatically determine one. Unable to find required version for "react" in description file (/Users/myComputer/Development/myapp/node_modules/#apollo/client/react/context/package.json). It need to be in dependencies, devDependencies or peerDependencies.
Here is what my webpack config (in the remote) looks like currently:
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin')
const deps = require('./package.json').dependencies
module.exports = {
mode: 'development',
devServer: { port: 3001 },
entry: './src/index.tsx',
output: {
path: __dirname + '/dist/',
},
module: {
rules: [
{
test: /\.(ts|tsx)$/,
exclude: /node_modules/,
resolve: {
extensions: ['.ts', '.tsx', '.js', '.json'],
},
use: 'ts-loader',
},
]
},
devtool: 'source-map',
plugins: [
new ModuleFederationPlugin(
{
name: 'myRemote',
filename: 'remoteEntry.js',
exposes: {
'./App':
'./src/App/App.tsx',
},
shared: {
'react': {
singleton: true,
version: deps['react'],
},
'react-dom': {
singleton: true,
version: deps['react-dom'],
},
},
}
),
new HtmlWebpackPlugin({
template:
'./index.html',
})
]
}
The consuming app's webpack config is almost the same, especially the shared section (there are some slight differences in that it declares the remotes).
What would be the way to tell webpack that the apollo package will be getting its react dependency from somewhere else? Or if thats not the right thing to tell webpack, what is and how can I get rid of these warnings?
Fixed my own problem by changing the key version to requiredVersion

Webpack unable to find babel-loader

I'm having a bit of trouble adding react to a legacy application. While I found plenty of materials on getting started, I ran into a bunch of issues related to my particular configuration and exacerbated by my utter lack of webpack knowledge (so much time relying on react cli tools makes one lax).
My configuration:
./docs/jslib = my node_modules, that's where yarn installs modules
./docs/jscripts = my general js folder, various js scripts go there
./docs/jscripts/mini = my dist folder, some things get built/packed by gulp and end up here. This is where the built things are expected to go
./docs/jscripts/react(/react.js) = my desired root for react things, where the react.js is the entrypoint for DOM selection and rendering (at least for the first attempt).
My webpack config:
const path = require("path");
module.exports = {
entry: "./docs/jscript/react/react.js",
output: {
path: path.resolve(__dirname, "./docs/jscript/mini"),
filename: "react.js"
},
resolve: {
extensions: [".js", ".jsx"],
modules: [
path.resolve(__dirname, "./docs/jslib")
],
alias: {
'babel-loader': path.resolve(__dirname, "./docs/jslib/babel-loader")
}
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
include: [
path.resolve(__dirname, "./docs/jscript/react")
],
exclude: [
path.resolve(__dirname, "./docs/jslib")
],
use: {
loader: "babel-loader"
}
}
]
}
};
The error I get on running webpack:
yarn run v1.21.1
$ ./docs/jslib/babel-loader/node_modules/.bin/webpack --mode production
Insufficient number of arguments or no entry found.
Alternatively, run 'webpack(-cli) --help' for usage info.
Hash: 210250af48f3cf84fa4a
Version: webpack 4.41.6
Time: 75ms
Built at: 02/14/2020 9:23:09 AM
ERROR in Entry module not found: Error: Can't resolve 'babel-loader' in '/var/www/html'
I have webpack-cli, I can run webpack straight, I can run it from the modules bin folder, it's all the same problem - it can't find babel-loader even though babel-loader brings its own webpack script which I use, so the loader is obviously there in the "node_modules" that's actually on a different path.
From what I gathered, all I had to do was to add my custom node_modules path to the webpack config under the resolve settings, which has solved my initial errors related to packages not found (yet webpack still can't find the loader).
Note: if I symlink my ./docs/jslib as ./node_modules, it works as expected.
Is there something I'm missing?
Thanks!
After some digging, I found a solution and some details that other might want to keep in mind when configuring webpack in a rather non-standard context:
resolve: points to modules that are directly required in various scripts
resolveLoader: should point to the same, for the purpose of accessing loaders (which is what I needed)
Solution:
resolveLoader: {
extensions: ['.js', '.json', '.jsx'],
modules: [
path.resolve(__dirname, "./docs/jslib")
],
mainFields: ['loader', 'main']
}

Images not loading in React app with Webpack despite having file loaders (url-loader)

I have a React app that uses Webpack and Babel. I am trying to load an image anyway possible (svg, png...) but I keep getting the error "Unexpected character '�' (1:0) > 1 | �PNG". I installed url-loader (npm install url-loader --save-dev) which is supposed to help load images when using Webpack. Nothing has changed.
This is my webpack.config.js:
const {NODE_ENV} = process.env;
module.exports = {
mode: NODE_ENV === 'production' ? NODE_ENV : 'development',
entry: ['./client/index.js'],
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ['babel-loader'],
},
{
test: /\.(png|jpg|gif)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 25000
}
}
]
},
],
},
resolve: {
extensions: ['*', '.js', '.jsx'],
},
output: {
path: __dirname + '/dist',
publicPath: '/',
filename: 'bundle.js',
},
};
This is how I was trying to load my image:
import hiker from './hiker.png';
<img src={hiker} />
Any help would be greatly appreciated, thank you.
Several issues here. First, you're using babel-node that's pointing to the index.js. If you want it to point to your webpack config, then you'll need to remove index.js from the package.json's dev scripts:
"dev": "nodemon --exec babel-node",
And rename webpack.config.js to babel.config.js.
Unfortunately, there's also quite a bit more work required to get your project up-and-running. It appears that this setup uses some server-side-rendering configuration. Admittedly, I've never used koa, so I can't be of much help here.
It also appears to be a bit outdated, and someone updated it and included a walkthrough.
That said, I'd recommend steering toward a new-developer friendly boilerplate if you're just learning.
I'd suggest starting with create-react-app, which obscures a lot of this webpack configuration.
Or, you can download my react-starter-kit, which has an exposed webpack configuration that you can play around with (if desired) and utilizes webpack-dev-server for development and webpack with a very simple express configuration for production.
Up to you.
Good luck!

Babel convert path jsx to js

I am using babel to transpile some es2015 code to es5, like this:
"scripts": {
"build:lib": "babel src --out-dir lib --presets=react,es2015,stage-0",
"clean": "rimraf lib dist coverage",
"prepublish": "npm run clean && npm run build:lib"
}
It is converting it fine to es5. The problem is that babel is not changing the path among files. It changes the extension of the file from .jsx to .js, but inside the file, it is still referencing the file as .jsx.
To simplify it, the folder structure looks like this. Babel has changed the extensions of the .jsx files:
- index.js
- Component.js
While inside index.js, it is doing keeping the .jsx extension:
require('./Component.jsx');
Am I missing something? Is there a better way to do this?
Thanks for you help:)
Why won't you simply use Webpack for that? Is there a reason for that? especially that you are also missing setting up node_env production so it will avoid adding propTyping etc.
es3ify is just for changing the code, while you are trying to build a library out of it. you need a tree builder like Webpack for something like that (how es3ify would know about the references between each other?)
So tl;dr there is a better solution for that: use Webpack.
module.exports = {
devtool: 'source-map',
entry: [
path.join(__dirname, '/src/index.jsx')
],
output: {
path: path.join(__dirname, '/dist'),
filename: 'bundle.js',
publicPath: '/'
},
resolve: {
extensions: ['', '.js', '.jsx']
},
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel'
}
]
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(process.env.NODE_ENV)
}
}),
new webpack.optimize.UglifyJsPlugin({
compressor: {
warnings: false
}
})
]
};
As Shiroo suggested, I ended up using webpack for this. The key concept here was understanding what resolvers do. They are really well explained in the webpack docs: https://webpack.github.io/docs/resolving.html
resolve: {
root: path.resolve('./src'),
extensions: ['', '.js', '.jsx']
}
Later, I encountered that all the node_modules were also included in the bundle, despite having it explicitly inside the loader:
module: {
loaders: [
{
test: /(\.jsx|\.js)$/,
include: path.resolve('./src'),
exclude: /node_modules/,
loader: 'babel'
}
]
}
This issue is better explained here https://stackoverflow.com/a/35820388/4929834

Why is my Webpack ReactJS App so large?

I have followed as many tips as I can find in packaging my Webpack ReactJS app for production. Unfortunately, the file size is still 3MB. What am I doing wrong?
Here is my Webpack Config file:
var path = require('path')
var webpack = require('webpack')
module.exports = {
devtool: 'cheap-module-eval-source-map',
entry: [
'webpack-hot-middleware/client',
'./index'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle-webpack.js',
publicPath: './'
},
plugins: [
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
screw_ie8: true,
warnings: false
}
})
],
module: {
loaders: [
{
test: /\.js$/,
loaders: [ 'babel' ],
exclude: /node_modules/,
include: __dirname
},
{
test: /\.css$/,
loader: "style-loader!css-loader"
},
{test: /node_modules\/react-chatview/, loader: 'babel' }
]
}
}
Any help would be greatly appreciated!
I use the following command to package it:
> NODE_ENV=production webpack -p
I get the following output:
bundle-webpack.js 3.1 MB 0 [emitted] main
Best,
Aaron
Looks like you've still got a fair amount of dev stuff there, e.g. hot module replacement.
Take a look at webpack.config.prod.js at React Transform Boilerplate as a guide.
You may also be able to optimise your imports by including only the parts of the packages you need and leaving out the rest. See: Reduce Your bundle.js File Size By Doing This One Thing .
So, it turns out that David L. Walsh was correct that I had too much development stuff in my app. However, the answer provided did not resolve the issue.
I resolved the issue using 3 steps.
Remove all the "hot-reloading" plugins from my webpack configuration, as David instructed.
Remove the hot reloading "react-transform" plugin from my .babelrc file.
Change the "devtool" parameter to "source-map" from "cheap-module-eval-source-map"
After following those steps, the final bundle file was 340kb while the source map was still 3MB. Fortunately, I don't have to include the source map in my application, so it can be downloaded at 340kb, which is still fairly large, but reasonable for modern browsers running on modern internet connections.
I would up-vote David's answer, but I don't have enough reputation points yet to do so.

Resources