Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

How we migrated our huge AngularJS app from CoffeeScript to TypeScript

5,648 views

Published on

How we migrated our huge AngularJS app from CoffeeScript to TypeScript

Published in: Technology
  • Hi there! Get Your Professional Job-Winning Resume Here - Check our website! http://bit.ly/resumpro
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

How we migrated our huge AngularJS app from CoffeeScript to TypeScript

  1. 1. HOW WE MIGRATED OUR HUGE ANGULAR.JS APP FROM COFFEESCRIPT TO TYPESCRIPT Luka Zakrajšek CTO @ Koofr @bancek Ljubljana Spring-ish JavaScript Meetup February 10, 2015
  2. 2. ABOUT ME FRI graduate CTO and cofounder at Koofr frontend, backend, iOS, Windows Phone almost 3 years of Angular.js
  3. 3. KOOFR Koofr is white-label cloud storage solution for ISPs
  4. 4. ANGULAR.JS AT KOOFR web app desktop application (webappwrappedintobrowsertolooklikenative)
  5. 5. HUGE APP? 26 route controllers 90 directives 22 factories 14 filters 15 services 6012 LOC of Coffee (30 files) 2937 LOC of Angular HTML templates (101 files)
  6. 6. WE WERE HAPPY WITH COFFEESCRIPT Pros clean code classes Cons technical debt fear of refactoring not enough tests
  7. 7. COFFEESCRIPT Launched in 2010. Gained traction with Rails support in 2011 $(function(){ //Initializationcodegoeshere }) $-> #Initializationcodegoeshere
  8. 8. BROWSERIFY Lets you require('modules') in the browser by bundling up all of your dependencies. varunique=require('uniq'); vardata=[1,2,2,3,4,5,5,5,6]; console.log(unique(data)); $npminstalluniq $browserifymain.js-obundle.js <scriptsrc="bundle.js"></script>
  9. 9. TYPESCRIPT a typed superset of JavaScript that compiles to plain JavaScript any existing JavaScript program is also valid TypeScript program developed by Microsoft from lead architect of C# and creator of Delphi and Turbo Pascal
  10. 10. FIND A TYPO classPoint{ x:number; y:number; constructor(x:number,y:number){ this.x=x; this.y=y; } getDist(){ returnMath.sqrt(this.x*this.x+ this.y*this.y); } } varp=newPoint(3,4); vardist=p.getDst(); alert("Hypotenuseis:"+dist);
  11. 11. FEATURES
  12. 12. JAVASCRIPT functionGreeter(greeting){ this.greeting=greeting; } Greeter.prototype.greet=function(){ return"Hello,"+this.greeting; } //Oops,we'repassinganobjectwhenwewantastring. vargreeter=newGreeter({message:"world"}); alert(greeter.greet());
  13. 13. TYPES functionGreeter(greeting:string){ this.greeting=greeting; } Greeter.prototype.greet=function(){ return"Hello,"+this.greeting; } vargreeter=newGreeter("world"); alert(greeter.greet());
  14. 14. CLASSES classGreeter{ greeting:string; constructor(message:string){ this.greeting=message; } greet(){ return"Hello,"+this.greeting; } } vargreeter=newGreeter("world"); alert(greeter.greet());
  15. 15. TYPES classAnimal{ constructor(publicname:string){} move(meters:number){ alert(this.name+"moved"+meters+"m."); } } classSnakeextendsAnimal{ constructor(name:string){super(name);} move(){ alert("Slithering..."); super.move(5); } } varsam:Animal=newSnake("SammythePython"); sam.move();
  16. 16. GENERICS classGreeter<T>{ greeting:T; constructor(message:T){ this.greeting=message; } greet(){ returnthis.greeting; } } vargreeter=newGreeter<string>("Hello,world"); alert(greeter.greet());
  17. 17. MODULES moduleSayings{ exportclassGreeter{ greeting:string; constructor(message:string){ this.greeting=message; } greet(){ return"Hello,"+this.greeting; } } } vargreeter=newSayings.Greeter("world"); alert(greeter.greet());
  18. 18. USAGE npminstall-gtypescript tschelloworld.ts <scriptsrc="helloworld.js"></script> Or Grunt, Gulp ...
  19. 19. TOOLS included in Visual Studio JetBrains (IntelliJ) Vim Emacs Sublime Text CATS
  20. 20. MIGRATION coffee-script-to-typescript to the rescue npminstall-gcoffee-script-to-typescritpt coffee-to-typescript-cmayour/files/*.coffee
  21. 21. EXISTING LIBRARIES we use more than 30 libraries to be completely type-safe, you need definitions for all external libraries DefinitelyTyped - more than 700 libraries https://github.com/borisyankov/DefinitelyTyped
  22. 22. EXAMPLE jgrowl.d.ts ///<referencepath="../jquery/jquery.d.ts"/> interfaceJQueryStatic{ jGrowl:jgrowl.JGrowlStatic; } declaremodulejgrowl{ interfaceJGrowlOptions{ sticky?:boolean; position?:string; beforeOpen?:Function; //... } interfaceJGrowlStatic{ (msg:string,options?:JGrowlOptions):void; } } $.jGrowl({sticky:true,beforeOpen:()=>{ console.log("opening")}})
  23. 23. ANGULARJS - BEFORE CoffeeScript angular.module('comments.controllers',[]).directive('comments',-> restrict:'E' scope: mount:'=' replace:yes templateUrl:'comments/comments.html' controller:($scope,Api)-> $scope.comments=[] $scope.load=-> Api.callApi.api.Comments.commentsRange($scope.mount.id,0,10 success:(res)-> $scope.comments=res.comments $scope.load() )
  24. 24. ANGULARJS - AFTER TypeScript ///<referencepath="../app.ts"/> modulecomments{ interfaceCommentsScopeextendsng.IScope{ mount:k.Mount comments:Array<k.Comment> load():void }
  25. 25. exportclassCommentsCtrl{ constructor($scope:CommentsScope,Api:api.Api){ $scope.comments=[]; $scope.load=()=>{ Api.get(Api.api.Comments.commentsRange($scope.mount.id,0, .then((res)=>{ $scope.comments=res.comments; }); } }; } }
  26. 26. exportvarcommentsDirective:ng.IDirectiveFactory=()=>{ return{ restrict:"E", scope:{ mount:"=", appendComment:"=" }, replace:true, templateUrl:"comments/comments.html", controller:CommentsCtrl }; }; }
  27. 27. PROJECT STRUCTURE files/ comments/ utils/ ... app.ts main.d.ts typings.d.ts
  28. 28. PROJECT STRUCTURE app.ts ///<referencepath="main.d.ts"/> ///<referencepath="files/index.ts"/> ///<referencepath="comments/index.ts"/> ///<referencepath="utils/index.ts"/> exportvarmodule=angular.module("app",[ "gettext", files.module.name, comments.module.name, utils.module.name ]) }
  29. 29. PROJECT STRUCTURE comments/index.ts ///<referencepath="../app.ts"/> ///<referencepath="commentsDirective.ts"/> modulecomments{ exportvarmodule=angular.module("comments",[]) .directive("comments",commentsDirective); }
  30. 30. HOW TO TEST EVERYTHING? code coverage to the rescue usually used for test code coverage we can use it to see which lines were covered by manually "testing" the app
  31. 31. LIVECOVER Notpublishedyet.WillbeonGitHubandnpm. #GenerateannotatedJavaScriptcodewithBlanket.js $simple-blanket-oapp-cover.jsapp.js #RunLiveCoverserver $livecover-p3000 <scriptsrc="http://localhost:3000/coverage.js"></script> Open in your browser and start clicking like crazy. https://localhost:3000
  32. 32. QUESTIONS?

×