reusing your frontend js on the server with v8/rhino

27
Reusing your frontend JS on the server with V8/Rhino Pushing SRP & DI/IoC to whole new level

Upload: kenneth-kalmer

Post on 17-May-2015

735 views

Category:

Technology


1 download

DESCRIPTION

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.

TRANSCRIPT

Page 1: Reusing your frontend JS on the server with V8/Rhino

Reusing your frontend JS on the server with V8/RhinoPushing SRP & DI/IoC to whole new level

Page 2: Reusing your frontend JS on the server with V8/Rhino

Kenneth Kalmer

Chief Rocket Scientist @ ValuationUP.com

@kennethkalmer

github/kennethkalmer

www.opensourcery.co.za

kennethkalmer

Page 3: Reusing your frontend JS on the server with V8/Rhino

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

Page 4: Reusing your frontend JS on the server with V8/Rhino

The challenge

We need a very responsive UI

Realtime updates as the user inputs information

The RTT to the server is not worth the wait for such a simple formula

Page 5: Reusing your frontend JS on the server with V8/Rhino
Page 6: Reusing your frontend JS on the server with V8/Rhino

Done!

Repeat that for 50+ financial models

Build fully buzzword compliant frontend

Page 7: Reusing your frontend JS on the server with V8/Rhino

Panic!

Let’s offer a PDF with all the information

A PDF...

...WITH ALL THE INFORMATION

Page 8: Reusing your frontend JS on the server with V8/Rhino
Page 9: Reusing your frontend JS on the server with V8/Rhino

We did it!But how?

Page 10: Reusing your frontend JS on the server with V8/Rhino

Dilemma

Duplicate?

Reuse?

wkhtmltopdf? (a.k.a. wtftopdf)

Page 11: Reusing your frontend JS on the server with V8/Rhino

Reuse!

Single Responsibility Principle

Dependency Injection/Inversion on Control

Use as much JS on the server as possible, where possible!

Page 12: Reusing your frontend JS on the server with V8/Rhino

By usingtherubyracer (github.com/cowboyd/rubyracer)

therubyrhino (github.com/cowboyd/rubyrhino)

coffee-script

1 gem 'therubyracer', platforms: :ruby2 gem 'therubyrhino', platforms: :jruby3 4 gem 'coffee-script'

Page 13: Reusing your frontend JS on the server with V8/Rhino

That’s WACC!

Page 14: Reusing your frontend JS on the server with V8/Rhino

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.3010 11 calculate: ->12 13 e = ( @statement.equity / ( @statement.debt + @statement.equity ) ) * @cost_of_equity14 d = ( @statement.debt / ( @statement.debt + @statement.equity ) ) * @statement.costOfDebt15 t = ( 1 - @statement.taxRate )16 17 e + d * t18 19 # Return the calculated WACC20 value: ->21 @wacc or= @calculate()

Page 15: Reusing your frontend JS on the server with V8/Rhino

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 9 10 render: ->11 wacc = new Demo.WACC( @data.statement )12 13 @view.render( wacc: wacc.value() )

Page 16: Reusing your frontend JS on the server with V8/Rhino

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 9 10 11 12 13 # Initialize a view14 view = new Demo.WaccView( el: '#wacc' )15 16 # Load and render our layout17 layout = new Demo.WaccLayout( view: view, data: data )18 layout.render()

Page 17: Reusing your frontend JS on the server with V8/Rhino

Reuse on the server...

Page 18: Reusing your frontend JS on the server with V8/Rhino

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 :context10 11 # Some delegations12 delegate :load, :eval, :[], :[]=, to: :context13 14 def initialize()15 @context = V8::Context.new16 #@context = Rhino::Context.new17 18 # Setup a fake 'window' object19 @context['window'] = FakeWindow.new( @context )20 @context['console'] = FakeConsole.new21 22 # Load our global setup23 load_coffee Rails.root.join( 'app/assets/javascripts/setup.js.coffee' )24 end25 26 # truncated, lots more detracting stuff down below...27 28 end

Page 19: Reusing your frontend JS on the server with V8/Rhino

CoffeeScript sprinkles

1 # 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

Page 20: Reusing your frontend JS on the server with V8/Rhino

Pause

We have a JavaScript context (V8) at our finger tips

Have some basic CoffeeScript loading abilities

And some additional plumbing

Far from a DOM

Page 21: Reusing your frontend JS on the server with V8/Rhino

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"] = view10 11 # Setup12 @context.eval <<-EOJS13 var layout = new Demo.WaccLayout({14 view: view, data: data15 });16 EOJS17 end18 19 def render20 context['layout']['render'].methodcall( context['layout'] )21 end22 23 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

Page 22: Reusing your frontend JS on the server with V8/Rhino

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 9 10 @pdf.text "WACC: #{wacc}"11 end12 13 end14 15 16 # Setup a view17 view = WaccPdf.new18 19 # Setup a layout and render20 layout = WaccLayout.new( view )21 layout.render

Page 23: Reusing your frontend JS on the server with V8/Rhino

1,000 ft view

Page 24: Reusing your frontend JS on the server with V8/Rhino

Reminder why we did it?

Page 25: Reusing your frontend JS on the server with V8/Rhino
Page 26: Reusing your frontend JS on the server with V8/Rhino

Yes please!

https://github.com/kennethkalmer/rubyfuza-2013

https://rubyfuza-2013-wacc.herokuapp.com

Later this weekend, you’re all getting drunk tonight anyway!!

Page 27: Reusing your frontend JS on the server with V8/Rhino

Thank you!It’s been wild!