$30 off During Our Annual Pro Sale. View Details »

The "Rails of JavaScript" won't be a framework

The "Rails of JavaScript" won't be a framework

As presented at RailsConf 2014. Video to follow.

Say [email protected]!

Justin Searls

April 25, 2014
Tweet

More Decks by Justin Searls

Other Decks in Programming

Transcript

  1. 1

  2. 2 1

  3. Ruby's tool ecosystem is mature, crowded Node's ecosystem is immature,

    innovative Tool authors aren't immune to trends Where are the best tools?
  4. Ruby's tool ecosystem is mature, crowded Node's ecosystem is immature,

    innovative Tool authors aren't immune to trends Tools address the problems of their day Where are the best tools?
  5. Ruby's tool ecosystem is mature, crowded Node's ecosystem is immature,

    innovative Tool authors aren't immune to trends Tools address the problems of their day Where are the best tools?
  6. Ruby's tool ecosystem is mature, crowded Node's ecosystem is immature,

    innovative Tool authors aren't immune to trends Tools address the problems of their day Web tools in Node better solve today's problems Where are the best tools?
  7. HTML UI ! app ├── controllers │ └── items_controller.rb ├──

    models │ └── item.rb └── views └── items └── index.html.erb
  8. HTML UI + JS ! app ├── controllers │ └──

    items_controller.rb ├── models │ └── item.rb ├── views │ └── items │ └── index.html.erb └── assets └── javascripts └── application.js
  9. HTML UI + JS UI ! app ├── controllers │

    └── items_controller.rb ├── models │ └── item.rb ├── views │ └── items │ └── index.html.erb └── assets └── javascripts └── more_app ├── controllers │ └── items_controller.js ├── models │ └── item.js └── views └── items └── index.jst.ejs
  10. HTML UI + JS UI ! app ├── controllers │

    └── items_controller.rb ├── models │ └── item.rb ├── views │ └── items │ └── index.html.erb └── assets └── javascripts └── more_app ├── controllers │ └── items_controller.js ├── models │ └── item.js └── views └── items └── index.jst.ejs
  11. HTML UI + JS UI ! app ├── controllers │

    └── items_controller.rb ├── models │ └── item.rb ├── views │ └── items │ └── index.html.erb └── assets └── javascripts └── more_app ├── controllers │ └── items_controller.js ├── models │ └── item.js └── views └── items └── index.jst.ejs
  12. HTML UI + JS UI ! app ├── controllers │

    └── items_controller.rb ├── models │ └── item.rb ├── views │ └── items │ └── index.html.erb └── assets └── javascripts └── more_app ├── controllers │ └── items_controller.js ├── models │ └── item.js └── views └── items └── index.jst.ejs
  13. HTML UI + JS UI ! app ├── controllers │

    └── items_controller.rb ├── models │ └── item.rb ├── views │ └── items │ └── index.html.erb └── assets └── javascripts └── more_app ├── controllers │ └── items_controller.js ├── models │ └── item.js └── views └── items └── index.jst.ejs
  14. JSON API + JS UI ! app ├── controllers │

    └── items_controller.rb ├── models │ └── item.rb │ │ │ └── assets └── javascripts └── more_app ├── controllers │ └── items_controller.js ├── models │ └── item.js └── views └── items └── index.jst.ejs
  15. JSON API + JS UI ! app ├── controllers │

    └── items_controller.rb ├── models │ └── item.rb │ │ │ └── assets └── javascripts └── more_app ├── controllers │ └── items_controller.js ├── models │ └── item.js └── views └── items └── index.jst.ejs
  16. JSON API + JS UI ! app ├── controllers │

    └── items_controller.rb ├── models │ └── item.rb │ │ │ └── assets └── javascripts └── more_app ├── controllers │ └── items_controller.js ├── models │ └── item.js └── views └── items └── index.jst.ejs vestigial appendage
  17. ap

  18. ap

  19. JSON API + JS UI ! app ├── controllers │

    └── items_controller.rb ├── models │ └── item.rb │ │ │ └── assets └── javascripts └── more_app ├── controllers │ └── items_controller.js ├── models │ └── item.js └── views └── items └── index.jst.ejs
  20. If you see this: ! <script> user = <%= user.to_json

    %> time = <%= Time.now.to_i %> </script>
  21. If you see this: ! <script> user = <%= user.to_json

    %> time = <%= Time.now.to_i %> items = <%= items.to_json %> </script>
  22. If you see this: ! <script> user = <%= user.to_json

    %> time = <%= Time.now.to_i %> items = <%= items.to_json %> token = "<%= @token %>" </script>
  23. ! <script> user = <%= user.to_json %> time = <%=

    Time.now.to_i %> items = <%= items.to_json %> token = "<%= @token %>" </script> Your yarn is tangled
  24. ! <script> user = <%= user.to_json %> time = <%=

    Time.now.to_i %> items = <%= items.to_json %> token = "<%= @token %>" </script> Your API is a lie
  25. Rails Rails Railsy Rake App Framework Convention & Config Build

    Automation Backbone Angular Ember ᵇ(´-ʆ)ᵃ

  26. Rails Rails Railsy Rake App Framework Convention & Config Build

    Automation Node.js Backbone Angular Ember ᵇ(´-ʆ)ᵃ

  27. Rails Rails Railsy Rake App Framework Convention & Config Build

    Automation Node.js ??? Backbone Angular Ember ᵇ(´-ʆ)ᵃ

  28. Rails Rails Railsy Rake App Framework Convention & Config Build

    Automation Node.js Lineman Backbone Ember Angular ᵇ(´-ʆ)ᵃ

  29. hi() code ! save loadTask = (module) -> if fs.existsSync("#{process.cwd()}/node_modules/#{module}")

    grunt.loadNpmTasks(module) else grunt.loadTasks("#{__dirname}/../node_modules/#{module}/ tasks") npmTasks = grunt.util._(linemanNpmTasks).chain(). union("grunt-contrib-sass" if config.enableSass). union(config.loadNpmTasks). compact().value() loadTask task for task in npmTasks grunt.renameTask "copy", "images" loadTask "grunt-contrib-copy" # load again so webfonts can use it grunt.renameTask "copy", "webfonts" loadTask "grunt-contrib-copy" # load again to make available in userland compile
  30. hi() code ! save loadTask = (module) -> if fs.existsSync("#{process.cwd()}/node_modules/#{module}")

    grunt.loadNpmTasks(module) else grunt.loadTasks("#{__dirname}/../node_modules/#{module}/ tasks") npmTasks = grunt.util._(linemanNpmTasks).chain(). union("grunt-contrib-sass" if config.enableSass). union(config.loadNpmTasks). compact().value() loadTask task for task in npmTasks grunt.renameTask "copy", "images" loadTask "grunt-contrib-copy" # load again so webfonts can use it grunt.renameTask "copy", "webfonts" loadTask "grunt-contrib-copy" # load again to make available in userland compile loadTask task for task in npmTasks grunt.renameTask "copy", "images" loadTask "grunt-contrib-copy" # load again so webfonts can use it grunt.renameTask "copy", "webfonts" loadTask "grunt-contrib-copy" # load again to make available in userland loadTask = (module) -> if fs.existsSync("#{process.cwd()}/node_modules/#{module}") grunt.loadNpmTasks(module) else grunt.loadTasks("#{__dirname}/../node_modules/#{module}/tasks") npmTasks = grunt.util._(linemanNpmTasks).chain(). union("grunt-contrib-sass" if config.enableSass). union(config.loadNpmTasks). compact().value() concat
  31. hi() code ! save loadTask = (module) -> if fs.existsSync("#{process.cwd()}/node_modules/#{module}")

    grunt.loadNpmTasks(module) else grunt.loadTasks("#{__dirname}/../node_modules/#{module}/ tasks") npmTasks = grunt.util._(linemanNpmTasks).chain(). union("grunt-contrib-sass" if config.enableSass). union(config.loadNpmTasks). compact().value() loadTask task for task in npmTasks grunt.renameTask "copy", "images" loadTask "grunt-contrib-copy" # load again so webfonts can use it grunt.renameTask "copy", "webfonts" loadTask "grunt-contrib-copy" # load again to make available in userland compile loadTask task for task in npmTasks grunt.renameTask "copy", "images" loadTask "grunt-contrib-copy" # load again so webfonts can use it grunt.renameTask "copy", "webfonts" loadTask "grunt-contrib-copy" # load again to make available in userland loadTask = (module) -> if fs.existsSync("#{process.cwd()}/node_modules/#{module}") grunt.loadNpmTasks(module) else grunt.loadTasks("#{__dirname}/../node_modules/#{module}/tasks") npmTasks = grunt.util._(linemanNpmTasks).chain(). union("grunt-contrib-sass" if config.enableSass). union(config.loadNpmTasks). compact().value() concat hello world! play
  32. < 100ms hi() code ! save loadTask = (module) ->

    if fs.existsSync("#{process.cwd()}/node_modules/#{module}") grunt.loadNpmTasks(module) else grunt.loadTasks("#{__dirname}/../node_modules/#{module}/ tasks") npmTasks = grunt.util._(linemanNpmTasks).chain(). union("grunt-contrib-sass" if config.enableSass). union(config.loadNpmTasks). compact().value() loadTask task for task in npmTasks grunt.renameTask "copy", "images" loadTask "grunt-contrib-copy" # load again so webfonts can use it grunt.renameTask "copy", "webfonts" loadTask "grunt-contrib-copy" # load again to make available in userland compile loadTask task for task in npmTasks grunt.renameTask "copy", "images" loadTask "grunt-contrib-copy" # load again so webfonts can use it grunt.renameTask "copy", "webfonts" loadTask "grunt-contrib-copy" # load again to make available in userland loadTask = (module) -> if fs.existsSync("#{process.cwd()}/node_modules/#{module}") grunt.loadNpmTasks(module) else grunt.loadTasks("#{__dirname}/../node_modules/#{module}/tasks") npmTasks = grunt.util._(linemanNpmTasks).chain(). union("grunt-contrib-sass" if config.enableSass). union(config.loadNpmTasks). compact().value() concat hello world! play
  33. < 100ms hi() code ! save loadTask = (module) ->

    if fs.existsSync("#{process.cwd()}/node_modules/#{module}") grunt.loadNpmTasks(module) else grunt.loadTasks("#{__dirname}/../node_modules/#{module}/ tasks") npmTasks = grunt.util._(linemanNpmTasks).chain(). union("grunt-contrib-sass" if config.enableSass). union(config.loadNpmTasks). compact().value() loadTask task for task in npmTasks grunt.renameTask "copy", "images" loadTask "grunt-contrib-copy" # load again so webfonts can use it grunt.renameTask "copy", "webfonts" loadTask "grunt-contrib-copy" # load again to make available in userland compile loadTask task for task in npmTasks grunt.renameTask "copy", "images" loadTask "grunt-contrib-copy" # load again so webfonts can use it grunt.renameTask "copy", "webfonts" loadTask "grunt-contrib-copy" # load again to make available in userland loadTask = (module) -> if fs.existsSync("#{process.cwd()}/node_modules/#{module}") grunt.loadNpmTasks(module) else grunt.loadTasks("#{__dirname}/../node_modules/#{module}/tasks") npmTasks = grunt.util._(linemanNpmTasks).chain(). union("grunt-contrib-sass" if config.enableSass). union(config.loadNpmTasks). compact().value() concat hello world! play
  34. test < 100ms hi() code ! save loadTask = (module)

    -> if fs.existsSync("#{process.cwd()}/node_modules/#{module}") grunt.loadNpmTasks(module) else grunt.loadTasks("#{__dirname}/../node_modules/#{module}/ tasks") npmTasks = grunt.util._(linemanNpmTasks).chain(). union("grunt-contrib-sass" if config.enableSass). union(config.loadNpmTasks). compact().value() loadTask task for task in npmTasks grunt.renameTask "copy", "images" loadTask "grunt-contrib-copy" # load again so webfonts can use it grunt.renameTask "copy", "webfonts" loadTask "grunt-contrib-copy" # load again to make available in userland compile loadTask task for task in npmTasks grunt.renameTask "copy", "images" loadTask "grunt-contrib-copy" # load again so webfonts can use it grunt.renameTask "copy", "webfonts" loadTask "grunt-contrib-copy" # load again to make available in userland loadTask = (module) -> if fs.existsSync("#{process.cwd()}/node_modules/#{module}") grunt.loadNpmTasks(module) else grunt.loadTasks("#{__dirname}/../node_modules/#{module}/tasks") npmTasks = grunt.util._(linemanNpmTasks).chain(). union("grunt-contrib-sass" if config.enableSass). union(config.loadNpmTasks). compact().value() concat
  35. ! $ lineman build ! $ tree dist ! dist

    ├── css │ └── app.css ├── index.html └── js └── app.js
  36. ! $ lineman build ! $ tree dist ! dist

    ├── assets.json ├── css │ └── app-6193b1...54592.css ├── index.html └── js └── app-8b750b...57f62.js
  37. Text goes here. ! $ npm install --save-dev lineman-bower !

    $ lineman run ! ... Running "bower:install" (bower) task >> Installed bower packages ... zero-config plugins
  38. noun project attribution Yarn designed by Marie Coons from The

    Noun Project! ! Scale designed by Ritika Khasgiwale from The Noun Project