How to configure ASP.NET 6 HMR with UseProxyToSpaDevelopmentServer using webpack 5 and devserver 4 - webpack-dev-server

I successfully configured ASP.NET5 with Webpack4 to use HMR previously. Now, I tried to upgrade all to new versions and I couldn't make the HMR work at all.
The problem is: when I start (debug) the ASP.NET web app it shows me a '/ not found' page. It looks like the UseProxyToSpaDevelopmentServer redirects all requests to the Webpack DevServer which has no index.html at all because I just want to use it to provide HMR functionality for the ASP.NET site.
Here are all version changes:
net5.0 > net6.0
webpack: v4.43.0 > v5.64.4
webpack-cli v3.3.12 > v4.9.1
webpack-dev-server v3.11.0 > v4.6.0
The ASP.NET code is the same:
app.UseSpa(spa =>
{
spa.UseProxyToSpaDevelopmentServer("http://localhost:8888");
});
The ASP.NET web site url is: https://localhost:44331
The DevServer configuration changed because there are lot of changes between v3 and v4 (https://github.com/webpack/webpack-dev-server/blob/master/migration-v4.md).
This is the previous (which was working) devServer config:
devServer: {
compress: true,
contentBase: false,
hot: true,
port: 8888,
public: 'https://localhost:44331',
publicPath: '/dist', //this is a subfolder under the wwwroot
serveIndex: false,
},
This is the new (which is not working) devServer config:
devServer: {
hot: true,
port: 8888,
host: 'localhost',
client: {
webSocketURL: 'https://localhost:44331', //V3: devServer.public
},
devMiddleware: {
publicPath: '/dist', //V3: devServer.publicPath
},
static: false //V3 ?
}
I'm not sure about the 'static' property (the contentBase was false previously) but I don't really think that can cause the problem.

Try this I think?
devMiddleware: {
index: false, // If false (but not undefined), the server will not respond to requests to the root URL.
publicPath: '/dist'
},

Related

SSE doen't work with vue-cli devServer proxy

I recently move from vue-cli 4.5.x to 5.0.x.
Since this upgrade it seems Server Sent Events (SSE) doesn't work any more with the WebPack Dev Server.
(I'm currently using vue-sse)
Note in production it works perfectly.
My devServer config looks like :
devServer: {
proxy: {
"/api": {
target: "http://localhost:8080",
ws: true,
changeOrigin: true,
},
},
},
It seems possible workarounds are :
Disable compression in the webpack devserver config.
Send Content-Type: no-transform in the response header.
(source : https://composed.blog/sse-webpack-dev-server)
I didn't test the 2. way but the 1. works for me.
devServer: {
proxy: {
"/api": {
target: "http://localhost:8080",
ws: true,
changeOrigin: true,
},
},
// To disable compression :
compress: false
},
If this doesn't help maybe you face this similar issue : https://forum.vuejs.org/t/server-sent-events-are-not-working-with-vue-cli-devserver-proxy-and-node-16-0/125450

Why does webpack dev server not auto reload page on changes when started from gitpod terminal?

The project is https://github.com/easychessanimations/htmltest .
I studied all the answers related to webpack dev server auto page reload.
When I do npm run start locally, it auto builds / reloads page on source change, so the dev server config must be right:
devServer: {
contentBase: path.join(__dirname, "dist"),
port: 8080,
hot: true,
watchContentBase: true,
watchOptions: {
poll: true
},
},
When I do the same from the gitpod terminal, online, the page is auto rebuilt, but not auto reloaded ( no matter whether I open it in a gitpod window or in a full blown browser tab ). If I reload manually, the changes are reflected.
What extra config do I need to make it work under gitpod?
You can play around with it using this link ( of course first you need to authorize gitpod with your github account ):
https://gitpod.io/#https://github.com/easychessanimations/htmltest
in the gitpod terminal type:
npm install
npm run build
npm run start
Webpack HMR needs to be configured accordingly.
Adding the following three properties to the webpack.conf does the trick:
devServer: {
// make HMR work - start
host: '0.0.0.0',
disableHostCheck: true,
public: require('child_process').execSync('gp url 8080').toString().trim(),
// make HMR work - end
contentBase: path.join(__dirname, "dist"),
port: 8080,
hot: true,
watchContentBase: true,
watchOptions: {
poll: true
},
},
Here is a working snapshot:
https://gitpod.io/#snapshot/daa14130-2f44-430d-93ab-2d4ed980fc2c

React with Webpack not displaying errors

I'm running react with HMR using webpack. When a function is deleted in a server or used shared service is deleted, no errors are emitted, neither in the console nor on the terminal.
This error can not be seen even during the build process.
I've waisted at least a day trying to find a solution for it. Any help is appreciated.
thank you.
const DEV_SERVER = {
contentBase: PATHS.public,
hot: true,
open: true,
hotOnly: true,
historyApiFallback: true,
overlay: true,
port: 3000,
// stats: 'verbose',
// proxy: {
// '/api': 'http://localhost:8888'
// },
More Details
if i have user.service.ts imported in an index.ts file and use in all the other files, then i delete the user.service.ts file.
Expected Behaviour: An error with module not found.
Current Behaviour: Nothing is showing in the console or terminal.
React v 16.13
Webpack v 4.41
Check the source maps used, this worked for me:
devtool: 'cheap-module-source-map'
Did you try the error-overlay-webpack-plugin?
const ErrorOverlayPlugin = require("error-overlay-webpack-plugin");
module.exports = {
plugins: [new ErrorOverlayPlugin()]
);
https://www.npmjs.com/package/error-overlay-webpack-plugin

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

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.
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"
})
]
});
In my opinion, Kram's answer should be marked as accepted as it really gives what's needed. I've spent some time setting up a .NET Core/React/Webpack project recently, and I could not get the spa.UseReactDevelopmentServer to work, but the spa.UseProxyToSpaDevelopmentServer works like a charm. Thanks Kram!
Here are my few gotchas they might help someone:
webpack.config.js (excerpt):
const path = require('path');
const webpack = require('webpack');
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'build.[hash].js',
},
devServer: {
contentBase: path.resolve(__dirname, 'public'),
publicPath: '/dist',
open: false,
hot: true
},
plugins: [
new webpack.HotModuleReplacementPlugin()
]
DevServer sets its root by publicPath property and completely ignores the output.path property in the root. So even though your output files (for prod) will go to dist folder, under webpack server they will be served under a root by default. If you want to preserve the same url, you have to set publicPath: '/dist'.
This means that your default page will be under http://localhost:8083/dist. I could not figure out a way to place assets under subfolder while keeping index in the root (other than hardcode the path for assets).
You need HotModuleReplacementPlugin in order to watch mode to work and also hot: true setting in the devServer configuration (or pass it as a parameter upon start).
If you (like me) copy some dev server configuration with open: true (default is false), you will finish up with two browsers opened upon application start as another one is opened by the launchSettings "launchBrowser": true. It was a bit of a surprise at the first moment.
Also, you will have to enable CORS for your project otherwise your backend calls will get blocked:
Startup.cs (excerpt):
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy(name: "developOrigins",
builder =>
{
builder.WithOrigins("http://localhost:8083");
});
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
app.UseCors("developOrigins");
}
If anything else will come to my mind I will update the answer, hope this helps to someone.
Webpack 5 update
webpack-dev-server command doesn't work anymore. Use:
"build:hotdev": webpack serve --config webpack.config.development.js
You might also need to add target: 'web' to your webpack.config.js in Webpack 5 to enable hot module reload to work:
module.exports = {
target: 'web'
}
Alternatively you might need to create a browserlist file. Hope this issue gets fixed soon.
You mention VS. My solution is good for Visual Studio, but not VS Code.
I use WebPack Task Runner: https://marketplace.visualstudio.com/items?itemName=MadsKristensen.WebPackTaskRunner
This adds webpack.config.js tasks into the "Task Runner Explorer" in Visual Studio, and you can then bind those tasks to events like "Before Build" or "After Build"
Extension is here : AspNetCore.SpaServices.Extensions
You could find examples here : https://github.com/RimuTec/AspNetCore.SpaServices.Extensions
With core 3.1 or 5.0
React with webpack
using :spaBuilder.UseWebpackDevelopmentServer(npmScriptName: "start");

