Getting TypeScript to Work with a LightSwitch HTML Project (kind of)


Last week I saw a post on the LightSwitch forum that pointed out that steps outlined in a blog post by Michael Washington regarding using TypeScript in a LightSwitch project were no longer working.  So I thought I would go through the blog post and try it out.  I hadn’t done anything with TypeScript before so this was my first experience.  The steps outlined in Michael’s blog post definitely didn’t work anymore and it ended up taking me a while to figure out how to get things “working” (in air quotes), so I figured I’d post about it.

To start, here’s a brief summary of the issues I ran into:

  • There was no entry in the “Add” context menu for “TypeScript File” when right-clicking on the HTMLClient project (i.e. the .jsproj)
  • There was no entry for “TypeScript File” in the “Add New Item” dialog
  • When I added a new JavaScript file and renamed it to end with a .ts extension, I couldn’t get the .ts file to compile and generate the corresponding .js file (I tried a variety of different things here that I won’t get into)

I did find an open bug that was something along the lines of “TypeScript should work with JavaScript projects (.jsproj)” so hopefully these will all be addressed in the near future.

    Here is what I needed to do to get things to work:

    Close VS

    Find the .jsproj file in the HTML sub-project’s folder and open it with Notepad

    image

    Insert the bolded entries just below the first PropertyGroup node near the top of the file:

     

    <PropertyGroup Condition=" ‘$(Configuration)’ != ‘Release’ ">
      < UseDesignTimeFeatures>true</UseDesignTimeFeatures>
    < /PropertyGroup>
    <PropertyGroup Condition="’$(Configuration)’ == ‘Debug’">
      < TypeScriptTarget>ES5</TypeScriptTarget>
      < TypeScriptRemoveComments>false</TypeScriptRemoveComments>
      < TypeScriptSourceMap>true</TypeScriptSourceMap>
      < TypeScriptModuleKind>AMD</TypeScriptModuleKind>
    < /PropertyGroup>
    < PropertyGroup Condition="’$(Configuration)’ == ‘Release’">
      < TypeScriptTarget>ES5</TypeScriptTarget>
      < TypeScriptRemoveComments>true</TypeScriptRemoveComments>
      < TypeScriptSourceMap>false</TypeScriptSourceMap>
      < TypeScriptModuleKind>AMD</TypeScriptModuleKind>
    < /PropertyGroup>
    < Import Project="C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v12.0\TypeScript\Microsoft.TypeScript.targets" />
    < Import Project="C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v12.0\TypeScript\Microsoft.TypeScript.jsproj.targets" />
    <PropertyGroup Label="Globals">

    I stole this snippet from a new TypeScript project that I had created and after some spelunking online found various sources that said that these are the meaningful parts regarding JavaScript generation (I changed the Import nodes to use absolute paths instead of environment variables because it didn’t work with the environment variables on some machines).  Note that you need to remove all the leading spaces in front most of the elements (LiveWriter insists on adding these during the publish process, sorry).

     

    Open your LightSwitch project in VS and choose to add a new JavaScript file to the HTMLClient project

    image

     

    Change the name of the file to end with .ts instead of .js

    image

     

    Paste this code into the file that was just created (this is taken from Michael’s blog post)

     

    class FormatName {
        _firstname: string;
        _lastname: string;
        _age: number;
        constructor(
            firstname: string,
            lastname: string,
            age: number
            ) {
            this._firstname = firstname;
            this._lastname = lastname;
            this._age = age;
        }
        ReturnName() {
            var formatedName =
                this._lastname.toUpperCase()
                + ", " +
                this._firstname.toLowerCase()
                + " {" + this._age.toString() + "}";
            
             return formatedName
           }
    }

     

    Then save the file.  Now what should have happened is that a .js file was generated and added to the .jsproj.  The .js file is created, but it isn’t added to the project

    image

     

    image

    So, we need to manually add this to the project by performing Add >> Existing Item and selecting the .js file from the browse window that opens

    image

     

    Now the .js file will be copied out to the Scripts folder when you do a build.  Finally, you will need to add an entry in the HTMLClient project’s default.htm to include this new file

    <script type="text/javascript" src="Scripts/Generated/generatedAssets.js"></script>

    <script src="scripts/formatname.js"></script>

    <script type="text/javascript">

    After all this, we now have generated JavaScript that we can call from the JavaScript files that are generated when you “Add Code” to a screen.  Here’s an example (again taken from Michael’s blog).  This example is for the “postRender” code for a List (notice the lines using FormatName and ReturnName).

    myapp.BrowsePeople.rows_render = function (element, contentItem) {
        // Write code here.
        var itemTemplate = $("<div></div>");
        var FirstName = contentItem.data["FirstName"];
        var LastName = contentItem.data["LastName"];
        var Age = contentItem.data["Age"];
        var objFomatName = new FormatName(FirstName, LastName, Age);
        var FinalName = $("<h1>" + objFomatName.ReturnName() + "</h1>");
        FinalName.appendTo($(itemTemplate));
        itemTemplate.appendTo($(element));
    };

    So that is something, not much, but something.  We got some good feedback on the forums about ways we could improve the experience for supporting TypeScript from a LightSwitch project.  Hopefully we can deliver on some improvements in the future.

    A sample project for the sample described here can be found at http://code.msdn.microsoft.com/Using-TypeScript-with-c418131a


    Comments (11)

    1. Michael Washington says:

      I updated my blog post to point to your new post 🙂

    2. Simon Jones says:

      "So, we need to manually add this to the project by performing Add >> New Item and selecting the .js file from the browse window that opens"

      I think this should be "Add >> Existing Item", as shown in the following screenshot.

    3. batpox says:

      Thank Dave, but this isn't working for me. A few things I've noticed:

      1. Your "PropertyGroup" includes are getting pretty mangled by your blog formatting. But I got the drift, added a TypeScript project and copied the text from there.

      2. When I add a .ts file like you describe, it does *not* generate the .js like you described. I'm still researching this, but are you sure you didn't have to do anything else?

      Just FYI: I have the VS2013 update 2, and can add a separate TypeScript project

      I'll update this as I find new information.

      Cheers…

    4. Dave Kidder says:

      @Simon – thanks, my bad

      @batpox – The file doesn't get generated immediately, you have to put something in the TypeScript file first and save it.  Assuming you tried that though.  Tomorrow I will look into posting my project to CodePlex so you can download it and compare it to what you have.

    5. batpox says:

      Thanks Dave, it is very much appreciated and I look forward to it. If I can just get it to automatically build to the .js as you describe, it will satisfy my requirements. Nonetheless, it has been an education exploring the msbuild, the targets, and what-not. My TS file has the TS Icon, and everything seems to point to the correct msbuild TypeScript folder (which has, I believe, the correct targets and TypeScript dll, but nothing is generated and I can find no errors. So again, thanks, and I look forward to seeing your project.

    6. Dave Kidder says:

      Well this is frustrating, I tried going through this on a different machine and it isn't working on that box.  I will keep digging, I don't know what would be causing this discrepancy.

    7. batpox says:

      I do appreciate your efforts. I will also keep digging as well and post here when I find something. It seems odd that MS would spend some serious money on such a (potentially) wonderful tool, bake it into Visual Studio, and then not provide a decent and consistent way to use it. I sometimes think MS has a serious attention deficit problem. Maybe it is part of their ARF (Announce, Release, and Forget) policy 🙂  

      Thanks again!

    8. Dave Kidder says:

      I updated the .jsproj snippet with a couple more lines and got it to work on the other machine (the two Import statements).  I have uploaded a sample to here: code.msdn.microsoft.com/Using-TypeScript-with-c418131a

      As far as your other comments, all I can say is there's a lot of people here that work on a lot of different stuff at a very fast pace, so it can be very difficult to get things right on the first try.  Thankfully, now that we have a more frequent cadence for VS Updates, we can get improvements out faster.

    9. batpox says:

      Thanks Dave, that did the trick. Hopefully VS2013 Update 3 will do this a bit cleaner. I *really* like LightSwitch and the extensibility that JavaScript provides, and TypeScript (IMHO) fixes most of JavaScript shortcomings. I notice you are on the test team. Perhaps next you could look at the *very* slow performance when you have 80 database tables (we end users are never satisfied, you know 🙂

      BTW: I marked you as answering my question.

      Thanks again!

    10. Yann Duran says:

      Hi Dave.

      It took me a bit of fiddling around to get an existing LS app to even start producing js files when saving ts files, but in the end I did finally get it to work. This is a pain, because this part at least used to "just work" the last time I played with TS. So one of the VS 2013 updates must have broken something. Or maybe it worked back in the days when I was using VS 2012.

      I'd like to point out a neat small shortcut. If you add the ts source files to a folder called "UserCode" (either manually created, or created by LS when you click on a "Write Code" link in a screen), instead of the "Scripts" folder as you described, you can shave a tiny bit off the manual process.

      I still had to "include" any generated js files (which again is a pain – this should be automatic by now, TS has been around long enough now), but at least I didn't have to add them to "default.htm" manually (which would be even more of a pain). During the building of the project, LightSwitch combines all of the js files found in the "UserCode" folder into a single file called "usercode.js" (found in the hidden "GeneratedArtifacts" folder), which is then somehow auto-magically included behind the scenes by default.

      It'd be great if TypeScript became a first-class citizen in LightSwitch, ideally being the "code-behind" that gets generated for screens and entities, instead of JavaScript. I'm not keen on having to learn yet another language, but it'd be nice to have some of the benefits that TS provides, so that a single mistyped character doesn't bring a whole app to its knees, with no indication of where the problem is.

      I seriously can't understand why that hasn't happened yet. And I sincerely hope that this is somewhere on the not-too-distant-future road-map for LightSwitch (or CBA's as SharePoint-enabled LS apps are now called).

      Well I hope that helps someone else in their LightSwitch/TypeScript endeavors. 🙂

    11. Yann Duran says:

      Just an addendum to my last post. I'm not suggesting that you put any of the generated "myapp.someMethodName" code into ts files in the "UserCode" folder. I tried using TS for that a while back (in the "Screens" folder), but it was more hassle than it was worth.

      I would only the put the code that I call from those methods. That reminds me that I need to write a complete blog post on how I avoid polluting the global scope like LightSwitch does by default. I'll put it on the list *sigh*