How can I get hot reloading (HMR) running with Webpack 5? - javascript

I am trying to get HMR running with webpack v5, but it does not work. When I modify and save a file, webpack re-compiles the project correctly, but the frontend does not update.
I read this article and followed the instructions: https://webpack.js.org/guides/hot-module-replacement/
This is my webpack config:
{
mode: 'development',
entry: {
babelpoly: 'babel-polyfill',
app: [ './src/index.js', './src/app.js' ]
},
plugins: [
BundleStatsWebpackPlugin { ... },
DefinePlugin { ... },
HtmlWebpackPlugin { ... }
],
stats: { ... },
output: {
path: '[pathTo]/dist',
filename: '[name].bundle.js',
chunkFilename: '[name].bundle.js'
},
optimization: {
splitChunks: { chunks: 'all' },
runtimeChunk: 'single',
usedExports: true,
mergeDuplicateChunks: true
},
module: {
rules: [
{
test: /\.(s[ac]ss)$/i,
include: path.resolve(ROOT, 'src'),
use: [
'style-loader', // Creates `style` nodes from JS strings
{
loader: 'css-loader', // Translates CSS into CommonJS
options: {
modules: {
mode: 'local',
localIdentName: devMode
? '[name]_[local]-[hash:base64:3]'
: '[local]-[hash:base64:5]',
},
},
},
{
loader: 'sass-loader', // compiles Sass to CSS
options: {
implementation: require('sass'),
},
},
],
},
{
test: /\.css$/,
include: [path.join(ROOT, 'node_modules')],
use: ['style-loader', 'css-loader'],
},
{
test: /\.(png|svg|jpg|gif)$/,
use: ['file-loader'],
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: ['file-loader'],
},
{
test: /\.m?jsx?$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: [
[
'#babel/preset-env',
{
useBuiltIns: 'entry',
corejs: 3,
},
],
'#babel/preset-react',
],
plugins: [['#babel/plugin-proposal-class-properties', {loose: true}]],
},
},
},
],
},
resolve: {
extensions: [ ... ],
alias: {
...
},
modules: [
...
]
},
devtool: 'inline-source-map',
devServer: {
port: 3003,
contentBase: '[pathTo]/dist',
host: '0.0.0.0',
hot: true,
compress: true,
disableHostCheck: true,
historyApiFallback: true,
overlay: { warnings: true, errors: true },
stats: { ... }
}
}
I am using:
webpack 5.7.0
webpack-cli 4.2.0
react 16.13
node 14.15.1
npm 6.14.8
I start webpack with this command: webpack serve --host 0.0.0.0 --config config/webpack.dev.js
What do I do wrong? Thanks for your help. :)

I believe it's a bug in webpack-dev-server v3 https://github.com/webpack/webpack-dev-server/issues/2758 when you're using it with webpack 5 and browserslist. You can wait for webpack-dev-server v4 https://github.com/webpack/webpack-dev-server/pull/2592#issuecomment-734400875, it will come soon, or use target: 'web' for the moment under your development mode.

Related

Webpack shows white screen

After I've added webpack in my react app, once the webpack started, it shows the white screen, and the whole bundle gets downloaded at one time. Even though I've done code splitting in react.
my webpack config:
/* eslint-disable no-un`enter code here`def */
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const HtmlWebpackInjectPreload = require("#principalstudio/html-webpack-inject-preload");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
entry: path.resolve(__dirname, './index.js'),
devtool: "inline-source-map",
output: {
path: path.resolve(__dirname, "build"),
filename: "bundle.js",
publicPath: '/'
},
devServer: {
contentBase: path.resolve(__dirname, 'build'),
port: 4000,
hot: true,
},
resolve: {
extensions: [".*",".js", ".jsx", ".css"],
fallback: {
stream: false
}
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /(node_modules)/,
use: ["babel-loader"],
},
{
test: /\.css$/,
exclude: /\.module\.css$/,
use: ["style-loader", "css-loader"],
},
{
test: /\.module\.css$/,
use: [
"style-loader",
{
loader: "css-loader",
options: { importLoaders: 2, modules: true },
},
"postcss-loader",
],
},
{
test: /\.(jpe?g|png|gif|woff|woff2|eot|ttf|svg)(\?[a-z0-9=.]+)?$/,
use: [
{
loader: "url-loader",
options: {
limit: 8192,
},
},
],
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve('./index.html')
}),
new CleanWebpackPlugin(),
new HtmlWebpackInjectPreload({
files: [
{
match: /.*\.woff2$/,
attributes: { as: "font", type: "font/woff2", crossorigin: true },
},
{
match: /\.[a-z-0-9]*.css$/,
attributes: { as: "style" },
},
],
}),
],
};
The attached bundle image also gets larger up to 19MB. What's going wrong I'm not able to figure out.

