Reusing your frontend JS on the server with V8/Rhino

  • 668 views
Uploaded on

Writing modern web applications requires a ton of JS, and somewhere in that JS lies some application logic (we're not just talking DOM manipulations here). If you require that same logic on the …

Writing modern web applications requires a ton of JS, and somewhere in that JS lies some application logic (we're not just talking DOM manipulations here). If you require that same logic on the server-side for say, generating reports, what do you do? I'll show you how ValuationUP.com pushes the single responsibility principle to the max by "embedding" V8 into our report generation code so the same JS that powers our Backbone.js frontend powers our PDF's generated by Prawn.

Thin wrappers, no duplication, practical IoC, ultimate SRP.

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
668
On Slideshare
0
From Embeds
0
Number of Embeds
1

Actions

Shares
Downloads
2
Comments
0
Likes
2

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Reusing your frontend JSon the server with V8/RhinoPushing SRP & DI/IoC to whole new level
  • 2. Kenneth KalmerChief Rocket Scientist @ ValuationUP.com@kennethkalmergithub/kennethkalmerwww.opensourcery.co.za kennethkalmer
  • 3. ValuationUP.com Help entrepreneurs make REAL sense of their management accounts Comparative analysis within industry Refactoring financials by getting from red to green Take actions to increase their valuations Valuation is the ultimate metric
  • 4. The challengeWe need a very responsive UIRealtime updates as the user inputs informationThe RTT to the server is not worth the wait for such asimple formula
  • 5. Done!Repeat that for 50+ financial modelsBuild fully buzzword compliant frontend
  • 6. Panic! Let’s offer a PDF with all the information A PDF... ...WITH ALL THE INFORMATION
  • 7. We did it!But how?
  • 8. DilemmaDuplicate?Reuse?wkhtmltopdf? (a.k.a. wtftopdf)
  • 9. Reuse!Single Responsibility PrincipleDependency Injection/Inversion on ControlUse as much JS on the server as possible, wherepossible!
  • 10. By using therubyracer (github.com/cowboyd/rubyracer) therubyrhino (github.com/cowboyd/rubyrhino) coffee-script1 gem therubyracer, platforms: :ruby2 gem therubyrhino, platforms: :jruby34 gem coffee-script
  • 11. That’s WACC!
  • 12. With coffee 1 # Determine the WACC of the business (weighted average cost of capital) 2 class Demo.WACC 3 4 constructor: (statement) -> 5 @statement = statement 6 7 @cost_of_equity = statement.cost_of_equity 8 unless _.isFinite( @cost_of_equity ) 9 @cost_of_equity = 0.301011 calculate: ->1213 e = ( @statement.equity / ( @statement.debt + @statement.equity ) ) * @cost_of_equity14 d = ( @statement.debt / ( @statement.debt + @statement.equity ) ) * @statement.costOfDebt15 t = ( 1 - @statement.taxRate )1617 e + d * t1819 # Return the calculated WACC20 value: ->21 @wacc or= @calculate()
  • 13. Present it 1 class Demo.WaccLayout 2 3 # The view that will render our information 4 view: null 5 6 initialize: (data, view = null) -> 7 @data = data 8 @view = view 910 render: ->11 wacc = new Demo.WACC( @data.statement )1213 @view.render( wacc: wacc.value() )
  • 14. Client-side view & usage 1 # Simple backbone view 2 class Demo.WaccView extends Backbone.View 3 4 render: (options) -> 5 wacc = options.wacc 6 7 @$el.empty().append( "<h1>#{wacc}</h1>" ) 8 910111213 # Initialize a view14 view = new Demo.WaccView( el: #wacc )1516 # Load and render our layout17 layout = new Demo.WaccLayout( view: view, data: data )18 layout.render()
  • 15. Reuse on the server...
  • 16. JavaScript Context 1 require v8 2 # require rhino 3 4 # This service wraps a JS context and allows us to interact with our Javascript 5 # directly in Ruby. 6 class Javascript 7 8 # Our V8 context object 9 attr_reader :context1011 # Some delegations12 delegate :load, :eval, :[], :[]=, to: :context1314 def initialize()15 @context = V8::Context.new16 #@context = Rhino::Context.new1718 # Setup a fake window object19 @context[window] = FakeWindow.new( @context )20 @context[console] = FakeConsole.new2122 # Load our global setup23 load_coffee Rails.root.join( app/assets/javascripts/setup.js.coffee )24 end2526 # truncated, lots more detracting stuff down below...2728 end
  • 17. CoffeeScript sprinkles1 # Compile and load a CoffeeScript file into the current context2 def load_coffee( path )3 compiled_coffeescript = CoffeeScript.compile( File.read( path ) )4 context.eval compiled_coffeescript5 end
  • 18. PauseWe have a JavaScript context (V8) at our finger tipsHave some basic CoffeeScript loading abilitiesAnd some additional plumbingFar from a DOM
  • 19. Server-side wrapper 1 class WaccLayout 2 3 def initialize( view, context = Javascript.new ) 4 @context = context 5 6 load_dependencies 7 8 # Pass our Ruby view into the context 9 @context["view"] = view1011 # Setup12 @context.eval <<-EOJS13 var layout = new Demo.WaccLayout({14 view: view, data: data15 });16 EOJS17 end1819 def render20 context[layout][render].methodcall( context[layout] )21 end2223 def load_dependencies24 @context.load_coffee Rails.root.join("app/assets/javascripts/wacc.js.coffee")25 @context.load_coffee Rails.root.join("app/assets/javascripts/wacc_layout.js.coffee")26 end27 end
  • 20. Server-side view & usage 1 class WaccPdf 2 3 def initialize 4 @pdf = Prawn::Document.new 5 end 6 7 def render( options ) 8 wacc = options.wacc 910 @pdf.text "WACC: #{wacc}"11 end1213 end141516 # Setup a view17 view = WaccPdf.new1819 # Setup a layout and render20 layout = WaccLayout.new( view )21 layout.render
  • 21. 1,000 ft view
  • 22. Reminder why we did it?
  • 23. Yes please! https://github.com/kennethkalmer/rubyfuza-2013 https://rubyfuza-2013-wacc.herokuapp.com Later this weekend, you’re all getting drunk tonight anyway!!
  • 24. Thank you!It’s been wild!