Remove server from react-boilerplate

How should one do to remove server folder from react-boilerplate? Question is also asked here by another person https://github.com/react-boilerplate/react-boilerplate/issues/2110.
Removing just server folder will not work because the webpack dev configuration is utilising it for hot reload as well as your npm start command starts express server from this folder.
If you want to remove server folder completely and still want the application to be working as it was like hot reloading etc, follow the below steps. We will require webpack dev server in that case:
Remove ./server folder manually.
Install webpack-dev-server and react-hot-loader as dev dependencies.
In your ./internals/webpack/webpack.dev.babel.js, do the following modifications:
Change entry to this:
entry: [
require.resolve('react-app-polyfill/ie11'),
'react-hot-loader/patch',
`webpack-dev-server/client?http://localhost:3000/`,
'webpack/hot/only-dev-server',
path.join(process.cwd(), 'app/app.js'), // Start with js/app.js
],
Add publicPath in output:
output: {
filename: '[name].js',
chunkFilename: '[name].chunk.js',
publicPath: `http://localhost:3000/`,
},
Add webpack dev server config property in the same file:
devServer: {
port: 3000,
publicPath: `http://localhost:3000/`,
compress: true,
noInfo: false,
stats: 'errors-only',
inline: true,
lazy: false,
hot: true,
open: true,
overlay: true,
headers: { 'Access-Control-Allow-Origin': '*' },
contentBase: path.join(__dirname, '..', '..', 'app', 'build'),
watchOptions: {
aggregateTimeout: 300,
ignored: /node_modules/,
poll: 100,
},
historyApiFallback: {
verbose: true,
disableDotRule: false,
},
},
In ./internals/webpack/webpack.base.babel.js, add the line:
devServer: options.devServer,
And finally, modify your start script in package.json as below:
"start": "cross-env NODE_ENV=development node --trace-warnings ./node_modules/webpack-dev-server/bin/webpack-dev-server --color --config internals/webpack/webpack.dev.babel.js",
And you are good to go!!
Just remove with rm -rf ./server if you feel harassed :)

Resources