Thursday, 27 February 2014

TypeScript and RequireJS (Keep It Simple)

I'm not the first to take a look at mixing TypeScript and RequireJS but I wanted to get it clear in my head. Also, I've always felt the best way to learn is to do. So here we go. I'm going to create a TypeScript and RequireJS demo based on John Papa's "Keep It Simple RequireJS Demo".

So let's fire up Visual Studio 2013 and create a new ASP.NET Web Application called “RequireJSandTypeScript” (the empty project template is fine).

Add a new HTML file to the root called “index.html” and base it on “index3.html” from John Papa’s demo:

<!DOCTYPE html>
<html>
<head>
    <title>TypeScript with RequireJS</title>
</head>
<body>
    <div>
        <h1>TypeScript with RequireJS loading jQuery in Visual Studio land</h1>
    </div>

    <!-- use jquery to load this message-->
    <p id="message"></p>

    <!-- Shortcut to load require and then load main-->
    <script src="/scripts/require.js"
            data-main="/scripts/main"
            type="text/javascript"></script>
</body>
</html>

John’s demo depends on jQuery and RequireJS (not too surprisingly) so let’s fire up Nuget and get them:

Install-Package RequireJS
Install-Package jQuery

Whilst we’re at it, let’s get the Definitely Typed typings as well:

Install-Package jQuery.TypeScript.DefinitelyTyped

To my surprise this popped up the following dialog:

By "Your project has been configured to support TypeScript." it means that the csproj file has had the following entries added:

<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.Default.props" Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.Default.props')" />
  ...
  <PropertyGroup>
    ...
    <TypeScriptToolsVersion>0.9</TypeScriptToolsVersion>
  </PropertyGroup>
  ...
  <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.targets" Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\Microsoft.TypeScript.targets')" />
  ...
</Project>

I’m not sure when this tweak to the Visual Studio tooling was added was added. Perhaps it's part of the TypeScript 1.0 RC release; either way it’s pretty nice. Let's press on.

Whilst we’re at it let’s make sure that we’re compiling to AMD (to be RequireJS friendly) by adding in the following csproj tweaks just before the Microsoft.TypeScript.targets Project import statement:

  <PropertyGroup Condition="'$(Configuration)' == 'Debug'">
    <TypeScriptModuleKind>amd</TypeScriptModuleKind>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)' == 'Release'">
    <TypeScriptModuleKind>amd</TypeScriptModuleKind>
  </PropertyGroup>

Where was I? Oh yes, typings. So let’s get the RequireJS typings too:

Install-Package requirejs.TypeScript.DefinitelyTyped

Right – looking at index.html we can see from the data-main tag that the first file loaded by RequireJS, our bootstrapper if you will, is main.js. So let’s add ourselves a main.ts based on John's example (which will in turn generate a main.js):

(function () {

    requirejs.config(
        {
            baseUrl: "scripts",
            paths: {
                "jquery": "jquery-2.1.0"
            }
        }
        );

    require(["alerter"],
        (alerter) => {
            alerter.showMessage();
        });
})();

main.ts depends upon alerter so let’s add ourselves an alerter.ts as well:

define('alerter',
    ['jquery', 'dataservice'],
    function ($, dataservice) {

        var
            name = 'John',
            showMessage = function () {
                var msg = dataservice.getMessage();

                $('#message').text(msg + ', ' + name);
            };

        return {
            showMessage: showMessage
        };
    });

And a dataservice.ts:

define('dataservice', [],
    function () {
        var
            msg = 'Welcome to Code Camp',
            getMessage = function () {
                return msg;
            };

        return {
            getMessage: getMessage
        };
    });

That all compiles fine. But we’re missing a trick. We’re supposed to be using TypeScripts AMD support so let’s change the code to do just that. First dataservice.ts:

var msg = "Welcome to Code Camp";

export function getMessage() {

    return msg;
};

Then alerter.ts:

import $ = require("jquery");
import dataservice = require("dataservice");

var name = "John";

export function showMessage() {

    var msg = dataservice.getMessage();

    $("#message").text(msg + ", " + name);
}

I know both of the above look slightly different but if you look close you'll see it's really only boilerplate changes. The actual application code is unaffected. Finally, main.ts remains as it is and that's us done; we have ourselves a working demo... Yay!