Unknown word error in css file even with css-loader

I am getting a syntax error in one of my css files from monaco-editor in node_modules. It is an unknown word error:
> 1 | // Imports
| ^
2 | import ___CSS_LOADER_API_IMPORT___ from "../../../../../../css-loader/dist/runtime/api.js";
3 | var ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(function(i){return i[1]});
# ./node_modules/monaco-editor/esm/vs/platform/contextview/browser/contextMenuHandler.css 2:12-317 9:17-24 13:15-29
However, I have css-loader configured in my webpack.config.js:
const HtmlWebPackPlugin = require("html-webpack-plugin");
const PerspectivePlugin = require("#finos/perspective-webpack-plugin");
const path = require("path");
const plugins = [
new HtmlWebPackPlugin({
title: "Perspective React Example",
template: "./src/frontend/index.html",
}),
new PerspectivePlugin(),
];
module.exports = {
context: path.resolve(__dirname),
entry: "./src/frontend/index.tsx",
mode: "development",
devtool: "source-map",
resolve: {
extensions: [".ts", ".tsx", ".js"],
},
plugins: plugins,
module: {
rules: [
{
test: /\.ts(x?)$/,
//exclude: /node_modules/,
loader: "ts-loader",
},
{
test: /\.css$/,
//exclude: /node_modules/,
use: [
"style-loader",
{
loader: "css-loader",
options: {
importLoaders: 1,
},
},
'postcss-loader'
],
},
],
},
devServer: {
// superstore.arrow is served from here
contentBase: [
path.join(__dirname, "dist"),
path.join(__dirname, "node_modules/superstore-arrow"),
],
},
experiments: {
executeModule: true,
syncWebAssembly: true,
asyncWebAssembly: true,
},
output: {
filename: "app.js",
path: __dirname + "/dist",
},
};
I also have a config file for postcss-loader:
module.exports = {
plugins: [
require('autoprefixer')
]
};
I'm not sure what is wrong with what I'm doing, so I'm wondering if there is another loader I need to add to webpack.config.js or if my configuration is incorrect?
I had same issue, try this:
use: [
"style-loader",
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
[
"postcss-preset-env",
{
// Options
},
],
],
},
},
},
],

Separate the config API with dev and prod webpack

