webpack 4 aspnetcore 2.2 HMR not reloading in browser

Viewed 1683

I'm unable to rule out a compatibility issue with aspnetcore 2.2 and webpack 4 or a configuration issue on my end.

I need some help spotting the configuration issue if that is the cause.

  • ASPNETCORE 2.2
  • WEBPACK 4

When I make a change to a ".tsx" file, Visual Studio outputs that webpack has rebuilt, however the browser is not refreshing and there are no messages in the console. (I do however get the initial HMR connected message in the browser console).

Visual Studio output:

Microsoft.AspNetCore.NodeServices:Information: webpack building... Microsoft.AspNetCore.NodeServices:Information: Checking started in a separate process...

754ms Microsoft.AspNetCore.NodeServices:Information: webpack built 1e45bf5f88ad514f4a12 in 4940ms

Compiled successfully. starting HTTP/1.1 GET https://localhost:44331/__webpack_hmr

webpack.config.js:

const path = require('path');
const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin;
const CleanWebpackPlugin = require('clean-webpack-plugin'); 
const webpack = require('webpack');

module.exports = (env) => {
const isDevBuild = !(env && env.prod);

const outputDir = (env && env.publishDir)
    ? env.publishDir
    : __dirname;

return [{
    mode: isDevBuild ? 'development' : 'production',

    devtool: 'inline-source-map',

    stats: { modules: false },

    entry: { 'main': './client/boot.tsx' },

    watchOptions: {
        ignored: /node_modules/
    },

    output: {
        filename: "dist/[name].js",
        path: path.join(outputDir, 'wwwroot'),
        publicPath: '/'
    },

    resolve: {   
        extensions: [".ts", ".tsx", ".js", ".json"]
    },

    devServer: {
        hot: true
    },

    module: {
        rules: [
            // All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'.
            {
                test: /\.tsx?$/,
                include: /client/,
                loader: [
                    {
                        loader: 'awesome-typescript-loader',
                        options: {
                            useCache: true,
                            useBabel: true,
                            babelOptions: {
                                babelrc: false,
                                plugins: ['react-hot-loader/babel'],
                            }
                        }
                    }
                ]
            },
            { test: /\.(png|jpg|jpeg|gif|svg)$/, use: 'url-loader?limit=25000' }
        ]
    },

    plugins: [             
        new CleanWebpackPlugin(path.join(outputDir, 'wwwroot', 'dist')),
        new CheckerPlugin()       
    ]
}];

};

Startup.cs Configure:

 if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions
            {
                HotModuleReplacement = true                 
            });
        }

package.json:

"devDependencies": {
"@babel/core": "*",
"@babel/preset-env": "*",
"@types/history": "4.6.0",
"@types/jest": "^23.3.2",
"@types/node": "^10.9.1",
"@types/react": "^16.7.13",
"@types/react-dom": "16.0.11",
"@types/react-hot-loader": "3.0.3",
"@types/react-router": "4.4.1",
"@types/react-router-dom": "4.3.1",
"@types/webpack-env": "^1.13.6",
"aspnet-webpack": "^3.0.0",
"awesome-typescript-loader": "^5.2.0",
"babel-core": "7.0.0-bridge.0",
"babel-jest": "*",
"clean-webpack-plugin": "^0.1.19",
"crypto-js": "^3.1.9-1",
"css-loader": "0.28.4",
"enzyme-to-json": "^3.3.4",
"event-source-polyfill": "0.0.9",
"extract-text-webpack-plugin": "2.1.2",
"file-loader": "0.11.2",
"file-saver": "^1.3.8",
"isomorphic-fetch": "2.2.1",
"jest": "^23.6.0",
"jquery": "^3.2.1",
"json-loader": "0.5.4",
"moment": "^2.22.2",
"raf": "^3.4.0",
"react": "^16.6.3",
"react-deep-force-update": "2.1.1",
"react-dom": "^16.6.3",
"react-hot-loader": "^4.0.0",
"react-router-dom": "4.1.1",
"react-select": "^2.0.0",
"style-loader": "0.18.2",
"ts-jest": "^23.10.3",
"ts-loader": "^2.0.1",
"typescript": "^2.9.2",
"url-loader": "0.5.9",
"webpack": "^4.15.1",
"webpack-cli": "^3.0.8",
"webpack-dev-middleware": "^3.1.3",
"webpack-hot-middleware": "^2.22.2"

EDIT: (adding boot.tsx and app.tsx to show hot module loading)

boot.tsx

   import * as React from 'react';
   import { runWithAdal } from 'react-adal';
   import * as ReactDOM from 'react-dom';
   import App from './app';
   import { authContext } from './authentication/azure/azureConfig';

   const DO_NOT_LOGIN = false;

   function renderApp() {   

       ReactDOM.render(
    <App />,
    document.getElementById('react-app')
       ); 
   }

   runWithAdal(authContext, () => {  
       renderApp();
   }, DO_NOT_LOGIN);

app.tsx

   import * as React from 'react';
   import { hot } from 'react-hot-loader';
   import { Provider } from 'react-redux';
   import * as RoutesModule from './routes';
   import { BrowserRouter } from 'react-router-dom';
   import configureStore from './store/configureStore';

   let routes = RoutesModule.routes;

   const store = configureStore({});

   const baseUrl = 
   document.getElementsByTagName('base')[0].getAttribute('href')!;

   const App: React.SFC = () => <Provider store={store}>

;

   export default hot(module)(App);
1 Answers

According to your above configuration, you're packing the js files into "wwwroot/dist/[name].js". The output information indicates that the Webpack hot reload feature is set up correctly. But it seems that Webpack has no idea on what the index page is. In other words, any changes made to *.tsx modules will only reload the compiled wwwroot/dist/main.js file.

For example, I create an App.tsx file:

import * as React from "react";
import * as ReactDOM from 'react-dom';

export const App = () => <div>Hello World!</div>

and render the App.tsx in the boot.tsx.

import * as React from "react";
import * as ReactDOM from 'react-dom';  
import {App} from "./App";

ReactDOM.render(<App/>, document.getElementById("appconainer"));

When I serve the index page by MVC or StaticFiles, and then test with your configuration, Webpack won't know it should make a request to home/index action (or some "index.htm" url) to refresh.

A possible approach to fix

Since you've installed the react-hot-loader package, one approach is to use a hot() function to convert the root component to be hot-exported:

// file: `App.tsx`
import { hot } from 'react-hot-loader/root'

export const App = () => <div>Hello World!</div>

export const HotApp = hot(App);        // make it hot-exported!

and render the hot-exported root component:

// file: root.tsx
import * as React from "react";
import * as ReactDOM from 'react-dom';
import {HotApp} from "./App";         // use the Hot-Exported component as the root component

ReactDOM.render(<App/>, document.getElementById("appconainer"));

For more details, see docs here

Related