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

Intro to Ember & Ember CLI

Intro to Ember & Ember CLI

From the April 2015 EmberATX meetup in Austin, TX.

6fd16b1b6a307ca583526e2ec4dab52d?s=128

tehviking

April 24, 2015
Tweet

Transcript

  1. w e l c o m e t o t

    h e n e x t l e v e l
  2. Ember CLI: UP AND RUNNING! The stuff you need to

    build next-level native web apps
  3. Brandon Hays @tehviking This one guy The Frontside

  4. Welcome to training

  5. WHAT WE’LL COVER: ¶ Ember CLI basics ¶ Building an

    app with CLI ¶ Migrating to Ember-CLI
  6. Prerequisites ¶ git ¶ node ¶ admin access

  7. WHY ember? It’s our favorite framework, sure. But why?

  8. Ember lets me focus on our unique business problems, not

    boilerplate code i just wanna code!
  9. Let the community tackle shared problems.

  10. I don’t want to spend my limited time on earth

    shaving yaks. WHY ember?
  11. how devs see their custom build pipeline

  12. their actual custom build pipeline

  13. Let’s see, we have a community, a shared problem, and

    Ember philosophy... so what do we do?
  14. An opinionated suite of command line tools for building Ember

    apps. Enter ember cli.
  15. I get to code, not shave yaks. WHY ember cli?

    >
  16. “You should begin moving your app to Ember CLI as

    soon as possible.” - Tom Dale, Javascript Ombudsman WHY ember cli?
  17. So let’s get up to speed. And get back to

    what we like: making stuff.
  18. PART 1: CLI BASICS

  19. the pleasure º Generators º Fast builds º Add-on ecosystem

    º Testing integration º ES6, Sass support
  20. THE PAIN ‡ Learning ES6 modules ‡ Cryptic error messages

    like “cannot find file tmp/3n8glcv7cv6sgs ‡ Migrating existing apps to Ember-CLI
  21. THE PAIN ‡ Migrating existing apps to Ember-CLI

  22. basic concepts - Installing - Generating - Using ES6 modules

    - Folder structure - Assets - Testing - Deployment
  23. Installing npm install -g ember-cli ember new cool-app

  24. GENERATORS & BLUEPRINTS

  25. LMGTFY ember generate route images ember generate component pixelate-image and

    my favorite... ember generate acceptance-test images (...let me generate that for you)
  26. Ember GENERATORS Controller Model Route Resource Template Mixin Component Helper

    Initializer Adapter Serializer Service Transform Util View
  27. Ember GENERATORS Acceptance-test* Adapter-test Component-test Controller-test Helper-test Initializer-test Mixin-test Model-test

    Route-test Serializer-test Service-test Transform-test Util-test View-test *(All but this are generated automatically)
  28. Ember GENERATORS Addon In-repo-addon (& lib) App Blueprint Http-mock Http-proxy

    Server Test-helper Plus custom generators from installed addons ...Or create your own
  29. ES6 Modules: getting out of dependency hell

  30. game over, globals!

  31. App.ImagesRoute = Ember.Route.extend({
 model: function() {
 return App.imageData();
 }
 });

    app/routes/images-route.js From globals...
  32. App.ImagesRoute = Ember.Route.extend({
 model: function() {
 return App.imageData();
 }
 });

    app/routes/images-route.js From globals... Ember is global imageData comes from global App (at least, we hope)
  33. import Ember from 'ember';
 import imageData from '../utils/image-data';
 
 var

    ImagesRoute = Ember.Route.extend({
 model: function() {
 return imageData();
 }
 }); export default ImagesRoute; app/routes/images.js TO ES6 Modules
  34. import Ember from 'ember';
 import imageData from '../utils/image-data';
 
 var

    ImagesRoute = Ember.Route.extend({
 model: function() {
 return imageData();
 }
 }); export default ImagesRoute; app/routes/images.js to ES6 Modules Ember comes from ember.js
  35. import Ember from 'ember';
 import imageData from '../utils/image-data';
 
 var

    ImagesRoute = Ember.Route.extend({
 model: function() {
 return imageData();
 }
 }); export default ImagesRoute; app/routes/images.js to ES6 Modules imageData comes from ../utils
  36. import Ember from 'ember';
 import imageData from '../utils/image-data';
 
 var

    ImagesRoute = Ember.Route.extend({
 model: function() {
 return imageData();
 }
 }); export default ImagesRoute; app/routes/images.js to ES6 Modules export so others can import
  37. Opinionated framework, opinionated structure Folder structure

  38. app/routes/images.js app/routes/images/show.js app/controllers/images.js app/controllers/images/show.js app/templates/images.hbs app/templates/images/show.hbs old-school folders

  39. app/images/route.js app/images/controller.js app/images/template.hbs app/images/show/route.js app/images/show/controller.js app/images/show/template.hbs New-school Pods

  40. ember generate resource foo --pod and if you want, in

    your env: podModulePrefix: 'pixelfy-me/pods' Maybe you’ll like it
  41. Asset compilation Where did your files go?

  42. None
  43. - assets/pixelfy-me.js (app) - assets/vendor.js (vendored js) Asset compilation

  44. app.import("vendor/my-stuff/cool-utility.js"); app.import("bower_components/pixelate/pixelate.js");
 app.import("bower_components/JavaScript-MD5/js/md5.js");
 Brocfile.js VENDORING ASSETS

  45. TESTING

  46. TESTING Awesome test helpers Awesome test generators QUnit & Mocha

    support
  47. Deployment

  48. Build & ship to S3/CloudFront Heroku Buildpack Existing asset pipeline

    Deployment
  49. The smartest DevOps engineer is our collective community ember cli

    ends the build tool yak shave
  50. EMBER ROUTER & NESTED ROUTES

  51. DATA, UI, STATE, URLs, IN PERFECT HARMONY

  52. ApplicationRoute (generated): ‘/’ ProductRoute: ‘/:id’ Rendered into products {{outlet}} URL:

    / products / 230 ProductsRoute: ‘/products’ Rendered into application {{outlet}}
  53. ACTION HANDLING ProductController {{action “add”}} ProductRoute ProductsRoute ApplicationRoute

  54. EMBER COMPONENTS

  55. <cc-input number={{cardNumber}} class=“cc-number {{isValid}}“> EMBER COMPONENTS OF THE NEAR FUTURE

  56. <x-select value={{bob}} action=“selectPerson”> {{each people as |person|}} <x-option value={{person}}>{{person.name}}</x-option> {{/each}}

    </x-select> EMBER COMPONENTS OF THE NEAR FUTURE
  57. COMPUTED PROPERTIES & COMPUTED MACROS

  58. COMPUTED PROPERTIES app/controllers/cart.js export default Ember.Controller.extend({
 cartItemSubtotals: Ember.computed.mapBy("model.cartItems", "subtotal"),
 orderSubtotal:

    Ember.computed.sum("cartItemSubtotals"),
 shippingCost: Ember.computed(function() {
 return 0;
 }),
 orderTax: Ember.computed("orderSubtotal", function() {
 var taxCents = (this.get("orderSubtotal") * 100) * 0.0825;
 return taxCents / 100;
 }),
 orderTotal: Ember.computed("orderTax", "orderSubtotal", function() {
 return this.get("orderSubtotal") + this.get("orderTax");
 }),
 });
  59. COMPUTED MACROS app/controllers/cart.js export default Ember.Controller.extend({
 cartItemSubtotals: Ember.computed.mapBy("model.cartItems", "subtotal"),
 orderSubtotal:

    Ember.computed.sum("cartItemSubtotals"),
 shippingCost: Ember.computed(function() {
 return 0;
 }),
 orderTax: Ember.computed("orderSubtotal", function() {
 var taxCents = (this.get("orderSubtotal") * 100) * 0.0825;
 return taxCents / 100;
 }),
 orderTotal: Ember.computed("orderTax", "orderSubtotal", function() {
 return this.get("orderSubtotal") + this.get("orderTax");
 }),
 });
  60. IF YOU UNDERSTAND: • Generating with Ember CLI • Router

    & Routes • Components • Computed Properties YOU CAN BUILD AWESOME STUFF
  61. Ember CLI lets me focus on our unique business problems,

    not janky build systems i just wanna code!
  62. so let’s code.

  63. Questions & break

  64. Let’s build an app! Pixelfy Me

  65. look out, batman! it’s the pixeler! Shut up, Robin! Worst.

    Villain. Ever.
  66. Let’s build an app!

  67. Let’s build an app! npm install -g ember-cli

  68. Let’s build an app! ember new pixelfy-me cd pixelfy-me git

    remote add origin https://github.com/thefrontside/pixelfy-me.git git fetch --tags open the folder in your text editor of choice
  69. Task 1: List Images What we’ll do: Generate Images resource

    Write Model hook for Images Route Install helper for image data Display images on Images page
  70. git checkout task-1 npm install bower install (Stuck? You can

    git checkout at any task with git checkout task-<task number>) Task 1: List Images
  71. Generate Images resource ember generate resource images (NOTE: don’t overwrite

    that hbs file!)
  72. import Ember from 'ember';
 
 export default Ember.Object.extend({
 url: ""


    });
 app/models/image.js “downgrade” model
  73. import Ember from 'ember';
 
 export default Ember.Route.extend({
 model: function()

    {
 return imageData();
 }
 });
 
 app/routes/images.js Load data in model hook KABOOOOOM! (doesn’t exist)
  74. kinda magic custom addon ember install cowboyd/ember-cli-sample-image-data

  75. import Ember from 'ember'; import imageData from 'ember-cli-sample-image-data';
 
 export

    default Ember.Route.extend({
 model: function() {
 return imageData();
 }
 });
 
 app/routes/images.js import it in the route
  76. ... "8": {
 id: "8",
 url: "/img/yeezus.jpg"
 }
 };
 if(arguments.length)

    {
 return Image.create(images[id]);
 } else {
 var imagesArray = Object.keys(images).map(function(k){
 return Image.create(images[k]);
 });
 return imagesArray;
 }
 inside the addon’s hidden volcano lair... P.S. it’s not really that magical
  77. check it out ember server check localhost:4200

  78. need to fast forward? git reset --hard task-2

  79. Let’s talk about what just happened: - Generated a route

    & model - Tweaked the route & model slightly - Installed an addon - Used ES6 to include the addon helper That loads images!
  80. task 2: show image What we’ll do: Generate images/show route

    Add dynamic segment to show route Write Model hook for Images Show Route Link to Image from Images page Display image on Image Show section
  81. Generate Images show route ember generate route images/show (again, don’t

    overwrite that hbs file!)
  82. Router.map(function() {
 this.resource('images', function() {
 this.route('show', {path: ":id"});
 });
 });


    app/router.js Add dynamic segment
  83. import Ember from 'ember';
 import imageData from 'ember-cli-sample-image-data';
 
 export

    default Ember.Route.extend({
 model: function(params) {
 return imageData(params.id);
 }
 }); app/routes/images/show.js Add model hook & import statement
  84. {{#each image in model}}
 <li>
 {{#link-to "images.show" image}}
 <img class="gallery-image"

    src={{image.url}}>
 {{/link-to}}
 </li>
 {{/each}}
 app/templates/images.hbs link to image from images template
  85. <div class="row">
 <div class="col-md-12">
 <img src={{model.url}}>
 <!-- Insert the pixelate-image

    component, bind src to model.url, bind value to pixelatePercentage -->
 ! Implement pixelate-image here !
 </div>
 </div>
 app/templates/images/show.hbs Display image in the show template
  86. To recap what we just built: - Generated a nested

    route with / - Used a dynamic segment - Re-used ES6 for our imageData helper - Edited template files to display stuff images/show done!
  87. task 3: pixelatE What we’ll do: Install pixelate-image component Wrap

    image in pixelate component Install {{emberx-slider}} component Drop in {{x-slider}} component
  88. install pixelate component addon ember install cowboyd/ember-cli-pixelate-image

  89. need to fast forward? git reset --hard task-3

  90. install x-slider component addon ember install emberx-slider

  91. <div class="row">
 <div class="col-md-12">
 {{pixelate-image src=model.url value=pixelatePercentage}}
 </div>
 </div>
 app/templates/images/show.hbs

    Drop in pixelate-image component
  92. <div class="col-md-9 slider-controls">
 {{x-slider value=pixelatePercentage}}
 </div>
 app/templates/images/show.hbs Drop in emberx-slider

    component
  93. what? that worked?! Did we mention Ember Addons are pretty

    great?
  94. Let’s look at what we did: - Installed pixelate-image custom

    addon - Installed emberx-slider addon - Tied the two together to make MAGIC So yeah
  95. task 4: Style it What we’ll do: Install ember-cli-sass addon

    Install bootstrap-sass bower package rename app.css to app.scss include bootstrap include custom SCSS
  96. install sass addon ember install ember-cli-sass

  97. install bootstrap-sass bower install --save-dev bootstrap-sass

  98. rename app.css mv app/styles/app.css app/styles/app.scss

  99. COPY & PASTE CSS FILES Files are here (grab the

    tar file): http://bit.ly/cli-training-styles - app.scss - _bootswatch.scss - bootstrap_imports.scss - bootstrap_variables.scss Copy or move them to app/styles
  100. need to fast forward? git reset --hard task-5

  101. Now we have a fully styled app! - Installed ember-cli-sass

    to compile Sass - Installed bootstrap-sass - Used Sass @include for granular control so stylin’
  102. task 5: test it Add karma, karma-cil, karma-mocha, karma-chai- plugins,

    karma-chrome-launcher, karma-ember- preprocessor, karma-mocha, karma-phantomjs- launcher, karma-junit-reporter to package.json Compile and install PhantomJS npm install Install ember-mocha-adapter and chai-jquery via Bower Set up a karma.conf file In your karma.conf: Customize your frameworks section in karma.conf to include mocha, chai, sinon-chai, and chai-jquery Set up a Grunt task to build your Sass on each test run Include your vendor dependencies in karma.conf Include your code in files section Debug file load order issues Add & configure handlebars karma preprocessor Then, create test-helper.js & include it in karma.conf In your test-helper.js: Configure chai and mocha defaults Set Ember.testing to true Set App.setupForTesting to true Call App.injectTestHelpers() Set up app on each test run Tear down app after each test run Ensure beforeEach and afterEach use the run loop Use the .done() callback for async beforeEach What we’ll do:
  103. task 5: test it j/k lol ;) ember generate acceptance-test

    images ember test
  104. ha! ha! ha! But seriously, this was real http://bit.ly/karma-sad-lol

  105. task 5: test it What we’ll do: Generate “images” acceptance

    test Remove generated Ember Data test Write an assertion Run the tests
  106. generate the test ember generate acceptance-test images

  107. remove ember data test rm tests/unit/models/image-test.js (We’re not using Ember

    data)
  108. test('visiting /images', function(assert) {
 visit('/images');
 
 andThen(function() {
 assert.equal(Ember.$(".spec-gallery-image").length, 8);


    });
 });
 tests/acceptance/images-test.js basic acceptance test
  109. run tests $ ember test --serve 1..14 # tests 14

    # pass 14 # fail 0 # ok
  110. WE DID IT!

  111. look at all the yaks i have to shave

  112. None
  113. bonus: gravatars What we’ll do: git checkout bonus-stage Set up

    gravatar route & link Handle download action install JavaScript-md5 bower component Pixelate images in the gravatar template
  114. set up gravatar route ember generate route gravatar

  115. downloadImage: function() {
 var link = document.createElement("a");
 var uri =

    Ember.$("img.pixelated-image").attr("src");
 link.download = "pixelfy.png";
 link.href = uri;
 link.click();
 }
 app/routes/gravatar.js handle download image
  116. {{#link-to "gravatar" tagName="li"}}
 {{#link-to "gravatar"}}
 Gravatar
 {{/link-to}}
 {{/link-to}}
 app/templates/application.hbs Link

    to gravatar route
  117. Install Md5 package bower install --save-dev JavaScript-MD5

  118. var app = new EmberApp();
 
 app.import("bower_components/JavaScript-MD5/js/md5.js");
 
 module.exports =

    app.toTree();
 Brocfile.js import md5 in brocfile
  119. window", "-Promise", "md5" ], "browser": true, ...
 Brocfile.js add md5

    to .jshintrc
  120. <p class="gravatar-preview"><strong>Preview:</strong></p>
 <img class="gravatar-preview-image" src={{gravatarUrl}}>
 app/templates/gravatar.hbs Add gravatar to template

  121. <div class="row pixelizer-controls">
 <div class="col-md-9 slider-controls">
 {{x-slider value=pixelatePercentage}}
 </div>
 app/templates/gravatar.hbs

    Add slider to template
  122. <div class="row">
 <div class="col-md-12">
 {{pixelate-image src=base64Url value=pixelatePercentage}}
 </div>
 </div>
 app/templates/gravatar.hbs

    Add pixelate to template
  123. This was more complicated. - Set up gravatar route -

    Handled download action - Installed bower component - Included lib in Brocfile and .jshintrc - Mixed pixelate and gravatar together It’s done!
  124. Now we can get back to focusing on moving fast

    and shipping, with a better set of tools i just wanna code!
  125. @tehviking THANKS! The Frontside

  126. always remember!