Slide 1

Slide 1 text

Using Ruby for Integrated Javascript Development Introducing Iridium Wednesday, August 15, 12

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

Goal: Build an Ambitious Ember App Wednesday, August 15, 12

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

• 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

Slide 6

Slide 6 text

Our Tools Wednesday, August 15, 12

Slide 7

Slide 7 text

Javascript ... Verdammt Wednesday, August 15, 12

Slide 8

Slide 8 text

• 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

Slide 9

Slide 9 text

Hard Problems mit Lösungen Wednesday, August 15, 12

Slide 10

Slide 10 text

• 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

Slide 11

Slide 11 text

thought = "I’ll just use #{[ "commonjs", "AMD", "requirejs", "E6 Modules" ].rand}!" Wednesday, August 15, 12

Slide 12

Slide 12 text

Code Loading Comparison Language Example Uses HTML C #include No :) Ruby require ‘socket’ No :) Python import fibo No :) JavaScript Yes :( Wednesday, August 15, 12

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

Loading JS: Minispade • 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

Slide 15

Slide 15 text

Compilation Wednesday, August 15, 12

Slide 16

Slide 16 text

$ cat **/*.coffee | coffescript > application.js Wednesday, August 15, 12

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

Coffeescript Concatenation Minification Compression application.js Wednesday, August 15, 12

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

What About Red, Green, Refactor? Wednesday, August 15, 12

Slide 22

Slide 22 text

// simplest possible test test("true", function() { ok(true, "True is true"); }); Let’s just fire this test up... Wednesday, August 15, 12

Slide 23

Slide 23 text

1. Ensure we have the correct application.js loadable 2. Make an HTML file 3. Add a 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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

#77 - Iridium (It’s an Element) Wednesday, August 15, 12

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

$ 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

Slide 30

Slide 30 text

// 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

Slide 31

Slide 31 text

$ iridium test Testable Wednesday, August 15, 12

Slide 32

Slide 32 text

$ 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

Slide 33

Slide 33 text

$ 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

Slide 34

Slide 34 text

class Todos < Iridium::Application config.load :minispade config.load :jquery config.load :handlebars config.load :ember end Dependency Management Wednesday, August 15, 12

Slide 35

Slide 35 text

$ iridium compile # production $ iridium compile ENV=staging Compilable Wednesday, August 15, 12

Slide 36

Slide 36 text

$ iridium lint If You Have OCD Wednesday, August 15, 12

Slide 37

Slide 37 text

github.com/ radiumsoftware/iridium git clone Wednesday, August 15, 12