Please tell me, here is the config.js file in it, the exported variable with a reference to the API, but there is an API for the dev version, and there is a separate API for the prod version, as I understand it, you need to make 2 separate files, but how to make it in webpack so that when dev he used one file, and prod another?
Below added webpack configuration files, a project on react.js (if that makes any difference :) )
rules.js
const rules = [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: ['babel-loader'],
},
{
test: /\.eot(\?v=\d+.\d+.\d+)?$/,
use: [
{
loader: 'url-loader',
options: {
name: '[name].[ext]',
},
},
],
},
{
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
use: [
{
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'application/font-woff',
name: '[name].[ext]',
},
},
],
},
{
test: /\.[ot]tf(\?v=\d+.\d+.\d+)?$/,
use: [
{
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'application/octet-stream',
name: '[name].[ext]',
},
},
],
},
{
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
use: [
{
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'image/svg+xml',
name: '[name].[ext]',
},
},
],
},
{
test: /\.(jpe?g|png|gif|ico)$/i,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
},
},
],
},
];
export default rules;
webpack.config.common.babel.js
import path from 'path';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import Dotenv from 'dotenv-webpack';
import rules from './utils/rules';
const config = (env) => {
const PUBLIC_PATH = env.production ? '/' : '/';
return {
entry: {
index: './src/index.js'
},
output: {
publicPath: PUBLIC_PATH,
path: path.resolve(process.cwd(), 'dist'),
filename: env.production ? '[name].js' : '[name].bundle.js'
},
resolve: {
alias: {
'react-dom': '#hot-loader/react-dom',
app: path.resolve(process.cwd(), 'src/app/'),
store: path.resolve(process.cwd(), 'src/store/'),
ui: path.resolve(process.cwd(), 'src/ui/')
},
extensions: ['*', '.js', '.jsx', '.json', 'scss']
},
module: {
rules
},
node: {
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty'
},
plugins: [
new Dotenv({
systemvars: true
}),
new HtmlWebpackPlugin({
template: 'public/index.html',
favicon: 'public/favicon.ico',
inject: true,
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true
}
})
]
};
};
export default config;
webpack.config.dev.babel.js
import webpack from 'webpack';
import path from 'path';
import merge from 'webpack-merge';
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
import common from './webpack.config.common.babel';
const config = env => merge(common(env), {
devtool: 'cheap-module-eval-source-map',
target: 'web',
mode: 'development',
optimization: {
minimize: false
},
performance: {
hints: false
},
devServer: {
historyApiFallback: true,
contentBase: '../dist',
port: 3009,
hot: true,
clientLogLevel: 'none'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: ['babel-loader', 'eslint-loader']
},
{
test: /(\.css|\.scss|\.sass)$/,
use: [
{
loader: 'style-loader',
options: { singleton: true }
},
{
loader: 'css-loader'
},
{
loader: 'postcss-loader',
options: {
/* eslint-disable global-require */
plugins: () => [require('autoprefixer')],
sourceMap: true
}
},
{
loader: 'sass-loader',
options: {
includePaths: [path.resolve(__dirname, 'src', 'scss')]
}
}
]
}
]
},
plugins: [
new webpack.NamedModulesPlugin(),
// new BundleAnalyzerPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
new webpack.HotModuleReplacementPlugin()
]
});
export default config;
webpack.config.common.babel.js
import path from 'path';
import webpack from 'webpack';
import merge from 'webpack-merge';
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import common from './webpack.config.common.babel';
const config = env => merge(common(env), {
devtool: 'source-map',
target: 'web',
mode: 'production',
optimization: {
minimize: true,
nodeEnv: 'production',
sideEffects: true,
concatenateModules: true,
runtimeChunk: 'single',
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
},
},
},
},
module: {
rules: [
{
test: /(\.css|\.scss|\.sass)$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
sourceMap: true,
},
},
{
loader: 'postcss-loader',
options: {
/* eslint-disable global-require */
plugins: () => [require('cssnano'), require('autoprefixer')],
sourceMap: true,
},
},
{
loader: 'sass-loader',
options: {
includePaths: [path.resolve(__dirname, 'src', 'scss')],
sourceMap: true,
},
},
],
},
],
},
plugins: [
new webpack.HashedModuleIdsPlugin(),
new MiniCssExtractPlugin({
filename: '[name].[chunkhash].css',
})
],
});
export default config;
You can define two different npm scripts and use the --config flag for custom files (/file-paths):
"build:dev": "webpack --config ./webpack.client.dev.js",
"build:prod": "webpack --config ./webpack.client.prod.js"
For the common you have to use webpack-merge, for example:
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'production',
...
});

Coverage reports with karma and a mix of javascript and typescript src files

