I am working on a mobile web application project using Telerik ASP.NET Core controls. These are the C# equivalent of the Kendo UI JavaScript controls. In fact, the Telerik ASP.NET Core controls are really Razor and tag helper wrappers that emit JavaScript to the browser to save you from the trouble of writing the JavaScript yourself.

Because this is a mobile web app that will be used in the field, we want fast page download speeds. Having worked with Kendo UI before, I knew I could import only the components I needed, rather than pull in code for sliders and other components not used in this app.

We are also using webpack and import only the JavaScript for the Telerik components used in each module.

Styles

In this project, we have a variables.scss file where we keep the common Sass variables, a site.scss files with the site-specific styles and overrides, and a common.scss file that brings these two project Sass files together with the vendor files - in this case, Bootstrap and Kendo UI styles.

Notice we are pulling in all Bootstrap styles, but we are not importing every Kendo UI styles or a combined file with all the Kendo UI styles for all the components. We are using only a handful of Kendo UI components in this app, so we don't want the extra weight of all those styles that will never be used in the app.

// All variables
@import "variables";

// Bootstrap
@import "node_modules/bootstrap/scss/bootstrap";

// Kendo UI
@import "node_modules/@progress/kendo-theme-bootstrap/scss/autocomplete";
@import "node_modules/@progress/kendo-theme-bootstrap/scss/grid";
@import "node_modules/@progress/kendo-theme-bootstrap/scss/combobox";
@import "node_modules/@progress/kendo-theme-bootstrap/scss/datetime";

// Site
@import "site";

Scripts

The webpack entry points for this web app are pages. It's a multi-page, not a single-page application. Here's what the home.js page script looks like. It imports the components it needs, which in turn import whatever they need. For this app, the home page is static and shows a splash, and that's about it.

import "common.scss";
import $ from "jquery";
import "components/top-menu";
import "components/header";
import "components/footer";

Here's the script for search.js a page that uses the Kendo UI autocomplete search and a gid to show search results. It also uses the Bootstrap alert module to show the user if there are no records found in the search.

Finally, I had to import @progress/kendo-ui/js/kendo.aspnetmvc in the page's JavaScript module. This is the secret sauce to get client-side behavior from server-side Telerik ASP.NET Core controls we used in Razor views (below).

import "common.scss";
import $ from "jquery";
import "components/top-menu";
import "components/header";
import "components/footer";
import "bootstrap/js/dist/alert";
import "@progress/kendo-ui/js/kendo.autocomplete";
import "@progress/kendo-ui/js/kendo.grid";
import "@progress/kendo-ui/js/kendo.aspnetmvc";

Razor

The Razor views were like normal ASP.NET Razor views or pages, but with client-side behavior coming from the page's import "@progress/kendo-ui/js/kendo.aspnetmvc";. This means you can sort or filter the results in a grid without a server call, but you don't have to write all the JavaScript client code to handle that.

We tried the Telerik ASP.NET Core control tag-helpers, and I kind of prefer the syntax, but we quickly found there were not enough examples on the Telerik site or out in the wild to figure out the API. Guessing got pretty old pretty fast, so we went to the more traditional HTML helper syntac in the Razor code.

<form id="searchForm" asp-controller="Search" asp-action="Index" method="post">
    <div class="input-group">
        @(
        Html.Kendo().AutoComplete()
            .Name("searchText")
            .DataTextField("HitString")
            .HtmlAttributes(new {@class="form-control"})
            .DataSource(source =>
            {
                source.Read(read =>
                {
                    read.Action("GetAutoCompleteAccounts", "Search").Data("() => { return { text: $('#searchText').val() }; }");
                }).ServerFiltering(true);
            })
            .Placeholder("Address, Owner Name, Legal Description, Account Number, or Parcel Number")
            .Value(Model)
            .Filter(FilterType.Contains)
            .MinLength(2)
        )
        <div class="input-group-append">
            <button type="submit" class="btn btn-primary text-light">
                <span class="fas fa-search"></span> Search
            </button>
        </div>
    </div>
</form>

Optimizing

When webpack starts build the entry points, in this case, home.js and search.js, it grabs only the styles in common.scss and only the modules in the pages and the components they use, so we get a smaller bundle than if we put style and script links in the <head> section of the _Layout.cshtml page.