Robust support for Kendo+Typescript+Requirejs

7 posts, 0 answers
  1. Rowan
    Rowan avatar
    21 posts
    Member since:
    Jul 2014

    Posted 11 Feb 2015 Link to this post

    I thought I would share our solution for robust Kendo+Typescript+Requirejs support, in the hope that Telerik starts including this out of the box in Kendo.

    THE PROBLEM
    Currently the Kendo typescript definitions don't include any declarations of AMD modules for use with requirejs. While it is possible to work around this in a number of ways to at least get the require("<kendo file>") statements to emit into the javascript code, the fundamental issue is that the Typescript compiler is not aware of which kendo classes belong in which AMD module. This means that you can write typescript code that compiles fine, but does not actually work at run-time. For example:
    import kendoData = require("kendo\kendo.data"); // I want to do something with data, emit require statement
    var data = new kendo.data.ObservableObject()
    kendo.bind("#target", data);

    This will compile fine because as far as the compiler is concerned the entire kendo library is always loaded and global. However when you run the resultant javascript from the above code, it will fail because kendo.bind is not within the require chain of kendo.data.js.

    This becomes very annoying because you are never 100% sure you are requiring the correct kendo modules actually needed for the code you write.

    OUR SOLUTION
    The solution we are using is to define our own kendo AMD module definitions, and have them explicitly re-export the named types from the kendo global scope out of the AMD module. Each AMD module only re-exports the kendo types that are actually contained within that modules kendo javascript file. For example in our new kendo.web.amd.d.ts file (which contains all the AMD module defs in one file) we have:
    declare module "kendo/kendo.data" {
        module data {
            export import Datasource = kendo.data.DataSource;
            export import ObservableObject = kendo.data.ObservableObject;
        }
    }

    The compiler is now aware of kendo.data.js as a proper AMD module, and knows exactly which types are available out of it. The leading "kendo/" is required so that we can configure requirejs to map to the actual kendo library path. As long as we avoid referring to the global kendo module in our typescript code, we now guarantee that if code compiles, it will also be pulling in the correct modules at runtime. The original example now looks like this:
    import kendoData = require("kendo\kendo.data");
    import kendoBind = require("kendo\kendo.binder");
    var data = new kendoData.data.ObservableObject();
    kendoBind.bind("#target", data);

    Note that we no longer reference the global "kendo" module, we only use types within the modules we have explicitly imported. Intellisense is smart enough to drop down all types available in the module, for example here typing "kendoData." will drop down everything available out of that AMD module.

    A BETTER SOLUTION
    The only problem with the above solution is that the global module is still available to the typescript compiler, so if you accidentally reference a type straight out of the global "kendo", you are back to the original problem where it will compile fine, but then fail at runtime. A better solution would be for Telerik to provide two versions of each definition file, ie

    kendo.web.ts
    kendo.web.amd.ts

    The .amd version, rather than just declaring all types in the global kendo namespace, would declare each type within the actual named module that it resided in (with the leading "kendo/" to allow path remapping!!). Within our projects we could then choose to include only the kendo.web.amd file, which would enforce that no kendo types are available unless you import the associated module.

  2. Marc
    Marc avatar
    11 posts
    Member since:
    Sep 2014

    Posted 27 Jul in reply to Rowan Link to this post

    Hi Rowan:

    I think I'm running into the same issue as you.  Would it be possible to get the your copy of kendo.web.amd.ts and also how you configured requires?

    Thanks

    marc

  3. Kendo UI is VS 2017 Ready
  4. Rowan
    Rowan avatar
    21 posts
    Member since:
    Jul 2014

    Posted 27 Jul Link to this post

    Hi Marc,

    Make sure you go up vote the feature request!!: http://kendoui-feedback.telerik.com/forums/127393-kendo-ui-feedback/suggestions/7517149-provide-correct-typescript-amd-module-definition-f

    We have an in-house custom version of kendo that we have built, so unfortunately I can't share our amd.ts file. However here are some quick examples to give you the general idea in practice.

    In the amd.ts file, re-map the Button class from the global namespace into it's actual module file on disk "kendo/kendo.button". The amd.ts file is just full of declarations like this.

    declare module "kendo/kendo.button" {
        module ui {
            export import Button = kendo.ui.Button;
            export import ButtonOptions = kendo.ui.ButtonOptions;
            export import ButtonEvent = kendo.ui.ButtonEvent;
            export import ButtonClickEvent = kendo.ui.ButtonClickEvent;
        }
    }     

  5. Rowan
    Rowan avatar
    21 posts
    Member since:
    Jul 2014

    Posted 27 Jul Link to this post

    Then the require.js config looks like this:

    require.config({
        paths: {
            // Map the "kendo" prefix to the actual path on the server where the kendo js files reside
            "kendo": "~/Lib/kendo/js/"
        },
      });

  6. Marc
    Marc avatar
    11 posts
    Member since:
    Sep 2014

    Posted 28 Jul in reply to Rowan Link to this post

    Hi Rowan:

    Thanks for the info.  I will give it a try.

  7. Marc
    Marc avatar
    11 posts
    Member since:
    Sep 2014

    Posted 28 Jul in reply to Marc Link to this post

    Hi Rowan, just to make sure I understand.  I need to go through the existing kendo-ui.d.ts file to determine what Kendo UI classes/interfaces I need.  Then create my own custom d.ts file that will explicitly export those classes/interfaces where I set the module name to be the [requirejs alias]/[kendo js file name].

    Using the requirejs.config that you provided in a previous message, if I want to load the definitions for the grid, I would need to declare the module to be kendo/kendo.grid.

    Is that correct, I assume than if I want to force the load of the minimized files I could do one of the following:

    1) just add .min to the module name.

    2) load the files from my web server, and not the Kendo CDN.  Then remove .min from all the local file names.

    Thanks

    marc

  8. Marc
    Marc avatar
    11 posts
    Member since:
    Sep 2014

    Posted 28 Jul in reply to Marc Link to this post

    Hi Rowan:

    Thank you for the help and guidance.  I've been able to get something to work.  I figured out a way to not have to put together a custom .d.ts file.  I also needed to change the syntax of the import statement slightly.

    Your insight and directions where a starting point for determine the best solution for my specific needs.

    Thank you again.

    -marc

Back to Top
Kendo UI is VS 2017 Ready