Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Using Ruby for Integrated Javascript Developmen...

Using Ruby for Integrated Javascript Development: Introducing Iridium

There are many problems doing modern javascript development. Its hard to get up and running, it's hard to organize code. It's hard to do a lot of things. I show you how we created an integrated solution using ruby to make developing complete JS applications so much easier.

I presented this at @cgnjs (Cologne JS) in Germany.

Adam Hawkins

August 14, 2012
Tweet

More Decks by Adam Hawkins

Other Decks in Programming

Transcript

  1. var Me = { }; • Ich heiße Adam Hawkins

    • @adman65 • https://github.com/twinturbo • Lead Code Monkey at Radium • Primarily Ruby guy, now focused on JS Wednesday, August 15, 12
  2. Ambitious (n) / Ambitioniert (h) • Organized: Directory structure reflects

    code’s responsibility • Testable: Headless and Automated • Compilable: Coffeescript, Handlebars, and SCSS • Reloadable: Develop in the Browser • Completely separate from any other code. Separate repos. Separate servers. Separate everything--allow per project optimizations. Wednesday, August 15, 12
  3. • We all have our own native language • Independent

    frontend and backend • We meet at the API • More frontend guys then backend guys Our Team Wednesday, August 15, 12
  4. • How can we write our code in Coffeescript? •

    How can we write our CSS in SCSS? • How can we organize & require our code? • How can we unit test? • How can we run integration tests? Wednesday, August 15, 12
  5. • Organized code has boundaries • Organized code is reusable

    • Organized code is split into many source files • Organized code can be required or imported • Now you’re thinking.... Organization ... lolwut Wednesday, August 15, 12
  6. thought = "I’ll just use #{[ "commonjs", "AMD", "requirejs", "E6

    Modules" ].rand}!" Wednesday, August 15, 12
  7. Code Loading Comparison Language Example Uses HTML C #include<stdio.h> No

    :) Ruby require ‘socket’ No :) Python import fibo No :) JavaScript <script src=”foo.js”></script> Yes :( Wednesday, August 15, 12
  8. Solutions ? • Accept it sucks & use a module

    loader • Wait for ES6 Modules. This will only take 5 lifetimes. • Use a Polyfill • Approach the problem from a new angle Wednesday, August 15, 12
  9. Loading JS: Minispade • <script> tags...<script> tag’s everywhere • Works

    when you have a small number of files • Blows up when you have hundreds or thousands • Use Minispade to wrap all individual source files in functions and dump them into a single file during compilation Wednesday, August 15, 12
  10. That Was Easy Right? • ... but I need to

    combine them into one file • ... but I need to load extra JS depending on environment (test/development/production) • ... but I want to minify it in production • ... but I only want something when I’m developing • ... but what about images and other assets? Wednesday, August 15, 12
  11. Rake::Pipeline • I know Ruby. Let’s use Rake::Pipeline to compile

    the application • It’s a series of tubes • Input files mapped to output files • It can do everything we need Wednesday, August 15, 12
  12. Rake::Pipeline.build input "app" output "site" match "javascripts/**/*.coffee" do coffeescript end

    match "stylesheets/**/*.scss" do scss end match "**/*.js" do contact "application.js" uglify if production? end match "**/*.css" do contact "application.css" yui_css if production? end end Wednesday, August 15, 12
  13. // simplest possible test test("true", function() { ok(true, "True is

    true"); }); Let’s just fire this test up... Wednesday, August 15, 12
  14. 1. Ensure we have the correct application.js loadable 2. Make

    an HTML file 3. Add a <script> tag for qunit 4. Add a <script> tag for our test(s) 5. Write <script> tags for any other files we need 6. Human opens the HTML file using a browser 7. Human verifies results After We Do All This: Wednesday, August 15, 12
  15. Integration Tests • Use a server to serve and boot

    the app • Use something to simulate user activity...no seriously what do you use? • Report Results Wednesday, August 15, 12
  16. What’s the Problem • We need HTML (this makes me

    sad) • Humans are involved • No unified test runner from the command line • How does this process map to CI? • Hard to run individual tests Wednesday, August 15, 12
  17. Iridium: Dev Faster • Unified test runner for integration and

    unit tests -- all from CLI • Sensible defaults for asset compilation with Rake::Pipeline • Code “modularization” with Minispade • Configurable based on environment (development, test, production) • Make it all work seamlessly Wednesday, August 15, 12
  18. Architecture • Written in Ruby & designed for Javascript •

    Rake::Pipeline for asset compilation • PhantomJS, CasperJS + Patches for automated tests • Minispade for JS module loading • Preload jQuery and Handlebars • Preload Qunit and Sinon for testing • Not framework specific. Can use Ember, Backbone, etc Wednesday, August 15, 12
  19. $ cd projects/todos $ iridium server >> Thin web server

    (v1.4.1 codename Chromeo) >> Maximum connections set to 1024 >> Listening on 0.0.0.0:9292, CTRL+C to stop Relodable ... now hit Refresh Wednesday, August 15, 12
  20. // app.js - loads all the code Todos = Ember.Application.create({

    VERSION: '1.0', storeNamespace: 'todos-emberjs', }); require('todos/router'); // app/javascripts/router.js|coffee require('todos/models'); // app/javascripts/models.js|coffee require('todos/controllers'); // you get require('todos/views'); // the point require('todos/templates'); // by now Organized Wednesday, August 15, 12
  21. $ iridium test integration/todo.coffee # integration test with CasperJS #

    test/integration/todo.coffee casper.start 'http://localhost:7777/', -> @test.assertExists('#new-todo', 'todo form found') casper.run -> @test.done() Fullstack Tests Wednesday, August 15, 12
  22. $ iridium test test/model_test.coffee # test/models_test.coffee test "should default to

    not done", -> equal Models.todo.get('isDone'), false, "todo is not done" test "should set todo title", -> Models.todo.set 'title', "A todo" equal Models.todo.get('title'), "A todo", "todo title is set" test "should be able to signify isdone", -> Models.todo.set 'isDone', true ok Models.todo.get('isDone'), "Todo is done" Unit Tests Wednesday, August 15, 12
  23. class Todos < Iridium::Application config.load :minispade config.load :jquery config.load :handlebars

    config.load :ember end Dependency Management Wednesday, August 15, 12