nx react module federation hot reload - reactjs

I'm using module federation with nx and want to enable HMR.
I applied the hmr: true option in both project.json files. (for the host and the remote).
The problem that its working only for the remote, and when changing the code in the host project its not working and not updating it in the browser.
this is the configuration for the host project.json (I'm using nx server):
"serve": {
"executor": "#nrwl/react:module-federation-dev-server",
"defaultConfiguration": "development",
"options": {
"buildTarget": "client:build",
"hmr": true,
"port": 4200
},
"configurations": {
"development": {
"buildTarget": "client:build:development",
"open": true,
"watch": true,
"liveReload": true
},
"production": {
"buildTarget": "client:build:production",
"hmr": false
}
}
}
and this is in the remote project.json
"serve": {
"executor": "#nrwl/react:module-federation-dev-server",
"defaultConfiguration": "development",
"options": {
"buildTarget": "assets:build",
"hmr": true,
"port": 4201
},
"configurations": {
"development": {
"buildTarget": "assets:build:development"
},
"production": {
"buildTarget": "assets:build:production",
"hmr": false
}
}
}

It's not working with HMR. Well never got to make it work. But using live reload witht following config its working fine. I can even debug TS with source maps.
module.exports = merge(custom, common, {
mode: 'development',
output: {
filename: '[name].[contenthash].js',
path: path.join(__dirname, 'dev'),
publicPath: 'auto',
},
devServer: {
static: path.join(__dirname, 'dev'),
hot: false,
liveReload: true,
port: infinisoft.moduleFederation.devport
},
plugins: [
new MFLiveReloadPlugin({
port: infinisoft.moduleFederation.devport,
container: name,
standalone: true
}),
new ReactRefreshWebpackPlugin(),
new MinChunkSizePlugin({
minChunkSize: 10000, // Minimum number of characters
}),
moduleFederation,
new MiniCssExtractPlugin(),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, 'src', 'config', 'index.html'),
}),
],
devtool: 'source-map',
});

Related

Browser tab freezes when running webpack-dev-server in development mode using remote Module Federation module

