VueJs is by far my favorite javascript framework. The topic of "Can I use X with Sitefinity" also comes up a lot. The answer is always "yes" (because the framework you use on the front end doesn't matter). In pure mvc mode the page renders everything exactly where you tell it to go.

So this tutorial is for larger sites where one might have MANY pages and MANY vue components\widgets scattered around. You don't want a 4 meg vue webpacked file loaded on every page, you just want the components needed for that page. This is the fundamental problem with a CMS where you let users design whatever they want.

Step 1: Load vue

You're going to want to open your /ResourcePackages//Mvc/Views/Layouts folder and open your main layout template... it's usually "default.cshtml" unless you've changed it.

default.cshtmlView on GitHub
@using System.Web.Mvc;
@using Telerik.Sitefinity.Frontend.Mvc.Helpers;
@using Telerik.Sitefinity.Modules.Pages;
@using Telerik.Sitefinity.UI.MVC;
@using Telerik.Sitefinity.Services;

<!DOCTYPE html> <!--[if IE 8]> <html class="no-js lt-ie9 ie8"> <![endif]--> <!--[if gt IE 8]><!--> <html class="no-js" @Html.RenderLangAttribute()> <!--<![endif]--> <head> <title></title> @Html.Section("head") </head>

<body> @Html.Section("top")

&lt;div id="content" v-cloak&gt;
    &lt;div&gt;
        {{ message }}
    &lt;/div&gt;
   @Html.SfPlaceHolder("contentPlaceHolder")
&lt;/div&gt;

@Html.Section("jquery")
@Html.Section("vue")
@Html.Section("kendo")
@Html.Section("plugins")
@Html.Section("bottom")

@Html.Partial("~/MVC/Views/Shared/Vue.cshtml")

@* This is the core sites vue script, minify or do whatever you need to it *@
@Html.Script("/ResourcePackages/YourTheme/assets/main-vue.js", "bottom")

</body>

</html>

Here's the core\main javascript file for the site, this is where all the custom code should be living for your "theme" like things that should exist on EVERY page (like menu stuff)

main-vue.jsView on GitHub
var $mySite = new Vue({
    el: '#content',
    name: "mySite",
    data: {
      message: "hello"
    },
    created: function () {
           
},
mounted: function () {

},
methods: {

},
computed: {

},
watch: {
    
}

});

So we're setting up the layout such that we can use Html.Script to precisely place the scripts where we need. Just because we have a jQuery section in here, doesn't mean anything nessesarily will go there, but like if we want to use kendo and it's vuejs wrappers, we're going to need Kendo AND jQuery (the wrappers are free, and kendo for jQuery is included with Sitefinity).

So you can see though the 2 frameworks are at the top, then plugins come after, then "bottom" is usually for custom scripts (or vue components) we're going to be making. Because we're not webpacking this badboy... sadly not going to be using Single File Components.

At the very bottom we're loading Vue from a shared cshtml file to keep things clean

Vue.cshtmlView on GitHub
@using Telerik.Sitefinity.Frontend.Mvc.Helpers;

@Html.Script(Util.VueJsScript, "vue") @Html.Script("https://unpkg.com/axios@0.21.1/dist/axios.min.js", "plugins") @OPTIONAL@

You'll notice I'm loading it through a helper method

public static class Util
{
  /// Return the Vue script itself, uses dev build on dev\staging so we get the VueJs browser tooling
  public static string VueJsScript {
      get
      {
          return Util.IsDev ? "https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js" : "https://cdn.jsdelivr.net/npm/vue@2.6.12";
      }
  }
  

/// Is the site running on live or dev public static bool IsDev { get { var context = Telerik.Sitefinity.Services.SystemManager.CurrentHttpContext; return context.Request.Url.Host.Contains("dev.") || context.Request.Url.Host.Contains("staging."); } } }

This lets me get the VueJs chrome extension tooling working if the site is on dev or staging. For this purpose the scripts are hardcoded, for an actual site you should be storing them in a configuration file to be updated in the backend.

Step 2: Create your widget

I'm not going to bother going through how to make a basic Sitefinity MVC Widget, lets just assume you already have the Controllers\Model\View files all setup and ready to go, and it's called "MyWidget".

MyWidget.cshtmlView on GitHub
@model SitefinityWebApp.Mvc.Models.MyWidgetModel

@using Telerik.Sitefinity.Frontend.Mvc.Helpers

@Html.Script("/MVC/Views/MyWidget/Resources/component-mywidget.js", "bottom")

<mywidget></mywidget>

In here we're just rendering the vue component node itself, pass in whatever you need as properties, handle events as normal, it's up to you.

component-mywidget.jsView on GitHub
Vue.component('mywidget', {
    props: [],
    data: function () {
      return {
        componentdata: "I'm the component"
      }
    },
    mounted: function () {
    },
    methods: {  
      
},
template: '&lt;div class="component"&gt;{{ componentdata }}&lt;/div&gt;'

})

The component is just an un-fancy .js filem but now it should load just fine. Dropping the MyWidget 10 times on a page doesn't load the script 10 times, but you should get 10 instances of that widget rendering.

Step 3

That's it, there's no step 3, just drag\drop and use your sitefinity widget as normal. The main core vue script will handle loading the components inside of itself (and the v-cloak hides the flout)

Enhancements\Notes

These are things I couldn't really add because they increased complexity, but you probably should consider doing...

  • Go through your Sitefinity theme template view files and move all the scripts from "top" or "head" into one of our placeholder elements we defined. This should provide a significant performance rendering bump as the scripts aren't loading\running ABOVE the content.

  • I hate the inline templates in the .js files with no syntax highlighting, just a giant ugly javascript string. If a component is only to be used ONCE per page, you can change it to template: #mywidget-template then move that template into the cshtml as <script id="mywidget-template" type="text/x-template"><script>. You'll get syntax highlighting on the html and your script is smaller. The problem is if you put it external, and someone uses the widget 8 times on the page, that x-template node is also rendered 8 times, but ALSO you have 8 of the same "mywidget-template" ids, and the browser or vue might throw some console errors or warnings. It'll PROBABLLY still work fine, but just be aware.

  • Minify your scripts, but use the IsDev helpers to deliver the unminified versions to yourself.

  • Move hardcoded scripts into a Configuration Element it'll save your butt in the future not needing to re-compile. Moreover add a cache breaker element in there to version your scripts. So you can do things like "/MVC/Views/MyWidget/Resources/component-mywidget.js?v=" + Util.CacheBreaker.

  • Play with maybe disabling the Vue stuff in the page designer if it's problematic. You can do an If\Else to render static html content if it's in page designer mode... a few SF widgets do this.

  • As I mentioned above React, Angular, Svelte, etc etc, all will work if you follow this format. The most important part is the Page Layout loading of the script elements in the proper order.