Best way to integrate webpack builds with ASP.NET Core 3.0?

BenjiFB picture BenjiFB · Sep 24, 2019 · Viewed 12.9k times · Source

I'm upgrading my ASP.NET Core app to V3, and using Visual Studio 2019 for development / debugging. The process has been smooth except for this:

public void Configure(…..
                app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions
                {
                    HotModuleReplacement = false,
                    ReactHotModuleReplacement = false
                });

UseWebpackDevMiddleware is no more: https://github.com/aspnet/AspNetCore/issues/12890 .

I'm now looking to understand the best way to have VS run webpack every time I debug, ideally only on JS code that has changed. This was the value I was getting from UseWebpackDevMiddleware. My app is a React app, and it seems like there is some new replacement for this if your app was started from CreateReactApp, but mine was not. (I believe apps that stated from this but then separated are called "ejected.") Is it somehow possible for me to still take advantage of whatever that facility is, even though my app does not leverage CreateReactApp? Also, what is the role of CreateReactApp after it bootstraps your new React application? I imagined it would be only used for inflating template code at the first go.

What is the role of Microsoft.AspNetCore.SpaServices.Extensions in all of this?

I don't need hot module replacement; I don't need server side prerendering. I'm really just trying to understand how to get my JS to transparently build (via Webpack) as part of my debugging process. Is this something that I could hook into MSBuild for? I imagine others are going to face the same question as they upgrade.

Thanks for any suggestions.

Answer

Kram picture Kram · Oct 8, 2019

So, I was using UseWebpackDevMiddleware for HMR for a much smoother dev process - In the end I reverted to using webpack-dev-server

Steps:

1) Add package to package.json: "webpack-dev-server": "3.8.2", 2) Add webpack.development.js

const merge = require('webpack-merge');
const common = require('./webpack.config.js');
const ExtractCssPlugin = require('mini-css-extract-plugin');

const webpackDevServerPort = 8083;
const proxyTarget = "http://localhost:8492";

module.exports = merge(common(), {
    output: {
        filename: "[name].js",
        publicPath: '/dist/'
    },
    mode: 'development',
    devtool: 'inline-source-map',
    devServer: {
        compress: true,
        proxy: {
            '*': {
                target: proxyTarget
            }
        },
        port: webpackDevServerPort
    },
    plugins: [
        new ExtractCssPlugin({
            filename: "[name].css",
            chunkFilename: "[id].css"
        })
    ]
});

Note that the proxy setting here will be used to proxy through to ASP.Net core for API calls

Modify launchSettings.json to point to webpack-dev-server:

"profiles": {
    "VisualStudio: Connect to HotDev proxy": {
      "commandName": "Project",
      "launchBrowser": true,
      "launchUrl": "http://localhost:8083/",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "applicationUrl": "http://localhost:8492/"
    }
  }

(also I had some problem with configuring the right locations in webpack, and found this useful

Also, will need to start webpack-dev-server which can be done via a npm script:

  "scripts": {
    "build:hotdev": "webpack-dev-server --config webpack.development.js --hot --inline",

And then this is bootstrapped

            app.UseSpa(spa =>
            {
                spa.Options.SourcePath = "ClientApp";

                if (env.IsDevelopment())
                {
                    spa.UseReactDevelopmentServer(npmScript: "build:hotdev");
                }
            });

(or you can install the npm task runner extension and:

  "-vs-binding": {
    "ProjectOpened": [
      "build:hotdev"
    ]
  }

Alternatively I realise you can proxy the other way using the following - this way any request to under "dist" will be pushed through to the proxy webpack-dev-server

            app.UseSpa(spa =>
            {
                spa.Options.SourcePath = "dist";

                if (env.IsDevelopment())
                {
                    // Ensure that you start webpack-dev-server - run "build:hotdev" npm script
                    // Also if you install the npm task runner extension then the webpack-dev-server script will run when the solution loads
                    spa.UseProxyToSpaDevelopmentServer("http://localhost:8083");
                }
            });

And then you don't need to proxy though from that back any more and can just serve /dist/ content - both hot and vendor-precompiled using as web.config.js like this:

module.exports = merge(common(), {
    output: {
        filename: "[name].js",
        publicPath: '/dist/',
    },
    mode: 'development',
    devtool: 'inline-source-map',
    devServer: {
        compress: true,
        port: 8083,
        contentBase: path.resolve(__dirname,"wwwroot"),
    },

    plugins: [
        new ExtractCssPlugin({
            filename: "[name].css",
            chunkFilename: "[id].css"
        })
    ]
});