Dependency versions:
webpack: 5.73.0
webpack-dev-server: 4.9.2
This occurs when running a host application via webpack-dev-server that consumes micro-apps via ModuleFederationPlugin.
Example host config:
module.exports = {
entry: path.resolve(__dirname, "src/index.js"),
mode: "development", // success when changed to "production"
devServer: {
port: 3000,
client: {
overlay: false,
},
},
output: {
path: path.resolve(__dirname, "./build"),
publicPath: "/",
filename: "[name].[contenthash].js",
clean: true,
},
module: {
rules: [
{
test: /\.jsx?$/,
loader: "babel-loader",
exclude: /node_modules/,
options: {
presets: ["#babel/preset-react"],
},
},
],
},
plugins: [
new ModuleFederationPlugin({
name: "Host",
remotes: {
ExampleModule: `ExampleModule#${
process.env.LOCAL_MODULE
? `http://localhost:3001/`
: "https://example.com/examplemodule/"
}remoteEntry.js`,
},
shared: [
{
react: { version: "16.13.0", singleton: true },
"react-dom": { version: "16.13.0", singleton: true },
},
],
}),
new HtmlWebpackPlugin({
template: path.join(__dirname, "public/index.html"),
}),
],
};
Example module config:
module.exports = {
entry: path.resolve(__dirname, "src/index.js"),
mode: "development", // set to "production" for build that is served statically
devServer: {
static: { directory: path.join(__dirname, "public") },
port: PORT,
},
output: {
path: path.resolve(__dirname, "./build"),
publicPath:
process.env.NODE_ENV === "development"
? `http://localhost:${PORT}/`
: "https://example.com/examplemodule/",
filename: "[name].[contenthash].js",
clean: true,
},
resolve: {
extensions: [".js", ".jsx"],
},
module: {
rules: [
{
test: /\.jsx?$/,
loader: "babel-loader",
exclude: /node_modules/,
options: {
presets: ["#babel/preset-react"],
},
},
],
},
plugins: [
new ModuleFederationPlugin({
name: "ExampleModule",
library: { type: "var", name: "ExampleModule" },
filename: "remoteEntry.js",
exposes: {
"./ExampleModule": "./src/ExampleModule",
},
shared: [
{
react: { version: "16.13.0", singleton: true },
"react-dom": { version: "16.13.0", singleton: true },
},
],
}),
new HtmlWebpackPlugin({
template: path.join(__dirname, "public/index.html"),
}),
],
};
When running both the host and ExampleModule via webpack-dev-server, the app works, consuming the module from localhost:3001 without issue.
However, when running the host via webpack-dev-server and consuming the production build of the module from a remote URL (using https://example.com/examplemodule/remoteEntry.js in the example above), the page becomes completely unresponsive immediately after the remote entry file is fetched. There is no output in the JavaScript console due to this, and there is no feedback in the CLI output, so there are no error messages to report. This occurs in any browser, and I am on macOS Monterey.
This only occurs when running webpack-dev-server for the host in the "development" Webpack mode. Switching to production mode will fix this issue. It also will not occur when serving the static build of the host, regardless of the Webpack mode used when creating the build.
Unfortunately, this is difficult to reproduce. I attempted to make an isolated example with a React host and remote module using the same dependencies and very similar webpack configs, but I cannot reproduce the issue this way yet, so it may be specific to application code I cannot share. I'm wondering if anyone else has experienced this.

React 17 and webpack 5 not working in IE11

I have looked into everything I could about the migration to react 17 and webpack 5. This for an application that is also running on IE11. And after all the changes (as you will see in the code) , according to evrything I read, it still doesnt work. I get the same error . When I look at the bundle and open it, there is a const there, which belongs to es6. It means that there was not translation, despite all the babel change I made.
If someone has an idea what could be done it would great!
Here is my webpack fike:
const webpack = require('webpack');
const path = require("path");
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const autoprefixer = require('autoprefixer');
const Dotenv = require('dotenv-webpack')
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const smp = new SpeedMeasurePlugin();
const nodeEnv = process.env.NODE_ENV || "development"
const simulateProd = process.env.SIMULATE_PROD
const isProdEnv = nodeEnv === 'production'
const isNotDevEnv = nodeEnv !== "development"
const buildPath =
const sourcePath =
const imagesPath =
const iconsPath =
const soundsPath = ;
// Common plugins
const plugins = [
new webpack.ProvidePlugin({
Buffer: ['buffer', 'Buffer'],
process: 'process/browser',
}),
new MiniCssExtractPlugin(),
new webpack.LoaderOptionsPlugin({
options: {
postcss: [
autoprefixer(),
],
context: sourcePath,
},
}),
new CopyWebpackPlugin(
{
patterns: [
{from: iconsPath, to: 'icons'},
{from: imagesPath, to: 'images'}
]
}
),
new Dotenv({
systemvars: true
}),
new HtmlWebpackPlugin({
template: path.join(sourcePath, 'index.html'),
path: buildPath,
filename: 'index.html',
}),
]
// Common rules
const rules = [
{
test: /\.(js|jsx)$/,
loader: 'babel-loader',
exclude: /node_modules/,
options: {
plugins: ['react-hot-loader/babel'],
presets: ["#babel/preset-env"] //Preset used for env setup
}
// use: [
// 'babel-loader',
// ],
},
{
test: /\.s[ac]ss$/i,
exclude: /node_modules/,
use: [
{
// creates style nodes from JS strings
loader: "style-loader",
// options: {sourceMap: true}
},
// Translates CSS into CommonJS
{
loader: 'css-loader',
options: {
importLoaders: 1,
url: false,
modules: {localIdentName: "[path]___[name]__[local]___[hash:base64:5]"}
}
},
{
loader:"resolve-url-loader"
},
{
// compiles Sass to CSS
loader: "sass-loader",
options: {
sourceMap: true
}
},
],
},
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "style-loader", 'css-loader'],
},
{
test: /\.(ico|jpe?g|png|gif|svg|mp3|html)$/,
include: [imagesPath, soundsPath],
type: 'asset/resource',
// use: 'file-loader',
// generator: {
// filename: '[path][name].[ext]'
// },
},
{
test: /\.md$/,
use: 'raw-loader'
}
]
if (isProdEnv) {
// Production plugins
plugins.push(
new TerserPlugin({
// cache: true,
parallel: true,
// sourceMap: true
})
)
}
else {
// Development plugins
}
module.exports = smp.wrap({
mode : isNotDevEnv ? 'production' : 'development',
target: ['web', 'es5'],
experiments: {
asset: true
},
devtool: isNotDevEnv ? false : 'source-map',
context: sourcePath,
entry: {
js: ['react-hot-loader/patch','./index.js'],
},
output: {
path: buildPath,
publicPath: '/',
filename: "bundle.js",
assetModuleFilename: '[path][name].[ext]'
},
module: {
rules,
},
resolve: {
extensions: ['.webpack-loader.js', '.web-loader.js', '.loader.js', '.js', '.jsx', '.md', '.scss', '.css'],
modules: [
path.resolve(__dirname, 'node_modules'),
sourcePath,
],
fallback: {
"buffer": require.resolve('buffers'),
"assert": require.resolve('assert/'),
"fs": false,
"os": false,
"path": false,
"zlib": require.resolve('browserify-zlib'),
"stream": require.resolve('stream-browserify'),
"crypto": false,
} ,
},
plugins,
optimization : {
moduleIds: 'named',
sideEffects: isProdEnv,
},
devServer: {
contentBase: isNotDevEnv ? buildPath : sourcePath,
historyApiFallback: true,
port: 8080,
compress: isNotDevEnv,
inline: !isNotDevEnv,
hot: !isNotDevEnv,
host: "localhost",
disableHostCheck: true,
stats: {
assets: true,
children: false,
chunks: false,
hash: false,
modules: false,
publicPath: false,
timings: true,
version: false,
warnings: true,
colors: {
green: '\u001b[32m',
},
},
},
});
Here is my babel.config.json file:
{
"presets": [
[
"#babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": "3",
"targets": {
"browsers": ["last 5 versions", "ie >= 9"]
}
}
],
"#babel/preset-typescript",
"#babel/preset-react"
],
"plugins": [
"#babel/plugin-proposal-object-rest-spread",
["#babel/plugin-proposal-decorators", { "legacy": true }],
"react-hot-loader/babel",
"#babel/plugin-transform-arrow-functions",
"#babel/plugin-proposal-optional-chaining",
"#babel/plugin-proposal-nullish-coalescing-operator",
"#babel/plugin-proposal-class-properties",
[
"#babel/plugin-transform-modules-commonjs",
{
"allowTopLevelThis": true
}
]
]
}
at the start of my src/index.js
there is that :
require('es6-promise/auto')
require('string.prototype.startswith')
require('string.prototype.endswith')
import 'react-app-polyfill/ie11';
import "react-app-polyfill/stable";
import "core-js/stable";
import "regenerator-runtime/runtime";
in my package.json I added that:
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all",
"IE 11"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version",
"IE 11"
]
},
Thank you !

