webpack-dev-server and WASM HMR

I’m trying to make a real time shooter game on the web using ThreeJS and Rapier. Rapier is a physics engine written in rust and can be used in JS using the WASM module. Now in development webpack-dev-server and HMR are really a god given tool, if it works. The RAPIER WASM module gets loaded but from the wrong port. My HTTP server runs on http://localhost:8080 but the devserver on -:9000. The fetch mechanism that webpack uses to get the WASM doesn’t configure the port for the fetch. Is this a bug or misconfiguration on my end?

My webpack.config.js:

const dotenv = require('dotenv');
dotenv.config();

const path = require('path');
const zlib = require('zlib');

const CompressionPlugin = require('compression-webpack-plugin');
const ThreadsPlugin = require('threads-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const WebpackBar = require('webpackbar');
const { WebpackManifestPlugin: ManifestPlugin } = require('webpack-manifest-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');

const DEBUG = process.env.NODE_ENV !== 'production';
const FILENAME = DEBUG ? '[name]' : '[name].[contenthash]';
const CHUNK_FILENAME = DEBUG ? '[name]' : '[id].[contenthash]';

module.exports = {
    mode: DEBUG ? 'development' : 'production',

    entry: { bundle: path.join(__dirname, 'resources/js/bundle.js') },

    output: {
        path: path.join(__dirname, 'public'),
        filename: FILENAME + '.js',
        chunkFilename: CHUNK_FILENAME + '.js',
        publicPath: '',
        clean: true,
    },

    module: {
        rules: [
            {
                test: '/.m?js$/',
                exclude: /(node_modules|bower_components)/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env']
                    }
                }
            },
            { test: /.(frag|vert)$/, use: 'raw-loader' },
            {
                test: /.(sa|sc|c)ss$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    { loader: 'css-loader', options: { importLoaders: 2 } },
                    'postcss-loader',
                    'sass-loader',
                ]
            },
            { test: /.(png|svg|jpg|jpeg|webm|gif)$/i, type: 'asset/resource' },
            { test: /.(woff|woff2|eot|ttf|otf)$/i, type: 'asset/resource' },
            { test: /.svelte$/, use: { loader: 'svelte-loader', options: {
                emitCss: false,
                hotReload: DEBUG,
                compilerOptions: { dev: DEBUG },
                hotOptions: {
                    preserveLocalState: false,
                    noReload: false, // prevent reload after fatal error
                    acceptAccesssors: true,
                    acceptNamedExports: true
                }
            } } },
            { test: /node_modules/svelte/.*.mjs$/, resolve: { fullySpecified: false } }
        ]
    },

    plugins: [
        new CopyPlugin({ patterns: [
            // { from: './resources/images', to: 'images' },
            { from: './resources/textures', to: 'textures' },
            { from: './resources/scenes', to: 'scenes' },
        ] }),
        new ManifestPlugin(),
        new MiniCssExtractPlugin({
            filename: FILENAME + '.css',
            chunkFilename: CHUNK_FILENAME + '.css'
        }),
        // new ThreadsPlugin(),
        new WebpackBar(),
    ].concat(DEBUG ? [] : [
        new CompressionPlugin({
            filename: '[path][base].gz',
            algorithm: 'gzip',
            test: /.(js|css|html|svg)$/,
            threshold: 10240,
            minRatio: 0.8,
        }),
        new CompressionPlugin({
            filename: '[path][base].br',
            algorithm: 'brotliCompress',
            test: /.(js|css|html|svg)$/,
            compressionOptions: {
                params: {
                    [zlib.constants.BROTLI_PARAM_QUALITY]: 11,
                },
            },
            threshold: 10240,
            minRatio: 0.8,
        })
    ]),

    optimization: {
        minimize: true,
        minimizer: [ new TerserPlugin(), new CssMinimizerPlugin() ],

        splitChunks: {
            cacheGroups: {
                vendor: {
                    test: /[\/]node_modules[\/]/,
                    name: 'vendor',
                    chunks: 'all'
                }
            }
        }
    },

    devServer: {
        port: 9000,
        static: path.join(__dirname, 'public'),
        hot: true,
        client: {
            overlay: {
                errors: true,
                warnings: false,
            },
            progress: true,
            reconnect: 10,
            webSocketURL: {
                hostname: 'localhost',
                port: 9000,
            }
        },
        compress: true
    },
    
    devtool: DEBUG ? 'inline-source-map' : false,

    experiments: {
        asyncWebAssembly: true
    }
};

I’ve googled a fair bit for solutions but so far I haven’t found anything that looks like my particular issue.