Part III - Generating TypeScript at build-time using TypeLite
This is a series of posts about TypeLite/TypeScript. The parts are:
Part I: TypeLite has gone v1.0 - Video demonstrating what we are doing
Part II: Using TypeLite to Generate TypeScript - Building the TypeScript generator
Part III (this part): Generating TypeScript at build-time using TypeLite - Automatically regenerating the TypeScript on each build
Well, it’s been over a year since I started a series on using TypeLite for improving the type-safety of your client side code. At least no one reads this, so it doesn’t matter! This is now part III. On the plus side, it does mean that over a year later I’m still using this technique in a number of applications that have gone live, and it’s proved it’s worth.
In the previous episode, we had a solution setup in which we could regenerate our TS interfaces by running a command. Now to make it generate on each build.
First step, we need to copy the TypeScriptGenerator EXE to a sensible location. Unfortunately running it from the location it’s built in can cause file locking issues with VisualStudio. As this project doesn’t change very often, I add a simple batch file to the project like this (see this commit):
copy bin\debug\*.dll ..\Tools
copy bin\debug\*.exe ..\Tools
*Note, I use the VSCommand extensions (http://vscommands.squaredinfinity.com/) which add a ‘Run’ option on the solution explorer context menu for batch files, making this workflow ok with me. Currently I’m committed the cardinal sin of then checking this ‘Tools’ folder into git with the required binary exe/dlls. Feel free to move this step to your build script so that you can avoid this.
Now we need to call the generator each time the solution is compiled. Initially I used Build Events to do this, but I learned that these fire at a different time if you run instead Visual Studio compared to running outside using MSBuild, so it had trouble when building on a Build Server. After quite a bit of trial and error, I settled on using an MSBuild extensibility point – add this to the csproj file of your Web project (see this commit):
<!-- the rest of the project file -->
<Exec Command="..\Tools\TypeScriptSample.Generator.exe ..\TypeScriptSample.Models\bin\$(ConfigurationName)\TypeScriptSample.Models.dll $(ProjectDir)App\server" WorkingDirectory="$(ProjectDir)" />
AfterResolveReferences runs at the perfect time for us. The references for the Web project have been pulled in, so the DLL containing the c# model classes will be in the \bin folder, but it’s before the web project itself is built – so any client-side errors introduced by the updated TypeScript (e.g. a property is renamed) will be reported as usual and prevent the build from succeeding. The command call is just the same command that we were running manually in part two.
The final result
All we have to do is build, and any TypeScript that references the old property name will appear as an error!
In the year since I started this series, the version of the generator I’m using actually does a lot more than just convert c# models into TS interfaces – it generates typed SignalR hubs, and also creates type-safe TypeScript method calls for WebAPI actions, allowing you to call your server-side methods from the client with intellisense for action parameters, etc. I’m hoping I’ll be able to tidy that up and add it to this series of posts.