Cross-env not changing env variable when running yarn

I am trying to setup the environment so that when i choose to run prod it runs the prod settings and when i choose to run dev it runs the dev server, currently my package.json scrips look like this :
"scripts": {
"build:dev": "cross-env NODE_ENV=developement webpack",
"build:prod": "cross-env NODE_ENV=production webpack",
"start:dev": "cross-env NODE_ENV=developement webpack-dev-server ",
"start:prod": "cross-env NODE_ENV=production webpack-dev-server "
},
webpack config file:
const webpack = require("webpack");
const path = require("path");
const dotenv = require("dotenv");
module.exports = {
//Entry file for webpack.config
entry: "./src/index.js",
//Target specific use of project ie. nodejs project we use node value
target: process.env.NODE_ENV === "dev" ? "node" : "web",
//Dev server meant for hosting local server for developement
devServer: {
contentBase: path.resolve(__dirname, "public"),
historyApiFallback: true,
port: 8080,
},
//Modules are used to set rules to build specific file types
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: [
{
loader: "babel-loader",
options: {
presets: ["#babel/env", "#babel/react"],
plugins: [
"#babel/plugin-transform-runtime",
"#babel/plugin-proposal-class-properties",
],
},
},
],
},
{
test: /\.(png|jpe?g|gif)$/i,
loader: 'file-loader',
options: {
name: '[path][name].[ext]',
},
},
{
test: /\.(css|sass|scss)$/,
use: [
"style-loader",
{
loader: "css-loader",
options: {
sourceMap: true,
importLoaders: 2,
},
},
{
loader: "sass-loader",
options: {
sourceMap: true,
},
},
],
},
{
test: /\.svg$/,
use: [
{
loader: "svg-inline-loader",
options: {
limit: 10000,
},
},
],
},
{
test: /\.tsx?$/,
use: "ts-loader",
exclude: /node_modules/,
},
],
},
externals: {
// require("jquery") is external and available
// on the global var jQuery
"jquery": "jQuery"
},
//Changes how modues are resolved
resolve: {
extensions: ["*", ".js", ".jsx", ".ts", ".tsx"],
},
//Output is setup to serve the bundle.js file to be served to web browser
output: {
path: path.resolve(__dirname, "public"),
filename: "bundle.js",
publicPath: "/",
},
//Prevent bundling of certain packages
externals: {
"react-native": true,
},
//A javascript object used to do various extra things for webpack
plugins: [
new webpack.DefinePlugin({
"process.env": JSON.stringify(dotenv.config().parsed),
}),
],
};
and i do:
console.log(process.env.NODE_ENV)
inside my homepage jsx, but everytime I run it even when i do yarn start:prod it console.logs development and not production, why is cross-env not successfully changing the NODE_ENV to production when i run this?
In order to copy env variable into webpack, you have to use webpack. DefinePlugin as you have done in your configuration file which looks like you're trying to copy all things into webpack.
Anyway if you want to use the value from cross-env, you would have do the same thing by using DefinePlugin plugin but input the specific value NODE_ENV as following:
webpack.config.js
{
// ...
plugins: [
// ...
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
}),
],
}