Thanks to John Papa for creating such a simple demo I could use as the basis for my own demo.

Closing Thoughts

Unfortunately there is no typing on the alerter reference within main.ts. To my knowledge there is no way to implicitly import the typings here – the only thing you can do is specify them manually. (By the way, if I'm wrong about this then please do set me straight!) That said, this is not so bad really since this main.ts file is essentially just a bootstrapper that kicks things off. All the other files contain the real application code and they have have typings a-go-go. So we're happy.

Finally for bonus points....

I’ve included the js and js.map files in the project file as they don't seem to be added into the project by Visual Studio when the TS file is created or when it is compiled for the first time. I've also ensured that these files are dependent upon the typescript files they were generated from.

    <TypeScriptCompile Include="Scripts\alerter.ts" />
    <Content Include="Scripts\alerter.js">
        <DependentUpon>alerter.ts</DependentUpon>
    </Content>
    <Content Include="Scripts\alerter.js.map">
        <DependentUpon>alerter.ts</DependentUpon>
    </Content>
    <TypeScriptCompile Include="Scripts\dataservice.ts" />
    <Content Include="Scripts\dataservice.js">
        <DependentUpon>dataservice.ts</DependentUpon>
    </Content>
    <Content Include="Scripts\dataservice.js.map">
        <DependentUpon>dataservice.ts</DependentUpon>
    </Content>
    <TypeScriptCompile Include="Scripts\main.ts" />
    <Content Include="Scripts\main.js">
        <DependentUpon>main.ts</DependentUpon>
    </Content>
    <Content Include="Scripts\main.js.map">
        <DependentUpon>main.ts</DependentUpon>
    </Content> 

Want the code for your very own?

Well you can grab it from GitHub.

Wednesday, 12 February 2014

WPF and Mystic Meg or "Playing Futurologist"

Time for an unusual post. Most of what gets put down here is technical "how-to's". It's usually prompted by something I've been working on and serves, as much as anything else, as an aide-memoire. Not this time.

I’ve been watching the changes in the world of development of the last couple of years and I’ve come to a controversial conclusion... So I wanted to write about it. Hopefully I'll be able to return to this in 5 years and say "wow - I'm so insightful - almost visionary really". Or not. Either way, let's put it out there - it's sink or swim time. Ready for it? Here’s my bet: WPF will die.

Sounds dramatic right? OK - I've overstated my case just to get you to read on (I should work for the tabloids). Let me flesh this out a little. First of all, I think WPF is a fine technology - great apps are built with it. My personal favourite being the fantastic GitHub for Windows. And actually I don't think WPF will die at all. What I think will happen is that it will become a more niche way to build applications.

More broadly, I think that native client apps (be they Windows, Mac, iOS, Android etc) will eventually come to be replaced by rich web apps / SPAs of the Angular / Ember / Durandal ilk. I realise that at the moment that seems like a ludicrous statement – native apps are heavily used throughout enterprises worldwide and certainly will continue to be used and actively developed for at least the next 5 years.

But as the web comes to perform like native, as JavaScript become a compile target, as HTML 5 provides rich UI and as interactive communication becomes possible I reckon this is a fairly probable scenario. Particularly when you consider the API work Firefox is doing around Firefox OS. I could be wrong, but my expectation is that the day will come when people will have apps that they can access from anywhere, on any platform and those apps can be deployed without infrastructure having to push out new versions to each client machine.

The web undeniably has issues but I think it will likely win out. And the cost case for a single client app is pretty compelling to anyone funding a system.

As a dev I’m always working with an ever-evolving grab bag of technology whether it be front end, middle tier, database or services. In fact that will likely always be the case (change being the only constant in the world of software). But on the basis of my expectations I’m planning to always keep at least a toe in the world of web apps as a form of “career future-proofing”.

Going less broad again when I look at the Microsoft stack, I think XAML will live on for some time. Obviously Silverlight is no longer being actively developed but MS are using it in Windows 8 (Phone and WinJS) as well as WPF. But I do kind of wonder if it will become like a bit like VB.Net, still around, still in use, but slowly dropping off in terms of popularity. Particularly as you can write WinJS apps in HTML / CSS / JavaScript.

As I say, I could very much be wrong about all of this. I don’t know what your view of the future of the development landscape is? You may have a different insight? I’d be intrigued to know!