I am trying to use the webpack dev-server with hot enabled in a React library - the main goal is to enable HMR.
However, whenever the serve
completes, it seems to delete the bundle file.
$ clear && npx webpack serve --mode=development
<i> [webpack-dev-server] Project is running at: "/tmp/webpack-dev-server.sock"
<i> [webpack-dev-server] Content not from webpack is served from '/usr/local/src/foo/View/public' directory
asset bundle_ff16b3001589ab53ae37.js 6.39 MiB [emitted] [immutable] (name: main)
orphan modules 1010 KiB [orphan] 233 modules
runtime modules 28.5 KiB 14 modules
cacheable modules 5.65 MiB
modules by path ./node_modules/ 5.26 MiB 219 modules
modules by path ./src/ 394 KiB
modules by path ./src/components/ 389 KiB 90 modules
modules by path ./src/lib/ 2.42 KiB
modules by path ./src/lib/util/*.ts 778 bytes 2 modules
+ 2 modules
modules by path ./src/*.js 2.72 KiB
./src/export.js 1.06 KiB [built] [code generated]
./src/constants.js 808 bytes [built] [code generated]
./src/helpers.js 899 bytes [built] [code generated]
external "React" 42 bytes [built] [code generated]
external "ReactDOM" 42 bytes [built] [code generated]
webpack 5.90.3 compiled successfully in 8966 ms
...
$ ll public
total 0
const webpack = require('webpack');
const path = require('path');
const fs = require('fs');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
/**
* Path resolver - automatically resolve alias from @folder into ./src/folder
* @type {string}
*/
const srcDir = path.resolve(__dirname, 'src');
const aliases = fs.readdirSync(srcDir)
.filter((item) => fs.statSync(path.join(srcDir, item)).isDirectory())
.reduce((acc, item) => {
acc[`@${item}`] = path.join(srcDir, item);
return acc;
}, {});
let config = {
entry: path.join(__dirname, 'src/export.js'),
watchOptions: {
aggregateTimeout: 200,
poll: 1000,
},
module: {
rules: [
{
test: [/\.js$/, /\.jsx$/],
exclude: [/node_modules/],
loader: 'babel-loader'
},
{
test: [/\.tsx?$/, /\.ts?$/],
exclude: [/node_modules/],
use: 'ts-loader'
},
{
test: /\.css$/,
exclude: [/node_modules/],
loader: 'css-loader'
},
{
test: /\.scss$/,
exclude: [/node_modules/],
use: ['style-loader', 'css-loader', 'sass-loader']
},
{
test: /\.(png|jpe?g|gif)$/i,
exclude: [/node_modules/],
type: 'asset/resource'
},
{
test: /\.svg$/,
type: 'asset',
use: ['@svgr/webpack'],
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/inline',
loader: 'url-loader',
}
]
},
plugins: [
new webpack.LoaderOptionsPlugin({
options: {
globalObject: '(typeof self !== \'undefined\' ? self : this)'
}
}),
new webpack.ProvidePlugin({
process: 'process/browser',
}),
],
resolve: {
fallback: {
'process/browser': require.resolve('process/browser'),
},
alias: {
...aliases,
'@scss': path.resolve(__dirname, 'src/static/scss'),
},
extensions: ['', '.js', '.jsx', '.ts', '.tsx']
},
output: {
path: path.join(__dirname, '/public'),
library: {
name: 'foo',
type: 'umd'
},
filename: 'bundle_[contenthash].js',
clean: true
},
externals: {
'react': 'React',
'react-dom': 'ReactDOM'
},
};
module.exports = (env, argv) => {
if (argv.mode === 'production') {
config.optimization = {
...config.optimization,
minimizer: [new TerserPlugin({
extractComments: false,
})],
minimize: true,
plugins: [
...config.plugins,
new CleanWebpackPlugin()
]
};
} else {
config = {
...config,
// development by default
mode: 'development',
devServer: {
hot: true,
ipc: true,
watchFiles: ['./src/**/**'],
},
};
}
return config;
};
Webpack dev-server keeps the bundle in memory and not statically, as reproduced from the above example.
To preserve the bundle in the disk, the webpack-dev-middleware has to be used with the writeToDisk
option.
devServer: {
devMiddleware: {
writeToDisk: true,
},
hot: true
}