I have a project where I use webpack for development/testing and karma as my test runner. This project has source files written half in js and half in ts/tsx. The test suite is written completely in js. I currently use karma-coverage, which shows coverage reports for all my js source files, but it does not support typescript files. All my tests run, there is no problem there, I just would like coverage reports for all my test files. Can anyone point me in the right direction?
Here is my karma.conf.js if this helps.
'use strict';
const webpackCfg = require('./webpack.config')('test');
module.exports = function karmaConfig(config) {
config.set({
browsers: ['Chrome'],
files: [
'test/loadtests.js'
],
port: 8080,
captureTimeout: 60000,
frameworks: [
'mocha',
'chai',
'sinon'
],
client: {
mocha: {}
},
singleRun: true,
reporters: ['mocha', 'coverage', 'junit'],
mochaReporter: {
output: 'autowatch'
},
preprocessors: {
'test/loadtests.js': ['webpack', 'sourcemap']
},
webpack: webpackCfg,
webpackServer: {
noInfo: true
},
junitReporter: {
outputDir: 'coverage',
outputFile: 'junit-result.xml',
useBrowserName: false
},
coverageReporter: {
dir: 'coverage/',
watermarks: {
statements: [70, 80],
functions: [70, 80],
branches: [70, 80],
lines: [70, 80]
},
reporters: [
{ type: 'text' },
{
type: 'html',
subdir: 'html'
},
{
type: 'cobertura',
subdir: 'cobertura'
},
{
type: 'lcovonly',
subdir: 'lcov'
}
]
}
});
};
And the relevant part of my webpack test config
{
devtool: 'inline-source-map',
externals: {
cheerio: 'window',
'react/lib/ExecutionEnvironment': true,
'react/addons': true,
'react/lib/ReactContext': true,
},
module: {
preLoaders: [
{
test: /\.(js|jsx)$/,
loader: 'isparta-loader',
include: [
this.srcPathAbsolute
]
}
],
loaders: [
{
test: /\.cssmodule\.css$/,
loaders: [
'style',
'css?modules&importLoaders=1&localIdentName=[name]-[local]-[hash:base64:5]'
]
},
{
test: /^.((?!cssmodule).)*\.css$/,
loader: 'null-loader'
},
{
test: /\.(sass|scss|less|styl|png|jpg|gif|mp4|ogg|svg|woff|woff2)$/,
loader: 'null-loader'
},
{
test: /\.json$/,
loader: 'json'
},
{
test: /\.ts(x?)$/,
exclude: /node_modules/,
loader: ['babel', 'ts-loader']
},
{
test: /\.(js|jsx)$/,
loader: 'babel-loader',
query: {
presets: ['airbnb']
},
include: [].concat(
this.includedPackages,
[
this.srcPathAbsolute,
this.testPathAbsolute
]
)
}
]
},
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': '"test"'
})
]
}
After a couple days of soul and google searching amongst hundreds of browser tabs, I have found a working solution. This is using TypeScript 2.x and Webpack 2.x. test.js is my entry point. It could just as easily be test.ts (and it will be eventually). In that entry point, I load my *.spec.js and *.spec.ts files. And then those files import whichever source they need to test from. I have put all the webpack config in the karma.conf.js so it's easier to see:
let myArgs = require('yargs').argv;
let path = require('path');
let webpack = require('webpack');
module.exports = function(config) {
const REPORTS_PATH = myArgs.reportsPath ? myArgs.reportsPath :path.join(__dirname, 'build');
config.set({
basePath: '',
frameworks: ['jasmine', 'es6-shim'],
files: [
'./test.js'
],
exclude: [],
reporters: ['progress', 'spec', 'coverage', 'junit', 'coverage-istanbul'],
preprocessors: {
'./test.js': ['webpack', 'sourcemap']
},
webpackServer: {
noInfo: true // prevent console spamming when running in Karma!
},
webpack: {
devtool: 'inline-source-map',
resolve: {
modules: [
path.resolve('./node_modules'),
path.resolve('./')
],
extensions: ['.js', '.ts', '.css', '.scss']
},
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery"
})
],
module: {
rules: [
{
enforce: 'pre',
test: /\.js$/,
use: 'source-map-loader',
exclude: [/node_modules/]
},
{
test: /\.ts$/,
use: [{
loader: 'awesome-typescript-loader',
options: {
module: 'commonjs'
},
}]
},
{
test: /\.js$/,
use: [{
loader: 'awesome-typescript-loader',
options: {
entryFileIsJs: true,
transpileOnly: true
}
}],
exclude: [/node_modules/],
},
{
enforce: 'post',
test: /\.(js|ts)$/,
use: [{
loader: 'istanbul-instrumenter-loader',
options: {
esModules: true
}
}],
exclude: [/node_modules/, /\.spec\.(js|ts)$/, /test/]
},
{ test: /\.html/, use: 'raw-loader' },
{ test: /\.(s)?css$/, use: 'null-loader' },
{ test: /\.(png|jpg|jpeg|gif|svg|pdf)$/, use: 'null-loader' },
{ test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, use: 'null-loader' },
{ test: /\.(ttf|eot)(\?v=[0-9]\.[0-9]\.[0-9])?$/, use: 'null-loader' },
{ test: /\.json$/, use: 'null-loader' }
]
}
},
coverageReporter: {
type: 'in-memory'
},
coverageIstanbulReporter: {
//TODO: Figure out why the 'html' reporter blows up with istanbul-reports (something with absolute path copying files)
reports: ['text-summary', 'cobertura'],
// base output directory
dir: REPORTS_PATH,
fixWebpackSourcePaths: true,
'report-config': {
cobertura: {
file: 'coverage.xml'
},
'text-summary': {
file: null
}
}
},
junitReporter: {
outputDir: `${REPORTS_PATH}/junit/`,
outputFile: 'jasmine-results.xml'
},
// Hide webpack build information from output
webpackMiddleware: {
stats: {
chunkModules: false,
colors: true
},
noInfo: 'errors-only'
},
colors: true,
logLevel: config.LOG_ERROR,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false,
autoWatchBatchDelay: 400
});
};
So, the key pieces here are awesome-typescript-loader, karma-coverage-istanbul-reporter, source-map-loader, and in the tsconfig.json, you want to set these in compilerOptions:
"inlineSourceMap": true,
"sourceMap": false,
I indicated a TODO about the html report. It DOES work but I couldn't get it to output to a custom directory (subdir) with TypeScript files as a part of it. JavaScript only worked fine. Could be a windows-specific problem with istanbul-reports. If you add html to the reports array under coverageIstanbulReporter, you should see it in your project dir but may have problems putting it in REPORTS_PATH.
It's also worth noting that I had a lot of luck using karma-remap-coverage instead of karma-coverage-istanbul-reporter but the former would not correctly generate cobertura reports for coverage which is what I needed for Jenkins.

