Using VueJs with ASP.NET Razor Can be Great!
I have been using VueJs with ASP.NET Core Razor for a couple years now and I find that the two technologies work well together. If you are interested in why I selected Vue, you can read about that here: Why I picked VueJs for my Asp.Net Core Web development. As I mention in that post, Vue works really well as a way to add reactiveness to web pages, and that’s true even for HTML generated using Razor. So that’s what I want to talk about. If that sounds interesting, keep reading.
Once this architecture has been implemented, each page has the power of Razor and the power of Vue at its disposal.
Web Page Approach, not SPA
My development work primarily involves building out an ecommerce website that has hundreds of pages. I prefer the web page approach rather than the SPA (single page app) approach for such development.
I have this preference for the following reasons:
Loading Vue.js Directly, without webpack
I chose to load Vue as a single file from a CDN rather embracing a module bundler like webpack. Early on I looked in to webpack and thought perhaps I might utilize the SPA approach for non-public areas of the website like the “My Account” area. However I found webpack configuration to be complicated and not well documented. It’s important to me that the front end code base is approachable to junior developers and introducing webpack felt like a step in the wrong direction.
Another downside, and this is also a biggie, is that this approach means that I can’t use most open source Vue Components straight away without modification. The use of webpack and ES6 is so ubiquitous at this point that most open source Vue Components are using it. Again, for me, that’s an OK tradeoff. Vue Components are still an option, they just need to be written in ES5 in a manner that works with vue.js directly rather than needing webpack.
ASP.NET Razor vs Vue.js
Since I do use both ASP.NET Razor and Vue.js together, I often have a choice of whether I should use Vue or Razor for a given aspect of generating the user experience. Let me start by saying that I find both Razor syntax and Vue syntax to be very intuitive, so that’s not typically a driver in the decision. As you may guess, my first choice is almost always Razor (for SEO and security reasons) unless the level of interactivity needed on the page requires that Vue be used for that aspect. And even when that’s the case, if it’s a public facing page, I tend to use Razor to fully generate the initial rendering of the page for SEO reasons. The HTML sent to the browser will contains Vue attributes and once Vue takes control of the page it can provide reactivity and can reconfigure the DOM as much as needed.
Even for non-public facing pages, I will use Razor right up to the point where I can’t get the desired behavior without using Vue. So again Razor will generate much of the page with the HTML including Vue attributes and then when the page loads, Vue will take it from there.
I find that in practice this approach works well, and often the question isn’t really should I use Razor more heavily or Vue more heavily on this page, the question typically is more along the lines of “what are the features and use cases that need supported by this page?” And then the technology to lean more heavily on is often obvious.
Architectural Approach Overview
When implementing Vue on the website the first decision I had to make was whether vue would be used on every page of the website or just some of the pages. But once I realized that I’d like to use it for functionality in the header of the page like signing into an account and displaying how many items are in the cart, it became clear that I would be using vue on ever page of the website.
We are all use to the idea that common areas of the website are defined in the _layout.cshtml file. Typically this is where the HTML for the header and footer portions of the site are located. So to me it just makes sense that if the site will be using Vue to support functionality manifested in the header, then one good place to instantiate vue is in the _layout.cshtml file. So that’s the approach I chose. A simplified example might be something like this:
Given that the _layout.cshtml file is responsible for setting up vue, every page that uses that layout can count on the fact that vue will be available without needing to do anything to make that happen. Also, the page will have access to any vue data, methods, or components that are declared in the _layout.cshtml file when vue is instantiated. That feels like the way it should be. Here’s an example of what a page.cshtml might look like:
The first thing to notice is that the page doesn’t have to do any setup for vue other than specifying to use _layout.cshtml. Then notice that Vue is being used in two ways on this page.
appMessagedata property is being displayed on the page
v-ifvue directive is used to display only one of the two buttons.
But what if the page needs to have some page specific vue data or functionality? Vue Mixins to the rescue! Vue has this cool concept called a Mixin. In a Mixin you can define most anything that can be defined via the options passed when the Vue instance is created including: data, methods, computed properties, event hooks, and such.
So the approach I chose for implementing page specific vue data and functionality was to create a pageMixin on that page and push that mixin into a global mixin array which the _layout.cshtml page utilizes when it creates the vue instance. A simplified example of that might look something like this:
var mixinArray = ;
In this, example 2, we can see how a mixin can be used to provide page specific Vue data. We can also see that data used in a simple way to create reactivity.
Then the “Toggle 1” button is clicked it will toggle whether Button 1 is visible or not. As you can see the code to make this happen is trivial and begins to show the power of the reactivity system.
Some care does need to be taken so that the names of methods and data properties don’t conflict between the mixin and the vue instance options. In cases where the do conflict the Vue instance options will prevail.
Mixin for Group of Pages
Again, it’s important to avoid having duplicate names for data, methods, computed properties, etc amongst the mixins used by the page and the options used to create the vue instance. If there is a name collision amongst the mixins, then the last one in the mixin array wins. This works out to be kind of a feature in that it makes it possible for a method in one mixin to be overridden by another mixin provided that other mixin is loaded afterwards into the mixin array. In practice, even on a large webstite, I haven’t had much of an issue avoiding name collisions and I’ve yet to need to override a method in one mixin with the method in another but this approach does make that a possibility if needed.
Its also easy to specify a vue component for use globally by including it's declaration in the _layout.cshtml file, or to specify a view component to be used on a page by declaring it on that page or declaring it in a partial view that is included in the page. Perhaps in the future I will do a blog article on this.
I hope that this blog post has helped you see how this non-traditional approach to integrating Vue with Razor can create interesting possibilities. Once this architecture has been implemented, each page has the power of Razor and the power of Vue at its disposal. I hope you will give this approach a try and let me know what you think. This blog doesn’t currently have commenting ability but you can tweet me your thoughts at @dotnetcore. Have fun with it.
The code for this blog post is available on github.