TypeScript, WebPack and Kendo

1 Answer 789 Views
General Discussions ListView
A
Top achievements
Rank 1
Iron
A asked on 13 May 2021, 02:12 PM | edited on 17 May 2021, 02:16 PM

I have a Kendo professional license. I have install @progress/kendo-ui via NPM. WebPack is bundling it as expected and everything compiles fine. When the page loads it can't find kendo to initialize  any of the controls.

in my index.cshtml I have:

...

<head>
 <script src="~/js/vendors-node_modules_jquery_dist_jquery_js.bundle.js" type="text/javascript" asp-append-version="true"></script>
 <script src="~/js/vendors-node_modules_jquery-validation-unobtrusive_dist_jquery_validate_unobtrusive_js.bundle.js" type="text/javascript" asp-append-version="true"></script>
 <script src="~/js/vendors-node_modules_popperjs_core_lib_index_js.bundle.js" type="text/javascript" asp-append-version="true"></script>
 <script src="~/js/vendors-node_modules_progress_kendo-ui_js_kendo_all_js.bundle.js" type="text/javascript" asp-append-version="true"></script>
 <script src="~/js/vendors-node_modules_progress_kendo-ui_js_kendo_all_js-node_modules_kendo-ui-core_js_kendo_ui-55088d.bundle.js" type="text/javascript" asp-append-version="true"></script>
 <script src="~/js/vendors-node_modules_toastr_toastr_js.bundle.js" type="text/javascript" asp-append-version="true"></script>
</head>

...

<div class="results">
		@(Html.Kendo().ListView<UserProfile>()
   .Name("userProfileSearchResults")
   .TagName("div")
   .Bordered(false)
   .DataSource(dataSource => dataSource
    .Ajax()
    .Model(m => m.Id(p => p.Id))
    .PageSize(25)
    .Read("UserProfiles_Search", "Home")
    .ServerOperation(false)
    .Sort(sorter =>
    {
     sorter.Add(c => c.ProfileName).Ascending();
     sorter.Add(c => c.EmailAddress).Ascending();
     sorter.Add(c => c.AccountNumber).Ascending();
     sorter.Add(c => c.Id).Ascending();
    })

   )
   .AutoBind(false)
   .Pageable(pager => pager
    .ButtonCount(10)
    .Numeric(true)
    .Enabled(true)
   )
   .ClientTemplateId("userProfileSearchResultItem")
   )
	</div>
	

which generates a chunk of script into the page to initialize that control. But for the inline kendo script....kendo is not defined. It is expecting a global kendo reference which no longer happens with webpack.

package.json:

{
	"version": "1.0.0",
	"name": "asp.net",
	"private": true,
	"scripts": {
		"build-Debug": "webpack --mode development --no-color --stats-error-details",
		"build-Release": "webpack --mode production --no-color"
	},
	"dependencies": {
		"@popperjs/core": "^2.9.2",
		"@progress/kendo-ui": "^2021.2.511",
		"jquery": "3.5.1",
		"jquery-validation": "^1.19.3",
		"jquery-validation-unobtrusive": "^3.2.12",
		"kendo-ui-core": "^2021.2.511",
		"toastr": "^2.1.4"
	},
	"devDependencies": {
		"@types/glob": "^7.1.3",
		"@types/jquery": "3.5.1",
		"@types/node": "^15.0.2",
		"@types/toastr": "^2.1.38",
		"@types/webpack": "^5.28.0",
		"glob": "^7.1.7",
		"ts-loader": "^9.1.2",
		"ts-node": "^9.1.1",
		"typescript": "^4.2.4",
		"webpack": "^5.37.0",
		"webpack-cli": "^4.7.0"
	}
}

webpack.config.ts

import * as path from 'path';
import * as glob from 'glob';
import * as webpack from 'webpack';

const config: webpack.Configuration = {
	mode: 'development',
	entry: glob.sync('{./Scripts/**/*.ts,./wwwroot/lib/**/*.js}').reduce((obj, path) => {
		const match = /Scripts\/(.*)\.ts$/.exec(path);
		const isDefinition = /(.*)\.d\.ts$/.exec(path);
		const isStandardJs = /lib\/(.*)\.js/.exec(path);
		if (match && !isDefinition) {
			const item = match[1];
			obj[item] = path;
		}
		if (isStandardJs) {
			const item = isStandardJs[1];
			obj[item] = path;
		}
		return obj;
	}, {} as webpack.EntryObject),
	module: {
		rules: [
			{
				test: /\.tsx?$/,
				use: 'ts-loader',
				exclude: /node_modules/
			}
		]
	},
	resolve: {
		extensions: [
			'.tsx',
			'.ts',
			'.js'
		]
	},
	devtool: 'inline-source-map',
	output: {
		filename: '[name].bundle.js',
		path: path.resolve(__dirname, 'wwwroot/js')
	},	
	optimization: {
		splitChunks: {			
			chunks: 'all'
		}
	}
};

export default config;

A
Top achievements
Rank 1
Iron
commented on 17 May 2021, 02:21 PM

I have something working but it is absolutely horrible. In one of my modules I manually add $, jQuery and Keno to the global ambient scope. I set all of the kendo calls to be deferred and then output the kendo scripts at the bottom of the page wrapped in a jQuery on document ready function. The kendo syncReady method that they are wrapped in when inline was firing too early, even when at the bottom of the page but the jQuery one was firing at the right time.

There has to be a better way of doing this.

1 Answer, 1 is accepted

Sort by
0
Stoyan
Telerik team
answered on 18 May 2021, 02:00 PM

Hi A McGinn,

The behavior will be observed when having jQuery defined as a separate dependency and if the version of that dependency does not match the version specified by Kendo, NPM and Webpack are installing 2 versions of jQuery.

One possible way to resolve this is, for example, by adding an alias to the webpack.config so that jQuery is always resolved from the node_module/jQuery package:

const path = require('path');
const webpack = require('webpack');

module.exports = {
    entry: './src/index.js',
    output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [{ loader: 'style-loader' }, { loader: 'css-loader' }]
            }
        ]
    },
    resolve: {
      alias: {
          'jquery': path.join(__dirname, 'node_modules/jquery')
      }
    },
    plugins: [
        new webpack.ProvidePlugin({
            $: 'jquery',
            jQuery: 'jquery'
        }),
    ],
}

 

Sample application is attached for you to review.

Regards,
Stoyan
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

Tags
General Discussions ListView
Asked by
A
Top achievements
Rank 1
Iron
Answers by
Stoyan
Telerik team
Share this question
or