DEV Community

Kevin Cocquyt
Kevin Cocquyt

Posted on • Originally published at Medium on

Vue SFC’s in an ASP.NET MVC app

Inspired by Cristi Jora and this article: https://medium.com/corebuild-software/vue-js-and-net-mvc-b5cede22862, I went on and tried to add the same functionalities in our boilerplate solution for future projects.

Between the time the article was posted and when I started my implementation, webpack went from v3 to v4 and Vue introduced the vue-template-compiler (additional to the vue-loader). Luckilly, most of the workings stayed the same… Writing SFC’s as well as adding them to your page with the created custom tags. The biggest challenge was moving over the webpack configuration (and doing something extra in my case) and that’s what I’m going to talk about.

When webpack went from v3 to v4, lots of the configuration settings were made easier (coming out of the box, like production mode which minifies your code), so you will see a ‘more or less’ slimmed down version of the configuration file as used in the mentioned article.

const path = require("path");
const fs = require("fs");
const VueLoaderPlugin = require("vue-loader/lib/plugin");

const appBasePath = "./js/components/";
const jsEntries = {};

fs.readdirSync(appBasePath).forEach(name =\> {
 var indexFile = `${appBasePath}${name}/index.js`;
 if (fs.existsSync(indexFile)) {
 jsEntries[name] = indexFile;
 }
});

module.exports = {
 entry: jsEntries,
 output: {
 path: path.resolve(\_\_dirname, "../dist/js/components"),
 filename: "[name].js"
 },
 resolve: {
 alias: {
 vue$: "vue/dist/vue.esm.js"
 }
 },
 module: {
 rules: [
 {
 test: /\.vue$/,
 use: {
 loader: "vue-loader",
 options: {
 js: "babel-loader"
 }
 }
 },
 {
 test: /\.js$/,
 exclude: /node\_modules/,
 use: {
 loader: "babel-loader",
 options: {
 presets: ["[@babel/preset-env](http://twitter.com/babel/preset-env)"]
 }
 }
 },
 {
 test: /\.(css|scss)$/,
 use: ["vue-style-loader", "style-loader", "css-loader", "sass-loader"]
 }
 ]
 },
 plugins: [new VueLoaderPlugin()],
 optimization: {
 splitChunks: {
 cacheGroups: {
 commons: {
 test: /[\\/]node\_modules[\\/]/,
 name: "vendors",
 chunks: "all"
 }
 }
 }
 },
 devtool: "source-map"
};

As you can see, it starts out with the same loop creating the entries (see mentioned article for the detailed information). For output, I chose a subfolder ‘components’ within my ‘dist’ folder as it’s only used for compiling Vue components. After that, do not (!) forget the ‘resolve’ setting as, because I thought it wouldn’t be, it cost me half a day to figure out why my compiled .js files were not rendering my components. The ‘module’ settings that follow are more or less the same, except for some options here and there (adding an additional package or a simplified Babel 7 setup). ‘Plugins’ is a new part and introduced since one of the latest vue-loader updates. And, maybe the part where I’m most happy about is the optimization (see separate section underneath).

Optimization

When creating a .js file, all of the included SFC’s and imported node modules are bundled and minified into one big .js file. As I don’t need every component on every page, I create a .js file per page using the jsEntries logic. The downside with that is that every .js file would be bundled up with the Vue runtime meaning an extra +/- 100 KB per file. Luckilly, you can do some optimizations by creating an extra file (‘vendors.js’ in my case), containing all the common node modules that are used in the Vue components making for only one (cachable) file. That file can then be added in your _Layout page and the other .js files can be added per page resulting in a lot less KB’s that have to be downloaded by your users and making the components load faster too.

Without decoupling the common node modules, every page file would be +104KB

Cache busting

When you add the JS files to your webpages, those will be cached by the browser and not be updated when a new version arrives (as it’s cached on the name, which did not change). As you’re not using the built-in .NET MVC bundling module, this also means the automated cache busting technique is not applied (changing/concatenating your JS files with a hash which changes when you change the JS files). For that, you will have to implement your own style of cache busting and more information can be found here: https://madskristensen.net/blog/cache-busting-in-aspnet/

I prefer the solution with the assembly version (https://madskristensen.net/blog/cache-busting-in-aspnet/#546c01e8-b3c7-4b63-a863-a47de3dc1507) even when it means a querystring is added as it’s not best practice for Google Page Speed. Standard .NET MVC bundling is doing the exact same thing after all…

And that’s about it if you want to add Vue SFC’s to your existing ASP.NET MVC projects. I had a blog post before about Vue components (non-SFC) but it bothered me that I couldn’t use the styling bit of SFC’s so I searched on and finally came up with a solution I’m happy about.

For those interested, I added the necessary files to a github repo so you can just copy-paste the stuff from there: https://github.com/KevinCocquyt39/mvc-vue-webpack4

Happy coding!

Top comments (0)