Keep getting [WDS] Disconnected! error, ReactJs, Webpack

This question relates to post: Keep getting [WDS] Disconnected! error
I have updated my webpack config settings according to the answers, however I still the "[WDS] Disconnected! error" within the console.
Please any suggestions?
webpack.config.js
var webpack = require("webpack");
var path = require("path");
module.exports = {
devtool: "inline-source-map",
entry: [
"webpack-dev-server/client?http://127.0.0.0:8080/",
"webpack/hot/only-dev-server",
"./src"
],
devServer: {
contentBase: "./public",
hot: true,
inline: true,
quiet: false,
noInfo: true,
stats: { colors: true }
},
output: {
path: path.join(__dirname, "./public"),
filename: "./assets/js/bundle.js"
},
resolve: {
modulesDirectrories: ["node_modules", "src"],
extentions: ["", ".js"]
},
module : {
loaders: [
{
test: /\.jsx?$/,
exclude: "/node_modules/",
loaders: ["react-hot-loader", "babel?presets[]=react,presets[]=es2015"]
},
{
test: /\.css$/,
loader: "style-loader!css-loader"
},
{
test: /\.gif$/,
loader: "url-loader?mimetype=image/png"
},
{
test: /\.woff(2)?(\?v=[0-9].[0-9].[0-9])?$/,
loader: "url-loader?mimetype=application/font-woff"
},
{
test: /\.(ttf|eot|svg)(\?v=[0-9].[0-9].[0-9])?$/,
loader: "file-loader?name=[name].[ext]"
}
]
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
new webpack.DefinePlugin({
"process.env": {
NODE_ENV: JSON.stringify("development")
}
})
]}
Change the transportMode to ws instead of "sock-js.node":-
devServer: {
transportMode: 'ws',
injectClient: false,
}
This will be solved by Enabling Error Overlay,
overlay:true include one more property in devServer object
devServer: {
...
overlay: true,
}
click here for more info webpack-dev-server

Categories

Resources