when i try to run my webpack-dev-server, it gives me following error, that module is not found

[![const path = require("path");
const webpack = require("webpack");
module.exports = {
mode: "development",
entry: "./src/app.js",
output: {
path: path.resolve(__dirname, "assets", "scripts"),
filename: "app.js",
publicPath: "./src",
},
devServer: {
hot: true,
host: "0.0.0.0",
port: 4000,
open: true,
},
module: {
rules: [{
test: /.css$/,
use: ["style-loader", "css-loader"],
}, ],
},
plugins: [
new webpack.optimize.UglifyJsPlugin({
//..
}),
],
};]1]1
i have change my command "webpack-dev-server" to "webpack serve" in my package.json file and my code is now working..

VSCode debugging on running webpack-dev-server, skips breakpoints

I have debugger for chrome extension installed. I run my app using
webpack-dev-server -d --config webpack.dev.js --inline
I'm running a react app, all source codes are under /src folder. I have js, ts and tsx files. When I put a breakpoint on render function, editor properly breaks execution, but when I put a breakpoint to an onClick event of a button, it doesn't break, it just continues the execution of the code.
related part of my webpack config is as follows:
mode: 'development',
devtool: 'source-map',
entry: {
bundle: [
'#babel/polyfill',
'react-hot-loader/patch',
`webpack-dev-server/client?http://${host}:${devPort}`,
'webpack/hot/only-dev-server',
path.resolve(__dirname, 'src/index.js'),
],
},
output: {
path: path.resolve(__dirname, 'public'),
publicPath: '/',
filename: '[name].[hash:16].js',
chunkFilename: '[id].[hash:16].js',
},
devServer: {
inline: true,
port: devPort,
contentBase: path.resolve(__dirname, 'public'),
hot: true,
writeToDisk: true,
publicPath: '/',
historyApiFallback: true,
host,
}
and my launch.json is as below:
{
"type": "chrome",
"request": "launch",
"name": "Launch Chrome",
"url": "http://localhost:8080",
"webRoot": "${workspaceFolder}/src",
"sourceMaps": true,
"sourceMapPathOverrides": {
"webpack:///./src/*.js": "${workspaceRoot}/src/*.js",
"webpack:///./src/*.tsx": "${workspaceRoot}/src/*.tsx",
"webpack:///./src/*.ts": "${workspaceRoot}/src/*.ts",
"webpack:///./node_modules/*": "${workspaceRoot}/node_modules/*"
}
}
What I'm missing?
I got this to work by using inline-source-map in my config file:
{
devtool: 'inline-source-map',
// ....
}
Now it works properly and breaks wherever I put the breakpoint.
I was facing the same issue with create-react-app. In webpack.config.js (after ejecting) I changed devtool: isEnvProduction? shouldUseSourceMap ? "inline-source-map" instead of "source-map" and now my breakpoints are constantly hitting!
Thanks for the tip!

Resources