The Bits Behind JS Bin

The Bits Behind JS Bin

The story behind JS Bin, how it came to be, why it moved to Node, the drivers and some of the challenges in running the app.

C8b387c489181844b3ffc704fadc0f14?s=128

Remy Sharp

June 10, 2014
Tweet

Transcript

  1. The Bits Behind JS Bin Remy Sharp — @rem

  2. Hi. Mine: nodemon 5minfork.com Full Frontal Me: @rem remy@leftlogic.com remysharp.com

  3. JS Bin?

  4. • 415,000 uniques/month (2mil page views) • 30-35 queries per

    second • 69,000+ registered users • 9.6mil bins in total / 1.5mil "owned" bins • 48 timers & lots of iframes!
  5. BACKSTORY

  6. Originally a PHP hack • Inspired by XHR insolation issues

    • Proceeded by ugliness (codedumper.com) • Tipping point: John Resig's http://ejohn.org/apps/learn/ • Approximately 4 hours of dev to live
  7. Workshop in Iceland

  8. Code Casting I wanted to create

  9. jsconf.eu 2009

  10. Förbind http://forbind.net

  11. None
  12. Pre-decent require

  13. Pre-package knowledge

  14. Straight up nutty

  15. 2 hours later...

  16. None
  17. Förbind: how it works express socket.io mongodb ejs Tightly coupled

    collections listening for messages, then firing it on all open connections. Restart and it all breaks...
  18. April 2012 & @aron

  19. 100% JavaScript

  20. None
  21. Pros of Node for JS Bin • CodeCasting & live

    reload (across all platforms) • Easy local and dependency free installs • Some code reuse, lots of knowledge reuse.
  22. The Spike

  23. Thank you Boris Grishenko

  24. Author JS Bin XHR save on keypress DB spike.js update

    event IE8 Chrome xbox iOS Firefox OS etc SSE push The Spike
  25. • Client saves on keypress • Server on save triggers

    "spike update" event with bin passed to event • Spike searches for sessions interested in that bin, and sends the updated panel
  26. All authored content is streamable •CodeCasting is easy •LiveReload is

    easy •Live injection into PhoneGap is easy
  27. Good Side Effect • XSS recently fixed using postMessage &

    run.jsbin.com • IE7 doesn't support postMessage • But IE7 does LiveReload - so IE still works & securely
  28. None
  29. None
  30. if (res.connection.writable === false) { // remove cached connection }

    Is the connection open?
  31. Testing event source • Sadly no devtools (http://crbug.com/254973) • curl

    --header "Accept: text/event-stream" <url>
  32. None
  33. No WebSockets? •EventSource is polyfilled only with JS •IE6-9 •Android

    Browser
  34. None
  35. Local installs • Always possible since day #1 on github

    • Now via `npm install -g jsbin` • Windows support is (now) pretty solid
  36. Database upgrades via npm • Package.json "scripts": { "install": "build/install.js",

    "preupdate": "build/pre-update.js", "postupdate": "build/post-update.js" }, • Pre-update - saves current version • Post-update - uses semver & checks upgrade/<version>/*.sql
  37. Dependency free •USB contains Node binaries for all platforms, code

    & dependancies •Saves to raw HTML files on USB stick •For teaching in strict tech environment
  38. todo •Add update-notifier for prompted updates •Get visibility on local

    installs •Release to npm frequently
  39. Features

  40. None
  41. None
  42. • Paid/donated • Alternative domain (ie. jsbin.leftlogic.com) • Each dev

    runs under rem.jsbin.leftlogic.com • Now we can remotely view each other's work ngrok
  43. Production

  44. scripts.json

  45. index template

  46. Grunt build generates concat & uglified. Triggered by...

  47. .git/hooks/post-merge remy@jsbin:/WWW/jsbin$ git pull remote: Counting objects: 19, done. remote:

    Compressing objects: 100% (7/7), done. remote: Total 11 (delta 8), reused 7 (delta 4) Unpacking objects: 100% (11/11), done. From git://github.com/remy/jsbin a7bf4f8..f99beff master -> origin/master * [new branch] feature/menu-update -> origin/feature/menu-up Merge made by the 'recursive' strategy. test/loop_detection_test.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) rebuild jsbin.js? [Y/n] y building public js Running "concat:dist" (concat) task File "public/js/prod/jsbin-3.4.8.js" created. Running "concat:runner" (concat) task File "public/js/prod/runner-3.4.8.js" created. Running "uglify:dist" (uglify) task Source Map "public/js/prod/jsbin.map.json" created. File "public/js/prod/jsbin-3.4.8.min.js" created. Running "uglify:runner" (uglify) task File "public/js/prod/runner-3.4.8.min.js" created. Done, without errors. restart jsbin? [Y/n] y restarting forever info: Forever restarted processes: data: uid command script forever pid logfile
  48. Upstart console log stop on shutdown respawn respawn limit 20

    5 post-start script # log that we restarted logger -is -t "$UPSTART_JOB" ">>>>>>>> jsbin restart" # email the last 100 lines from the log tail -100 /var/log/upstart/jsbin.log | mail -s "ALARM: jsbin restart" jsbin@leftlogic.com end script script set -e # make sure you only write out to /var/log/upstart/<task> exec sudo -u www-data PORT=8000 /usr/local/bin/node /WWW/jsbin/ 2>&1 end script https://github.com/jsbin-org/production/blob/master/apps.jsbin.com/etc/init/jsbin.conf
  49. •URLs - probably not fixable •Database choice - fixable hard

    •Database adapter logic - fixable easy •Near total lack of tests - fix in progress Mistakes
  50. It's hard •Memory leaks •CPU loops •Easy to get lazy

  51. gdb ftw http://remysharp.com/2013/09/11/how-i-fixed-an-anonymous-infinite-loop-in-jsbin/

  52. Sustainability: Pro • Dropbox support & live syncing • Bin

    playback & annotation • Sass, SCSS, smart screenshots... • Branded JS Bin's ala http://emberjs.jsbin.com