0
JAVASCRIPT &1ST CLASS CITIZENRYFast, modular code with RequireJS &node.js                              talks@goneopen.com
Size and complexityAs JavaScript applications grow in size andcomplexity we need a real tool to handledependencies and kee...
Agenda• Global Pollution• Dependencies &  Modularisation• Building and Testing• Optimisation
Global PollutionIn Javascript, global functions are not agood strategy. They pollute. So, too do wellknown namespaces – bu...
Badness 1: Global functions<body>      <button onclick="addMovie()">addMovie</button>      <script type="text/javascript”>...
Badness 2: Well-known namespaces<html><head>          <script src=http://code.jquery.com/jquery.js …          <script src=...
Template Pattern(function($) {    // nothing outside here can call this function    function sumWithInterest( el, interset...
RequireJs (module) patterndefine([“jquery”], function($) {     function sumWithInterest( el, interest){       return $(el)...
Dependencies & ModularisationLet‟s take that all a little bit more slowly.
Each module ecapsulatesCreate                     Consumedefine(“main”,             require(“main”)  function(){      //al...
Access in is via a return onlyCreate            Consumedefine(“main”,    require(“main”).init()  function(){      return {...
Dependencies are explicitdefine(“main”, [„log‟, „jquery‟],  function( log, $ ){       log.debug( $(„body‟).text() )    })
Module loading can be ordereddefine(“main”, [„log‟, „order!jquery‟, „order!jsrender‟],    function( log, $ ){       $.temp...
Building & Testing
Build command line•   Rake•   Gradle•   Psake•   Msbuild•   Ant•   Bat•   sh
Test-first via jasmineUnits• Views• EventsAcceptance• Full loading
Test html           Code template <li>                              <i>{{:type}}</i> (<abbr                           clas...
Test Eventsit("should register add order handler”, function() {     _requires([“coffee/loader”]));    spyOn(_, order).andC...
Test that it actually works!    it("should be able to add new order", function(){       _requires(["coffee/main"]));      ...
Build and get runtime errors$ rake buildnode lib/r.js -o app.build.jsTracing dependencies for: coffee/mainError: Error eva...
Throw away the debugger no break points or step through   … no really, I‟m serious
OptimisationWe still need to package code ready forserving. Why wait until run?
Script-tag vomitIn development, it’s good   Production, it’s not
Pretty clean
Create bundles & linted
Script and CSS compressed
Ready for deployment
Gotchas!• File paths between development and    production•   CSS url paths•   Text (html, json) loading without server•  ...
Follow-up areas•   Different AMD implementations•   Plugins (page load, internationalisation)•   Lazy and dynamic loading•...
Finally, what does this mean?• We can unit test web-based application at the  GUI layer• We CAN reduce the number of  expe...
Useful refs (and referred tomaterials)• http://www.angrycoding.com/2011/09/managing-dependencies-with-    requirejs.html• ...
Good luck                               Todd Brackley                               goneopen.com                          ...
Upcoming SlideShare
Loading in...5
×

Javascript first-class citizenery

1,489

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
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
1,489
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
22
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Transcript of "Javascript first-class citizenery"

  1. 1. JAVASCRIPT &1ST CLASS CITIZENRYFast, modular code with RequireJS &node.js talks@goneopen.com
  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: http://www.meetup.com/jQuery-Boston/events/16191792/
  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 (this.name); } </script></body>
  6. 6. Badness 2: Well-known namespaces<html><head> <script src=http://code.jquery.com/jquery.js … <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 app.build.jsTracing 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)• http://www.angrycoding.com/2011/09/managing-dependencies-with- requirejs.html• http://patrickmcelhaney.com/AMD-Talk/#microjs• http://projects.haykranen.nl/amsterdamjs• http://www.slideshare.net/JulienZee/parisjs-10-requirejs-9111799• http://www.slideshare.net/tim_doherty/requirejs-8858167• http://www.slideshare.net/timoxley/testable-client-sidemvcappsinjavascript• http://www.slideshare.net/sioked/requirejs
  32. 32. Good luck Todd Brackley goneopen.com twitter: toddbNZ code: github.com/toddb/javascript-amd
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×