Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Ember Island Life

Lindsey
December 09, 2015

Ember Island Life

Iteratively updating Kickstarter's frontend with Ember

Lindsey

December 09, 2015
Tweet

More Decks by Lindsey

Other Decks in Programming

Transcript

  1. Ember Island Life - this is a talk about iteratively

    updating the frontend of a Rails app by adding Ember.js - at Kickstarter, we have a ~7 year old rails app - it’s server rendered, with UI interactivity added via jquery - a lot of that jquery is fine, but it’s also untested, under maintained, full of IE hacks for browsers we don’t even support any more - one of our goals this past year was to modernize our front end development process, - deciding how to do this was a whole process which could be a talk unto itself - I’m happy to talk about it in person, email, etc - we ended up deciding to use Ember, but one of our biggest question marks was how Ember “scaled down” - ember is for building ambitious web applications, and it prefers to own the whole page - we had plenty of areas where we wanted to enhance an existing page or add small new client side sections of the site, but rewriting kickstarter.com entirely in Ember was prohibitive - this talk is an overview of the process we ended up going through, and are still going through, which will hopefully provide some guidance if you want to go down the same route of integrate Rails and Ember
  2. Geography Using Ember to create islands of richness - the

    overly strained metaphor of this talk is based on the key library we used, Ember Islands by Mitch Lloyd - the name refers to the concept of “islands of richness”, which I believe was coined in a talk in 2012 by a fella by the name of Todd H. Gardner - basically, it’s about adding client side interactivity via small pockets of JavaScript - the ember islands library was a perfect way to scale ember down, so we didn’t need to rewrite entire pages from the start - we could leverage everything that Ember is good for - binding in templates, wonderful testing, ES6 support, etc - but we could move in small incremental steps
  3. Undersea volcanos Building a framework for the framework - before

    we could start building our islands of ember, we had to lay some groundwork - islands need groundwork to support them - literally - you could even say that an undersea volcano creates the framework for a physical island
  4. Ember on Rails - ember-rails? - No ember-cli :( -

    ember-cli-rails + ember-cli-rails-addon? - Lots of integration features - Works well for Continents... - … less so for Islands and Archipelagos (I think!) - We had problems with development environments - Roll your own? - if you’re starting down this path today you might Google “ember rails” and see where that gets you - something called “ember-rails” might sound like a great starting point, but it has a major shortcoming: it’s not based on Ember CLI - Ember CLI is Embers build tool, which integrates building, testing, and installation of Ember addons - quite a bit of the value of Ember is through that last one, addons, so not having first class support for sharing code immediately gave us pause - future ember features such as engines will also be centered around ember cli, so we knew it was a requirement - how about “ember-cli-rails”? - we looked at this at the start of our process, and while we didn’t end up using it, it’s come a long way - also has a companion Ember CLI addon that integrates the stuff like rails’ CSRF tokens - more geared around having a single Ember app, less so for enhancement of existing pages with islands of ember - we also had problems with builds not happening reliably with our development environment, which uses “pow” - a requirement of ember-cli-rails is a single process development
  5. - server, so your milage may vary - since we

    couldn’t use it, we used it for inspiration - this is what we did: we took concepts from ember-cli-rails and used them to roll our own integration - we also got lucky in that our rails build and deployment system was easily able to accommodate embers build process - the details of that integration are specific enough to kickstarter that I won’t spend time talking about it here, but do come to me if you want more information - there were a couple of things that tripped us up, however
  6. Getting Ember ready - Output manifest.json in production environment fingerprint:

    { generateRailsManifest: true } - Only include jQuery, moment.js, Underscore, etc, when testing if (EmberApp.env() !== 'test') { vendorFiles['jquery.js'] = false; } app.import({ test: 'bower_components/underscore/underscore.js' }); - a couple of issues also became apparent during the integration process - ember cli has its own production build pipeline, which fingerprints files - it prepends an MD5 hash to the filename, for cache busting - but, how do we know what those fingerprints are when we include the files in rails? - well, ember cli can be configured to generate manifest files, which map a file to the filename plus fingerprint - this is in fact the same method that rails’ asset pipeline uses - next up, a conundrum: ember requires jquery, and by default packages it up in its vendor files, but we already use jquery on kickstarter.com - solution: only include jquery in test builds - this lets us keep it included for testing, which is an isolated ember environment without the existing rails dependencies, without duplicating it in development or production - we do something similar for libraries used in both Ember and rails, such as moment.js and underscore - ember cli has the ability to “import” bower dependencies into your ember build - it can be configured to do so only in certain environments - this is all configured in ember-cli’s build file
  7. Islands - so we’ve finally got the ability to include

    ember on a page, let’s start using it - our theme of iterative enhancement starts out with small sections of content and behaviour - the “islands of richness” ember components - the ember-islands addon allows you to insert components into specific places in a non-Ember page - what exactly is a component in this context? - self contained templates and behaviour - we use similar concepts every day - an HTML input could be thought of as a component - you give it an initial value, it renders it in a native text box, allows a user to edit the value, and allows us to hook into its lifecycle with events - that one HTML tag belies more complicated goings on when rendered - scale that thought up and you can begin to model more complex workflows as self contained components - in ember you create components that have an initial representation of some data, respond to user interactions, and emit change as actions or events - the trick is finding parts of your app that can be isolated and extracted into components
  8. Our first island - this is the first Ember Island

    we deployed at Kickstarter - it’s in the middle of the project dashboard you can access when running a kickstarter project - it replaced a rails rendered form that used jquery to create the client side interactions - you type in your google analytics code, you hit submit - just some client side validation, and an Ajax call - the button text changes depending on whether there’s a tracking code - it’s very simple, but there was enough complexity that we could see an immediate improvement over the rails and jquery version that it replaced
  9. Rendering our first island <div data-component="google-analytics-tracker" data-attrs="<%= { analytics_id: 'UA-12341234-12',

    analytics_endpoint: '/projects/my-project/analytics' }.to_json %>"></div> - this is what rendering that island might look like from your rails app - you specify what component you want to render via the data-component attribute - ember-islands is pragmatic and allows you to pass in data from your existing server rendered page to the component when it’s created - at the beginning - and even today - we need to “import” existing data from your application into the components - for example in this particular component we needed to know what the existing analytics code was, and also the URL the ajax call would make the request to - we can specify this data as a json payload, and ember islands makes it available as properties in the component when it’s rendered - we very specifically started simple - this helps us validate that the whole process, from writing the code, to testing the code, to deploying the code, worked - it also gets people used to the new workflows that come with an ember app, such as having to run a build tool
  10. Archipelagos Groups of islands of richness - in short order

    we were looking at rendering multiple components on a page - at the same time, we started wanting to share data and behaviour between them - whether a user is logged in, ways of doing analytics on clicks, strings for internationalisation, etc - some of that data and behaviour was already defined in our rails app - we already had an analytics library, an internationalisation library - thankfully using ember islands didn’t preclude us from using embers building blocks for shared data and behaviour, helpers and services, to create interfaces between ember and the existing code
  11. Shims {{t "projects.creator_analytics_edit.Enter_your_analytics_tracking_id"}} this.get('formHelperService').wrapForRailsForm('analytics', { analytics_id: this.get('newAnalyticsId') }); - Translation

    helper - Rails form service - services are long-lived objects that can share data and behaviour across our archipelago of components in a consistent way - helpers are a way of extending the functionality of handlebars templates - we quickly developed a set of shims around our existing client side libraries - for example, we created an internationalisation helper that hooked into our existing i18n system - this allowed us to use the existing translation strings as we migrated parts of our app to ember - we also created a service for interacting with rails forms via ajax - as we migrated the UI we didn’t necessarily have the bandwidth to migrate on the server side, so we needed a way of submitting ajax calls to the rails app, and interpreting the response - this snippet is a method that we use to take a javascript object and make it look like an HTML form submitted payload - the key, we found, was to create boundaries between the existing kickstarter app, and our new ember code - one major benefit of this is that we can easily shim existing code like translations when testing the ember app, even though the full translation environment might not be available - we’ve found it great that, even though at this stage we didn’t have what you’d consider a “real” ember app, we were still creating building blocks we could
  12. - use when we did - as it was, building

    a real ember app was the next step in our process
  13. Continents - one of Embers real strengths is its super

    solid client side routing and we pretty quickly wanted to leverage it - we expanded upon the concept of an ember island, but instead of a rendering a single, or set, of components in a server rendered page, we rendered the entire ember application - an ember continent, you could say - the trick to this was getting ember and rails’ routing to cooperate
  14. Routes - Rails route - Ember’s route get /help/resources(/*glob)' =>

    :index this.route('resources', {path: '/help/resources'}, function() { this.route('category', {path: '/:category'}); }); - it’s a pretty straightforward trick, but it can be hard to wrap your head around - in rails you define a “globbing” route, that points to the same action no matter what the URL globbed segment of the URL is - the syntax is effectively saying “disregard everything after slash help slash resources and always use the same controller action” - all the action has to do is render our ember continent - now embers routing can take over - it notices that the URL matches one of its defined routes, defined here as the path “/help/resources” even if a part of that URL wasn’t actually rendered by ember - we also have a dynamic segment, defined here as “category”, which allows us to change what we’re displaying on the page and keep the URL in sync - even if you copy and paste a URL with a category in it Rails will always serve the ember app because of the globbing route
  15. Routes - here’s an ember continent in action - you

    can see in the URL bar that the URL updates as we click through each category - these transitions are being handled by ember - if you copy and pasted one of those URLs, rails would see that you wanted the first part of the url, /help/resources, and serve up the ember application - ember would then see the category when it booted, and immediately transition to the correct template
  16. Pangea - pangea was the name of the supercontinent that

    existed before plate tectonics broke it up into the recognizable world map of today - we may end up with a reversal of this process, with more and more ember continents coming together until we have one giant app - I might give a talk about it if it happens
  17. - https://github.com/mitchlloyd/ember-islands - The library - https://github.com/yapplabs/ember-wormhole - An alternative?

    - https://www.youtube.com/watch?v=b-LZjy5QS7Q - A talk by Ember contributor Godfrey Chan, which hints that parts of the Ember Islands concept may one day be built in to Ember. - https://www.youtube.com/watch?v=GB8pgxoBEBg - Another version of this talk, focusing on the nuts and bolts of refactoring out your first component. - https://twitter.com/praxxis - Me! Further resources - finally, a couple of resources for if you go through these slides on the web afterwards - firstly, the ember islands library itself - ember wormhole is a potential alternative library for rendering components in arbitrary locations, Luke might be able to talk more about it - a talk by Godfrey Chan which hints that parts of ember islands might be built in to ember core one day - a talk that focuses on the nuts and bolts refactor of the that first component - finally, me on twitter if you want to get in touch if you have any more questions about what we’ve been doing with Ember at Kickstarter