Javascript first-class citizenery


Published on

Javascript and first-class citizenry: require.js & node.js

Javascript on web pages is ubiquitous and its problems are legendary. Javascript, seen as a second-class code citizen, is usually hacked together even by seasoned developers. New libraries (jQuery, prototype, backbone, knockout, underscore) and runtime tools (firebug, jasmine) look like they solve many problems - and they do. But they still leave poorly written code as just that. One key problem is that all javascript code lives globally and this results in poorly managed, tested and delivered code.

In this session, I will illustrate that we can treat javascript as a first-class citizen using with require.js and node.js: it can be modular, encapsulated and easily unit tested and added to continuous integration cycle. The dependencies between javascript modules can also be managed and packaged just like in C# and Java. In the end, we can resolve many javascript difficulties at compile time rather than waiting until runtime.

Published in: Technology
  • Be the first to comment

  • Be the first to like this

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Javascript first-class citizenery

  1. 1. JAVASCRIPT &1ST CLASS CITIZENRYFast, modular code with RequireJS &node.js
  2. 2. Size and complexityAs JavaScript applications grow in size andcomplexity we need a real tool to handledependencies and keep our code modular.RequireJS give you an easy way to definedependencies on your module and itll makesure it‟s loaded before your code runs. It alsohas a nice build system which can be used tocompress and obfuscate your code using aclosure compiler. Adapted from:
  3. 3. Agenda• Global Pollution• Dependencies & Modularisation• Building and Testing• Optimisation
  4. 4. Global PollutionIn Javascript, global functions are not agood strategy. They pollute. So, too do wellknown namespaces – but we‟ll live withthat. Modules provide a way forwardagainst these problems.
  5. 5. Badness 1: Global functions<body> <button onclick="addMovie()">addMovie</button> <script type="text/javascript”> function addMovie() { $.observable( movies ).insert (; } </script></body>
  6. 6. Badness 2: Well-known namespaces<html><head> <script src= … <script src="jsrender.js" type="text/javascript"></script></head><body> <div id="movieList"><b>Our Movies</b><br /></div> <script type="text/javascript”> $.templates({ movieTemplate: "#movieList” }) $.template.moveTemplate.render( ) </script></body></html>
  7. 7. Template Pattern(function($) { // nothing outside here can call this function function sumWithInterest( el, interset){ return $(el).val() * interest; } $.extend($.fn , sumWithInterest) // except …}(jQuery));
  8. 8. RequireJs (module) patterndefine([“jquery”], function($) { function sumWithInterest( el, interest){ return $(el) .val() * interest; } return sumWithInterest// object or function});
  9. 9. Dependencies & ModularisationLet‟s take that all a little bit more slowly.
  10. 10. Each module ecapsulatesCreate Consumedefine(“main”, require(“main”) function(){ //all code in here // is scoped })
  11. 11. Access in is via a return onlyCreate Consumedefine(“main”, require(“main”).init() function(){ return { init:function(){…} } })
  12. 12. Dependencies are explicitdefine(“main”, [„log‟, „jquery‟], function( log, $ ){ log.debug( $(„body‟).text() ) })
  13. 13. Module loading can be ordereddefine(“main”, [„log‟, „order!jquery‟, „order!jsrender‟], function( log, $ ){ $.template(„body‟).render() log.debug( $(„body‟).text() ) })
  14. 14. Building & Testing
  15. 15. Build command line• Rake• Gradle• Psake• Msbuild• Ant• Bat• sh
  16. 16. Test-first via jasmineUnits• Views• EventsAcceptance• Full loading
  17. 17. Test html Code template <li> <i>{{:type}}</i> (<abbr class="date”{{:ordered}}</abbr>) </li>Testdescribe("Html views", function() { var data = { type: "small", ordered: "1 min ago" } it("has a line item", function() { _requires(["text!coffee/views/_item.html", jsrender], function( text ){ $( "#test" ).html( $.templates( text ).render( data ) ); expect($("li", "#test" ).size()).toEqual(1); }); }
  18. 18. Test Eventsit("should register add order handler”, function() { _requires([“coffee/loader”])); spyOn(_, order).andCallThrough() _.orderHandler( $(#test), function(){ return {} ) $(#test).click() expect(_.order).toHaveBeenCalled() });
  19. 19. Test that it actually works! it("should be able to add new order", function(){ _requires(["coffee/main"])); val = $(li, ‟#orders).size(); $(button.order, ‟#orders).click()expect($(li, ‟#orders).size()).toEqual(val++); });
  20. 20. Build and get runtime errors$ rake buildnode lib/r.js -o dependencies for: coffee/mainError: Error evaluating module "undefined" atlocation"/Users/todd/Documents/src/coffee/build/scripts/coffee/main.js":Unexpected token: punc (,) (line: 4, col: 16, pos:152)
  21. 21. Throw away the debugger no break points or step through … no really, I‟m serious
  22. 22. OptimisationWe still need to package code ready forserving. Why wait until run?
  23. 23. Script-tag vomitIn development, it’s good Production, it’s not
  24. 24. Pretty clean
  25. 25. Create bundles & linted
  26. 26. Script and CSS compressed
  27. 27. Ready for deployment
  28. 28. Gotchas!• File paths between development and production• CSS url paths• Text (html, json) loading without server• Creating a localhost server for text• Hassle for smaller projects
  29. 29. Follow-up areas• Different AMD implementations• Plugins (page load, internationalisation)• Lazy and dynamic loading• Wrapping non-AMD code• Coffeescript• Data-main loading• Build runners and CI integration
  30. 30. Finally, what does this mean?• We can unit test web-based application at the GUI layer• We CAN reduce the number of expensive, system tests (eg selenium)• Modularity and testing are likely to allow smaller pieces of work and potentially increased flow• All this (coupled with REST) means interesting times!
  31. 31. Useful refs (and referred tomaterials)• requirejs.html••••••
  32. 32. Good luck Todd Brackley twitter: toddbNZ code: