As webpack continues to grow in popularity, more tooling evolves for a smooth development experience. This is true for a story with webpack and ASP.NET together as well, at least if you're running .NET Core. I want to share a framework-neutral setup with a satisfactory experience independent of ASP.NET version.
I'll describe how to:
Integrate webpack 4 with ASP.NET MVC 5
Use webpack's development server
Get started with Hot Module Replacement (HMR)
Getting started
The first thing to do, in the root of your web project, is to install webpack and its CLI. Run npm install webpack webpack-cli --save-dev. Once installed, I recommend adding a convenience task in package.json for executing webpack.
"scripts":{"test":"echo \"Error: no test specified\" && exit 1","build":"webpack"}
If you try npm run build, you'll likely get an error stating Can't resolve './src'. To fix this, a configuration file for webpack will come in handy. In the root of your project, add a webpack.config.js file with the following content:
module.exports ={// point this path to your entry,// your non-minified start fileentry:"./Scripts/main.js"};
Once saved, webpack is now configured to build your JavaScript application and output in into the folder ./dist. For now, ASP.NET has no understanding of webpack's output. Let's start integrating.
webpack 💝 ASP.NET
To be able to reference webpack's output in ASP.NET, use npm to install razor-partial-views-webpack-plugin(opens in a new window). The plugin extends webpack's build with capability to generate Razor views for webpack assets. Which assets to create views for are configurable.
With the plugin for generating Razor views configured, a webpack build outputs a main.cshtml. The partial view's content is a script tag referencing webpack's built JavaScript file.
With webpack integrated with ASP.NET, let's build on that to enhance the development experience. webpack-dev-server provides automatic page refresh and hot swapping of modules, which saves you from restarting the whole application after code updates. Install the development server with npm and extend package.json to run it for serving webpack's assets.
"scripts":{"test":"echo \"Error: no test specified\" && exit 1","start":"webpack-dev-server --hot","build":"webpack"}
Update webpack.config.js to include devServer and signal that assets no longer are served from ./dist folder. These configuration updates also function as scaffolding for partial views used in ASP.NET.
output:{// assets served by webpack-dev-serverpublicPath:"https://localhost:8080/"},devServer:{// output assets to disk for ASP.NETwriteToDisk:true,// clearly display errorsoverlay:true,// include CORS headersheaders:{"Access-Control-Allow-Origin":"*"},// use self-signed certificatehttps:true}
Run npm start and start your ASP.NET web application. Open your browser's development tools and take notice of Loading failed for the <script> with source "https://localhost:8080/main.js". The reason for the error, is the browser not trusting the development server's self-signed certificate. For now, browse to https://localhost:8080/ to accept the certificate. We'll get to a proper fix shortly.
Browse back to the web application and see your JavaScript code running. Now we reap rewards of our work. In the development console you should have webpack's development server signaling Hot Module Replacement enabled and Live Reloading enabled. Make a JavaScript update and notice the browser refresh. Happy times!
Trusted development certificate
I recommend generating a trusted development certificate for webpack-dev-server. That'll smoothen cross-browser testing, without having to hack about with getting your browser to trust a self-signed certificate. mkcert(opens in a new window)provides the feature to create an ample certificate. Install the tool, and run the setup of a local certificate authority. Thereafter, generate a development certificate in your web project root.
# Install local certificate authority> mkcert -install# Generate development certificate> mkcert localhost
Once the certificate is generated, update webpack's devServer configuration to start using it. Afterwards, your browser will consider the connection to the development server as secure.
const fs =require("fs");module.exports ={/*...*/devServer:{writeToDisk:true,overlay:true,headers:{"Access-Control-Allow-Origin":"*"},// use development certificatehttps:{cert: fs.readFileSync("./localhost.pem"),key: fs.readFileSync("./localhost-key.pem")}}}
Hot Module Replacement
So far, you've gained automatic page refresh when updating JavaScript. This alone is an improvement compared to full recycle via Visual Studio's Start Debugging. With Hot Module Replacement (HMR) the feedback loop is tightened even more.
HMR enables swapping updated modules without reloading the page. When you update front-end code, take notice of the message [HMR] Aborted because [module] is not accepted.
Hot Module Replacement is activated by signaling to webpack if and when changes are accepted by using the module.hot API. Pay attention to side-effects (like appending elements to DOM), as they likely have to be accounted for before modules are reapplied.
import{ create }from"./state-picker";const statePicker =create();
document.body.prepend(statePicker);// is HMR activated?// don't activate in productionif(module.hot){// accept changes// for this module and dependencies
module.hot.accept();
module.hot.dispose(()=>{// prevent multiple
statePicker.remove();});}
Include module.hot.accept() in your JavaScript code. You'll notice how the page doesn't refresh on every update. Instead webpack knows what modules have been updated. Great success!
Build for production
webpack comes with decent defaults for managing development and production builds. Over time, you'll likely need to adapt your configuration more granular according to target environment. For now, adapt webpack's output configuration to match your production environment (e.g. use of CDN). Ensure paths and cache busting are properly configured.
To run a production build, execute npm run build -- --mode=production (yes, that's four hyphens, so consider another npm script).
webpack is a powerful toolbox to utilize for delivering front-end assets. One use case I thoroughly recommend using it for, is to evolve legacy applications. webpack comes with support for multiple module systems, which enables migration scenarios, like updating from AMD to ES modules.
Plugins like razor-partial-views-webpack-plugin(opens in a new window)takes the webpack ecosystem closer to ASP.NET's. Try it out! Adopt the habit of running webpack in a terminal on the side. I hope you'll appreciate it as much as I do.