EmberConf 2021 Notes

Here is a highlighted overview of the major points from some of my favorite EmberConf 2021 talks: Conference Opening Keynote, Part 1 – Yehuda Katz 2011 Ember: A framework for 1️⃣0️⃣ years 🐹 How did we do? Started – before Ember 1.0, Ember Rails Today – Ember 3.25, Octane, Native Classes, TypeScript Early Ember users: Heroku, Intercom, Square, LinkedIn, Tilde Embers approach to change is the reason why these early adopter apps are using modern Ember today Breaking changes are BAD – it disrupts the ecosystem and kills momentum Progress and stability are two sides of a coin “For me, shipping is the thing” -Jamie Zawinski Release cycle? 🛳️ Trunk-based development, feature flags, overlapping releases, experiments on canary, automation Iterate everything on master master is always ready to ship No deadlines, no code freezes, just ship Evolution strategy Brand new features? Release channels Idiom transitions? Ember CLI Future proofing? Declarative Disruptions are disruptive whether we cause it or not 🚅 Ride the train: Upgrading Ember upgrades your build tools, deprecations are an important migration tool When faced with a choice between today’s popular solution and an equally expressive declarative solution, pick the declarative solution. Removal rules? Features may only be deprecated if a replacement is already available and enabled RFC Process New APIs that would require a feature flag need RFCs Removing an API that already landed on stable needs an RFC RFC must be merged before its feature flag can be enabled React to the future? 1-way data flow Virtual DOM DOM is the bottleneck Progress is important, but so is ending the constant cycle of writing and rewriting that plagues so many applications Slow and steady improvement Community momentum People underestimate non-contributors in their communities → Quest Issues The more you commit to writing instructions, the better it works Glimmer 2: drop in replacement in Ember 2.10 (complete rewrite behind a feature flag) 😲 We’re instead going to lean on small primitives and compatibility as our main mantra for how we do new feature design Coherence? Editions Collection of recommended features Staging Opening Keynote, Part 2 – Godfrey Chan Improvements 🎉 {{page-title}} RouterService#refresh() ember new --lang Prettier @ember/* ES Modules Better Error Messages <LinkTo> works in integration tests Modernized built-in components Better component inspector New lint rules and fixes Unbundled ember-source Deprecations 👋 {{attrs.*}} tryInvoke Ember Global getWithDefault Classic Edition optional features <LinkTo> positional arguments {{#with}} Legacy classNameBindings template syntax Ember.String utilities Implicit this property lookup hasBlock and hasBlockParams magic variables Old Browser support policy Octane → Polaris (Next Edition) ✨ Embroider Named Blocks <MyComponent> <:block>...</:block> </MyComponent> {{#if (has-block "thing")}} {{yield "one" "two" "three" to="thing"}} {{else}} Default content {{/if}} {{! ... }} <:thing as |first second third|> First: {{first}} Second: {{second}} third: {{third}} <:thing> {{#my-component}} Hello! {{else}} Bye! {{/my-component}} {{! Converts to this under the hood }} <MyComponent> <:default>Hello!</:default> <:else>Bye!</:else> </MyComponent> Value Semantics: Contextual components, Helpers, Modifiers and more <MyComponent @component={{component "some-component"}} /> <MyComponent @modifier={{modifier "some-modifier"}} /> {{! NEW! }} <MyComponent @helper={{helper "some-helper"}} /> {{! NEW! }} {{! ... }} <f.Component @foo="bar" /> <div {{f.modifier foo="bar"}}> ...</div> {{! NEW! }} {{#if (f.helper foo="bar")}}...{{/if}} {{! NEW! }} import Component from '@glimmer/component'; import { SomeComponent, someModifier, someHelper } from 'some-addon'; export default class MyComponent extends Component { SomeComponent = SomeComponent; someModifier = someModifier; someHelper = someHelper; } <this.SomeComponent @foo="bar" /> <div {{this.someModifier foo="bar"}}> ...</div> {{#if (this.someHelper foo="bar")}}...{{/if}} New Primitives {{#in-element}} Destroyables Auto-Tracking Memoization invokeHelper Strict Mode Templates New Test Waiters Helper Manager Tracked Storage Process Updates RFC Stages Deprecation Staging New Browser Support Policy Codemods TypeScript Strike Team Polyfills Accessibility Working Group Tooling HTML-First Apps are the Future – Jen Weber HTML is the key to building apps for devices you have not seen or can not imagine Web authors in the 90s didn’t imagine their websites would be viewed on your phone Core Accessibility API Mappings When everything is a <div>, you miss out on some of the most powerful programming tools in history What does it mean to put HTML first? 🤔 Write valid, semantic HTML by default Follow HTML-like patterns in non-HTML Emphasize readability of templates over DRY-ness Test for mistakes Ember’s evolution {{outlet}} → {{page-title "About"}}{{outlet}} {{input type="text" value=firstName}} → <label>First Name <Input @type="text" @value={{this.firstName}} /></label> ember-template-lint to the rescue {{! no-nested-interactive: https://github.com/ember-template-lint/ember-template-lint/blob/v3.2.0/docs/rule/no-nested-interactive.md }} <div {{on "click" @someClick}} class="my-button"> Click here </div> Custom date picker → Native date picker I don’t now everything about what users need, even right now Our technological future must be creative, inclusive, and empathetic HTML First Demos Building a Pinterest Clone – Jordan Hawker Masonry layout Existing solutions? Library 2,500 LOC unminified and last update was nearly 3 years ago 😞 Lightweight solutions? The Masonry Holy Grail™ Dynamic number of columns No unused space Fully responsive Efficient reflow Pinterest uses explicit CSS transform Noticeable delays during content reflow Must recalculate the position of every element in the grid Computationally heavy, JS is slow compared to HTML/CSS Enter CSS Grid Fully responsive content reflow Highly configurable Great performance Doesn’t support masonry (…yet) Ember Photo Gallery {{! index.hbs }} <MasonryGrid @columns="auto" @columnWidth="210px" @columnGap="10px" @rowGap="5px" as |grid| > {{#each @model as |photo|}} <grid.Item @async={{true}} as |item|> <UnsplashPhoto @photo={{photo}} @onLoadImage={{item.onLoaded}}/> </grid.Item> {{/each}} </MasonryGrid> {{! components/masonry-grid.hbs }} <div class="masonry-grid" {{masonry-columns columns=@columns columnWidth=@columnWidth columnGap=@columnGap }} > {{yield (hash Item=(component 'masonry-item' rowGap=@rowGap))}} </div> import Modifier from 'ember-modifier'; export default class MasonryColumnsModifier extends Modifier { resizeObserver; constructor() { super(...arguments); this.resizeObserver = new ResizeObserver(() => { this.organizeGridColumns(); }); } get columns() { let { columns } = this.args.named; let columnGap = parseFloat(this.args.named.columnGap); let columnWidth = parseFloat(this.args.named.columnWidth); if (columns === 'auto') { return Math.floor( (this.gridWidth + columnGap) / (columnWidth + columnGap) ); } return parseFloat(columns); } } .masonry-grid { display: grid; box-sizing: border-box; grid-auto-rows: 1px; justify-content: center; } ember-resize-observer Keep It Local – Chris Krycho What “reasoning about your code” really means /* Instead of declaring all the variables at the top, declare your variables where they will be used This forces you to think about scope and makes refactors easy */ function doSomething(anArg) { let i, total = 0, max, min; // 😢 max = getMax(anArg); min = max < 100 ? 0 : 100; for (i = min; i < max; i++) { total += i; } } // Converts to... function doSomething(anArg) { let max = getMax(anArg); let min = max < 100 ? 0 : 100; let total = 0; for (let i = min; i < max; i++) { total += i; } } // And now refactor is very easy! function doSomething(anArg) { let max = getMax(anArg); let min = max < 100 ? 0 : 100; let total = getTotal(min, max); } function getTotal(min, max) { let total = 0; for (let i = min; i < max; i++) { total += i; } return total; } Rust: Two fundamental rules 1️⃣ Data has one owner 2️⃣ No shared mutable data ​​infinite read access OR exactly one write access Pure functional programming Purity: when a function only has access to its arguments no global state no global functions (console.log) cannot mutate values not its arguments not other state (no access!) Benefits: consistent results: same input → same output no mutating arguments or global state “referential transparency”: ability to substitute the results for evaluating a function for the function itself 2 + 5 = 7 Reasoning about your code? → Local Reasoning! → Shrink the radius of thought! SOLID Single Responsibility Principle Open-Closed Principle Liskov Substitution Principle Interface Segregation Principle Dependency Inversion Principle Types? describe(user: User) has reasoning about a whole class 😓 describe(person: { name: string, age: number }) has reasoning about structured data 🤗 class User { constructor( name: string, age: number, email: string, state: State, ) {} } function describe(user: User): string { return `${user.name} is ${user.age} years old`; } // Converts to... function describe(person: { name: string; age: number }): string { return `${person.name} is ${person.age} years old`; } Reactivity? Observable-based systems (consumer-driven): computed(), get()/set(), Two way binding observer(), didReceiveAttrs() Arbitrary further pushes Autotracking (owner-managed): @tracked root state One way data flow No observers No arbitrary reactivity No arbitrary pushes Observable-based systems 😓 → reasoning about reactivity → Autotracking 🤗 Learning Ember in 2021 – Lenora Porter Algebra Teacher → Product Designer → Developer The mindset of a beginner 👨‍💻 Try → Fail → Learn → Repeat Your mindset can make or break your learning journey Stopping your limiting beliefs Moving from failure to failure without losing your enthusiasm 💪 10,000 hours to master a skill 40 hours x 52 weeks/year = 2,080 hours/year 10,0000 hours / 2,080 hours/year = ~5 years Learning style? Creating your first curriculum Plan 30 days Where do I want to level up? Mon - Fri: Tutorials & Learning at 5am one hour a day; Weekend: Break Ember Core Concepts: Models/Routing/Services/Components/etc Weekly Study Plan Mentors, Coaches, and Community What did you do during moments of defeat? Try → Fail → Learn → Repeat! Join the community, say Hello and build out your curriculum If you are an Ember community leader, reach out to encourage newcomers when you can. Cultivate an inclusive environment Building a Realtime App with Firebase and Ember M3 – Chris Garrett What problem is M3 trying to solve? 🤔 Thousands of models + nested fragments Solution: Generated models No more issues keeping things in sync Still shipping thousands of generated models and fragments to the clients M3: Mega Morphic Model ember-m3 Blob of JSON Understands relationships Deduplicates IDs Configured via M3 schema to work with any API Pros: Handles complex nested models, works well with strong APIs, less maintenance required to keep frontend and backend in sync, better performance with many models Cons: Frontend no longer has model definitions, can’t work with bespoke APIs, relationships are sync (No promise API for loading a belongsTo or hasMany – you need to make sure that data is loaded ahead of time) Firebase is a backend as a service DB is Firestore Data is not represented as tables, it is represented as JSON objects Pros: Can represent complex data models pretty easily, no need for 10 tables and 20 joins, application development more fluid Cons: Limited query capabilities, no concept of relationships Firestore ↔ M3 No more models, but you can type your models with an interface models/meal-plan.d.ts instead import Recipe from './recipe'; interface Meal { name: string; recipe: Recipe; servings: number; } interface Day { meals: Meal[]; } interface MealPlan { name: string; days: Day[] } export default MealPlan; firestore-m3 Please Wait… Oh it didn’t work! – Tobias Bieniek Best practices class HttpError extends Error { constructor(response) { let message = `HTTP request failed with: ${response.status} ${response.statusText}`; super(message); this.status = response.status; } } function isServerError(error) { return error instanceof HttpError && error.status >= 500; } function isNetworkError(error) { return error instanceof TypeError; } class LikeButton extends Component { @task *likeTask() { try { let response = yield fetch('/like', { method: 'POST' }); if (!response.ok) { throw new HttpError(response); } } catch (error) { this.notifications.error('whoops...that did not work!'); if (!isNetworkError(error) && !isServerError(error)) { Sentry.captureException(error); } } } } Helpful test utilities function setupFetchRestore(hooks) { let oldFetch; hooks.beforeEach(function() { oldFetch = window.fetch; }); hooks.afterEach(function() { window.fetch = oldFetch; }); } module('Component | LikeButton', function(hooks) { setupRenderingTest(hooks); setupMirage(hooks); setupFetchRestore(hooks); //... test('network error', function() { window.fetch = async function() { throw new TypeError( 'NetworkError: when attempting to fetch resource.' ) } await render(hbs`<LikeButton/>`); await click('button'); await waitFor('button[disabled]'); assert.dom('[data-test-notification-message="error"]') .hasText('whoops...that did not work!'); }); }); Use defer() to avoid race conditions and slow tests test('loading state', function() { let deferred = defer(); this.server.post('/like', deferred.promise); await render(hbs`<LikeButton/>`); click('button'); await waitFor('button[disabled]'); assert.dom('button') .isDisabled() .hasText('Please wait...'); deferred.resolve({ likes: 5 }); await settled(); assert.dom('button') .isEnabled() .hasText('Like'); }); Use a notification system Use an error reporting service Throw HttpError for HTTP error responses Only send unexpected errors to your error reporting service Ending the Plague of Memory Leaks – Steve Szczecina The Heap: a finite chunk of memory dedicated to a browser tab Memory allocation: Every object is automatically stored in the heap as your program runs Heap Snapshot Tool 🔧 Garbage Collection: Used by the JS engine to free up memory by removing objects from the heap once they no longer referred Memory Allocation Timeline 🪛 GC Root: Object in the heap that is not reachable from a GC root will be garbage collected (window/global object, DOM Tree) Memory Leak: Occurs when an unused object remains in the heap and is never garbage collected As the heap grows, GC will take longer to execute and will execute more frequently. Also, if the problem is bad enough, the heap can actually run out of memory completely. Long user sessions? Lots of time for memory issues to compound high priority + no reproduction = disaster memory-leak-examples run test → open dev tools → take a heap snapshot → search the heap snapshot → change some code → rinse → repeat Ember’s declarative template system lets us completely ignore a whole class of problems Ember’s {{on}} modifier automatically takes care of this as well <button {{on "click" this.doStuff}}> Hi! </button> {{! ... }} <div {{doDOMStuff}}> {{! ... }} </div> Destroyables: A toolset of new APIs in Ember for managing lifecycle and teardown. Available since v3.22 Common leaks: event callbacks that are never cleaned up storing state in module scope putting non-primitives on object prototypes async functions that never complete unintended closures babel transpilation of let/const ember-cli-memory-leak-detector ✨ Closing Keynote – Edward Faulkner The fastest build tool is no build tool ❌ Ember was one of the very first projects committing strongly to utilize a build tool Next? 🔮 How far can we push minimizing the server? <!-- No web server ---> <script type="importmap"> { "imports": { "lodash-es": "https://cdn.skypack.dev/lodash-es@^4" } } </script> <script type="module"> import { capitalize } from 'lodash-es'; </script> Aghhh, but now we need a web server again <!-- Needs a web server ---> <script type="module" src="./app.js"></script> But what about incorporating a build tool? Hmmmmmmm… <script src="./please-understand-typescript.js"></script> <script type="module" src="./app.ts"></script> Service worker to the rescue. Its actually an excellent place for DevTools Persists across page reloads Nothing is going to get stuff into the browser than the browser’s own cache How to we bring this to Ember apps now? Embroider Ember App → Embroider Compat (compiler) → “Vanilla” (the spec) → Webpack → The Web // Follow web standards export default setComponentTemplate( precompileTemplate("<YourTemplateHere/>"), class extends Component { // your component JS here } ); Webpack ↔ Snowpack Ship with a great out of the box experience, but it should be possible for the community to experiment Mho: Experimental service-worker based javascript build tool 🤯 Written in Rust Serves files Serves a manifest of all files with versioning mho client: Waits for the service worker and reload the page Browser does all the work of discovering the files importmap.json: basically a translation of yarn.lock Embroider is the Ember community’s bridge into the future of Web build tools Fun Fast Tools for Serious Work Bonusconf AMA with @rwjblue – Robert Jackson Best ways to solve state complexities when converting a classic app to octane? TODO, linting, introducing new best practices for new features Status of major ecosystem projects like Fastboot, Embroider and Engines? Fastboot: team resurgence as of recently (past 3-4 months), Rehydration opt-in → default behavior, head on over to the Discord #fastboot channel weekly meeting Embroider: redo of the build pipeline which backs Ember apps, addons testing against Embroider by default, Open PRs against Ember CLI to make Embroider the default Engines: Build-time/run-time isolation and bundling of individual assets and on-disk separation by having a logic root path for a subtree. Embroider should help eliminate some of the dependency on Engines (route subpath to lazily load/individually mount engines) Will more focus be given to applications using Windows? Embroider master branch has all known Windows-related bug fixes which will land soon Are there plans to go beyond Fastboot to a more integrated framework? There’s most likely a future state where Fastboot is integrated into the default Ember CLI blueprint What are some things, current or future, where Ember has analyzed other frameworks and decided to either integrate or stay away from certain ideas? Integrating: import statements and leveraging standard JS packaging and bundling Staying away: Imperative render functions Both sides: React Hooks — instead opting integrating directly we can leverage some of the lower level primitives Which initiatives and ideas have you most excited about the future of Ember and our community? Spend lots of time working on the micro level but when I get a chance to look up at a high level it would be Embroider and template language improvements (modifiers/side-effects/etc) Strategy to prevent burnout? Helpful engineering manager who understands, stepping back very slightly to let others take on tasks What do you think would increase the adoption of Ember? We all need to be more comfortable with regards to our increase in productivity and be more vocal 🗣️ about it. People who put their heads down and just get their work done are unfortunately more often the ones who will shy away from speaking out about the exciting happenings in the Ember community. Marketing. How do you see Ember fitting into the larger Frontend landscape? Not doing our own special and bespoke things. Leveraging more of the work going in the greater JS community. ember-cli-deprecation-workflow and ember-try are some things that do not really exist outside of Ember and they are concepts and code that we can offer to the greater ecosystem, for example. What would you say to people who haven’t tried Ember yet or haven’t tried Ember lately? “Don’t pick the tech, solve your problem.” Ember has iteratively changed and improved significantly since pre-octane days Continuous Accessibility – Melanie Sumner Accessibility primer: Inclusive websites so people with disabilities can use what we create Accessibility === A11y Web Content Accessibility Guidelines CD (Continuous Delivery) → CI (Continuous Integration) → CA (Continuous Accessibility) ember-template-lint release v3.0.0 delivers template linting in such a way to ensure our code has a path to accessibility by default Audit reports and automation reported issues 1️⃣ Automation Lighthouse Microsoft Accessibility insights ember-a11y-testing axe-core ember-template-lint TODO: instead of simply having WARNING and ERROR, TODO is time-based New rule released -> Existing code -> Create TODOs and plan to fix ember-template-lint . --update-todo ember-template-lint . --include-todo ember-template-lint . --fix 2️⃣ Audits 3️⃣ User Reports Metrics Meaningful, Controllable, Actionable “When a measure becomes a target, it ceases to be a good measure” -Goodhart’s Law Potential violation count: WCAG, Location legal standards, Failures identified by audit findings A11y Automation Tracker Total bug count, Bug severity count, Time to fix, Violation frequency Trend analysis 📈 Lint ALL The Things – Bryan Mishkin Linter: Rule-based static code analysis tool Catching a real bug with linting export default class MyComponent extends Component { // Missing a `return` statement get isAllCompleted() { return this.milestones.every((milestone) => { milestone.completed; } } } Enforce and educate about best practices ✨ export default Component.extend({ tagName: 'li' }) Tighten security {{{post.body}}} Tools eslint eslint-plugin-ember: Octane by default as of v10.0.0 eslint-plugin-node eslint-plugin-qunit ember-template-lint prettier typescript-eslint Writing your own lint rule is very approachable: Implement a simplified ember/no-get this.get('myProperty') → this.myProperty AST Explorer Write tests — allowed: [], disallowed: [] Write your rule CallExpression(node) { if (isViolation) { report(node, 'use ES5 getter' ); } } IDE highlighting and auto-fixing linting violations Handling Images on the Web – Marco Otte-Witte Simple: <img src="/images/my-image.jpg"> More complex: <picture>, <source>, <svg> Decisions we make around images have real impacts on the end-user’s experience 1️⃣ Images as essential UI Icons, status indicators Many but small Dynamic Must be present immediately (don’t lazy load) ❗ Image URLs in CSS: A slight rendering delay background-image: url('/images/contacts.png'); Base64 in CSS: CSS is a render-blocking resource; doing this bloats the CSS file size. background-image: url('data:image/png:...'); Icon font: Bad for A11y, screen reader interprets as text 🚀 SVG: Embed the SVG inline in the DOM and the icon is rendered instantly. Stylable and dynamic. However, JS is parser blocking; Many inline SVGs may bloat DOM and cause delay. ember-asset-sizes-action: diffs the asset sizes of the master branch and the PR branch SVG is generally best, just remember to avoid disproportionately growing your JS bundle with many inline SVGs 2️⃣ Static images Photos, illustrations Few but big Non-essential No adaption to application state Lazy load Asynchronously decode image off the main thread Show placeholder which displays immediately Explicitly code image dimensions to prevent layout shift <img src="/images/landing.jpg" loading="lazy" sizes="(max-width: 608px) 100vw, 1280px" srcset="/landing-608.jpg 608w, /landing-1280.png 1280w" decoding="async" style="background-size: cover; background-image: url('data:image/base64;...')" width="1280" height="400" > PNG, JPEG, WebP (combines lossless + lossy encoding and transparency) <!-- Fallback mechanism --> <picture> <source srcset="landing.webp" type="image/webp"> <img src="landing.jpg"> </picture> Real world example: PNG 201KB → WebP 25KB ember-responsive-image 3️⃣ Images as data Loaded as part of dynamic data from an API Discovered at runtime Similar to static images otherwise One option: API response should include additional image information in order to apply all the optimizations from above <!-- Fallback mechanism --> <picture> <source srcset={{@post.picture.url.small}} type="image/webp" media="(max-width: 608px)"> <source srcset={{@post.picture.url.large}} type="image/webp" ...> <img src="landing.jpg"> </picture> Another option: Preload the image in the Routes model hook (If the image is more critical to the application) async model() { let posts = await this.store.findAll('post'); await Promise.all(posts.map(p) => preloadImage(p.picture)); return posts; } function preloadImage(src) { // ... } Technical Interviews Don’t Have to Suck – Kaitlin Jones-Muth Be kind to people 😁 Plan ahead Consistent questions from interview to interview What does your team need? Once you figure out what you want, how do you evaluate that? Adjust as you go You want the candidate to be at ease (and to leave feeling good) Be conversational and welcoming Talk about what to expect and what not to expect Coach candidates “Let’s say we want to add an interactive table to our page. What are some things we can do to make that table accessible?” Stuck or less experienced candidate? Be more specific: “What about someone who is visually impaired but isn’t using a screen reader?” Pivot to a different skill: “How would you approach a designer or stakeholder about making the page more accessible?” Very experienced candidate? Make the problem more complex: “What if the columns need to be resizable?” Candidate is missing important details? Ask directly: “What things would we want to use ARIA for, and when would we want to use semantic HTML instead?” Ask about personal experience: “Have you had to deal with this before? What problems did you run into?” Give useful feedback Technical interviews are actually behavioral interviews: How we arrive at the answer is generally more important than the answer itself. Introducing Template Imports – Chris Garrett Currently: Ember resolves template values using file system matching In the future you will import explicitly using JS syntax 🌟 Better developer experience, integration with editors and tooling More flexible file layout Simplifies internals, better performance Initial Ideas --- import MyComponent from './my-component' --- <script> import MyComponent from './my-component' </script> Instead of pushing a final API immediately. We’ll use Low level APIs first to develop the best available final API ✨ precompileTemplate() ember-template-imports Using <template> tags and .gjs files Defining values in the same file 💯 // hello.gjs import { helper } from '@ember/component/helper'; import moment from 'moment'; const Greeting = <template> Hello, {{@name}}! </template> const currentTime = helper(() => { return moment().format('h:mm:ss a'); }); <template> <Greeting @name={{@name}}/>! It is currently {{currentTime}}. </template> Using template literals with hbs Assign the final template to the static template class property // components/hello.js import Component from '@glimmer/component'; import { hbs } from 'ember-template-imports'; export default class Hello extends Component { name = 'world'; static template = hbs` <span>Hello, {{this.name}}!</span> `; } Birds-eye Vue of Ember – Gonçalo Morais If you know Vue, you know Ember as well Core concepts Command Line Interfaces Vue CLI Ember CLI Single file components Vue: by default Ember: Can enable using ember-template-imports Passing data into a component Vue: props Ember: arguments Component state and reactivity Vue: watch Ember: @tracked Native events Vue: <button v-on:click="count++"> Ember: {{on "click" this.handleClick}} Directives (Vue)/Modifiers (Ember) Vue: Directives Ember: Modifiers Slots (Vue)/Named Blocks (Ember) Global state Vue: Vuex for stores → provide/inject in Vue 3 Ember: Services and ember-data Routing Vue: Vue router Ember: router.js and <LinkTo @route="about"> Testing Vue: Loose official guidance Ember: Ships with tests and generators out of the box Animations and Transitions Vue: Applies CSS classes .slide-fade-enter-active Ember: Not built-in with Ember but ember-css-transitions or ember-animated Building Forms Mobile Users Will Love – James Steinbach Use semantic markup Foundation: Input that renders correctly on every device <label> Username <input type="text" /> </label> Ember unique-id helper RFC {{#let (unique-id) as |usernameId|}} <label for={{usernameId}}>Username</label> <input id={{usernameId}} type="text" /> {{/let}} Attributes type: Semantically identifies the type of input content autocomplete: Tells browsers what user data to offer as autocomplete options inputmode: Suggests the ideal on-screen keyboard for mobile devices Integrate password managers for a username field <input type="text" autocomplete="username" autocorrect="off" autocapitalize="none" spellcheck="false" /> Addresses <input type="text" autocomplete="street-address" /> Numbers <input type="text" inputmode="decimal" pattern="[0-9]*" /> Verification code <input type="text" inputmode="decimal" autocomplete="one-time-code" /> Dates <fieldset> <legend>Start Date</legend> <label for="month">Month (MM)</label> <input id="month" type="text" inputmode="decimal" /> <label for="day">Day (DD)</label> <input id="day" type="text" inputmode="decimal" /> <label for="year">Year (YYYY)</label> <input id="year" type="text" inputmode="decimal" /> </fieldset> CSS / Design 📍 Prevent iOS zoom with minimum font-size of 16px Use a single column layout Resources 👇 Input Builder inputmode Tester Mobile-friendly input CodePen examples

March 30, 2021 · 20 min

EmberConf 2020 Notes

Here is a highlighted overview of the major points from some of my favorite EmberConf 2020 talks: DAY 1 Opening Keynote – Yehuda Katz, Jen Weber, Godfrey Chan First ever all-virtual EmberConf 💻 ⚡ 🎉 There’s more to software than the number of lines of code you write Value sustainability Innovating on Community 🤝 👪 Ember 1.13 had a large number of deprecations Technically followed SemVer, but created lots of chaos…😰 SemVer doesn’t tell the whole story of ecosystem stability RFC Process (Started 2014 📅) Driven by the community Aid the core team with many perspectives Collect constraints Build relationships Provide structure for implementation Record history and rationale RFC: Slack → Discord 🌟 RFC: Website Redesign ✨ But where’s the Tomster? - Drives conversation and solutions Core teams → Diverse leadership Together™ 2017: Ember framework began to feel like it was falling behind Surviving the Framework Hype Cycle by Brandon Hays 📺 Settlers and Pioneers Shipping features as low-level primitives and let the pioneers finalize the APIs Stable 🧱 Give pioneers the tools and leave the settlers alone visit() API → Fastboot Component Manager → @glimmer/component Modifier Manager → ember-modifier But when do settlers adopt? 2019: Ember Editions Collection of features …and the settlers keep on working Ember Octane Fresh look for a new user 🎊 1️⃣ HTML-First Framework Core of Ember is HTML and CSS No special Ember-specific tweaks…Just copy paste ✂️ Components can simply be a natural extension of HTML → Driven by HTML and Templates Template only components (Improved performance, no this in template) 🏎️ 2️⃣ Integrating JavaScript Old: Managing DOM 😭 👎 → New: Managing Data 😆 👍 JS file co-located next to your existing Template Native JS syntax and idioms this.args get shareURL() { //... } → {{this.shareURL}} (JustWorks™ in the template) Autotracking: Auto-updates the getter if any passed-in this.args properties used in shareURL change @tracked properties Even works on Native JS classes 3️⃣ Working with the DOM Element modifiers <button {{on "click" this.toggleSize}}></button> {{#if this.isLarge}} Large code... {{else}} Small code... {{/if}} import Component from '@glimmer/component'; import { tracked } from '@glimmer/tracking'; export default class MyComponent extends Component { @tracked isLarge = true; @action toggleSize() { this.isLarge = !this.isLarge; } } Powerful, intuitive <input {{autofocus}} /> export default class AutofocusModifier extends Modifier { didInstall() { this.element.focus(); } } ember-ref-modifier Syntax and mental model overhaul Shipped Dec 2019 Don’t have to rewrite apps to begin using features Linting out of the box Updated defaults when generating apps Zero config builds Refreshed guides Create a new app → ember new Paste in HTML and CSS → application.hbs Fast deploy → Netlify Incrementalism Backwards compatibility Interoperability between new and old paradigms Codemods Ember 2019-2020 Roadmap RFC Invest in Octane Modernize build system Better accessibility by default Share Octane outside our community Building Ember Together 🤝 ember-inspector - Octane certified 🥇 Ember Twiddle - Octane certified 🥇 FastFlood: The Story of a Massive Memory Leak in FastBoot Land – Sergio Arbeo Fastboot: Render Ember apps on the server Memory leak: piece of data which should have been garbage collected ♻️ But Why❓ A reference is being kept somewhere Chrome Developer tools 🛠️ Object memory graph - All objects in memory 📊 Distance - Distance from GC root Shallow size - Size of the object itself Retained size - Size we would free if we freed the object reference Heap profile - Capture memory state at a point in time Three snapshot technique to find the problem areas 1️⃣ Warmup the application - Create baseline objects 2️⃣ First snapshot Now, do the suspected memory leak action 3️⃣ Second snapshot Now, repeat the action 4️⃣ Third snapshot Timeline tool Step 0: Reproduce locally on a production-ish build (no uglification) Step 1: Find the leak 🔎 Run the server with debugging enabled Make one request Start timeline Make a few requests Inspect class LeakDetect { constructor() { Object.assign(this, attrs); } } Step 2: Find the dominator (retainer we need to remove so the leak is gone) 🔎 Container: used to instantiate and cache objects, associated with a Registry Look for Owner leaking (public API of the Container) Problem: export default Adapter.extend({ headers: computed(function() { return { Authorization: `Bearer ${something.here}`; } }) }) Fix: export default Adapter.extend({ get headers() { return { Authorization: `Bearer ${something.here}`; } } }) Octane: A Paradigm shift in EmberJS – Suchita Doshi The Journey of Ember 🏃‍♀️ Ember 1.x Convention over configuration Built-in routing Ember Data View driven architecture Two way bindings 🔁 Attribute bindings Ember 2.x Component driven architecture Glimmer rendering engine adoption Better binding with properties Improved template scoping “Data Down, Actions Up” approach Roadmap for further improvements Ember 3.x Road to Octane Cleanup Remove IE9, IE10, PhantomJS and Bower Native Classes Angle Brackets Lots of documentation Evolution of Ember Edition: Shift in programming model due to new framework features ✨ Native Classes Increased performance Smooth learning curve More aligned with JS community Glimmer Components Simple, Ergonomic, Declarative 💪 Fewer lifecycle hooks and properties to learn Removed the implicit component wrapper Namespaced arguments Templating in Octane {{!-- Old --}} {{employee-details name=employeeName empId=employeeId addEmployee=(action "addEmployee")}} {{!-- New --}} <EmployeeDetails @name={{this.employeeName}} @empId={{@employeeId}} @addEmployee={{this.addEmployee}} /> Tracked Properties No more this.set() Reduce complexity Modifiers and Decorators ember-codemods Ember Atlas AST: the Secret Weapon to Transform a Codebase – Sophia Wang How do I bulk edit syntax at scale? Example: Wrap all requests with a global error handler But we have a problem… Hundreds of requests scattered around the codebase Update manually? 🤔😢 Tedious and time consuming Update with RegEx? 🤔😢 Too inefficient for so many unique changes Update with Codemods? 🤔😆 Understanding the grammar behind a language Apple === Noun 1️⃣ Tools 🛠️ ESLint Disallow unreachable code function foo() { let retVal = 1; return retVale; returnValue = 2; // <-- Unreachable code detected ts(7027) } Codemod: Bulk edit syntax Babel Transpiler: Write modern JS → Transpile → Run in any browser // Convert this [1, 2, 3].map((n) => n + 1); // To this [1, 2, 3].map(function(n) { return n + 1; }); 2️⃣ What is an Abstract Syntax Tree (AST)? 🌳 A Tree structure highlights the most important syntax of a language Tree: Nodes connected by Edges Heap Tree Parse Tree AST: Best parts of a Parse Tree (Structure) but only highlights the most important information Remove extraneous information, Simpler 3️⃣ How does syntax transformation work? Parsing Lexical analysis (Scanning/Tokenization) Syntax analysis - AST Explorer (Includes Glimmer parser ✨) Transformation Code Generation Taming the Beast: Managing a really ambitious codebase – Luke Deniston But this time I will build things the right way… The Beast === Complexity When we write code, we’re telling a story Audience: Developers, Computers Strategies for dealing with complexity Abstracting Subdividing (Systems → Subsystems) Codebase v1: Coffeescript, Rails, Ember 😑 Regressions with each upgrade Performance degradation Codebase v2: Shared addon and micro front ends 😑 Solved some issues but full page refreshes when navigating from app to app In-repo engines? Repo-mageddon Fix bug in shared addon → 5-6 different cascading pull requests Codebase v3: Mono repo - yarn workspaces with Ember Engines 🥳 Workspaces: 1 repo, many packages Packages can import each other { "private": true, "workspaces": ["packages/*"] } Pro tip: Make individual package folder with the same name as the package.json name field Engines: Mini application, built and booted by the host application Optional lazy loading Code isolation Routable engine Router.map(function() { this.mount('super-blog'); }) Routeless engine {{mount "super-blog"}} Tests: Use the correct resolver ember-engines/test-support/engine-resolver-for Sharing services Controversial Tips⁉️ Replace this with your real tests → Treat this as a bug! Use the last argument in tests .assert() to describe the test Use Prettier and ESLint Be careful with Addons (Actively maintained? File size bloat?) Use TypeScript Use Tailwind Lessons Learned from Changing Careers – Kara Luton Your past experiences make you the developer you are today 🥇 A non-traditional background is a feature, not a bug What did I want in a new career? Codecademy Get a CS degree, self teach or go to a bootcamp? The Iron Yard bootcamp Overwhelming amount of information about HTML, CSS, and JS Job rejections → Judged for not having experience 😩 Lessons learned along the way (Ballerina → Music Publicist → Developer) 👩‍🎓 Practice doesn’t make perfect, it makes progress 📈⬆️ Pay attention to the small details Accepting feedback and not taking it personally My writing skills → Code commenting! 💪 How to work well with others How to stand out amongst the crowd Interviewing skills Community is important 37.6% of developer who have a college degree did NOT major in Computer Science Look back on your own past experiences Ember as Song – James C. Davis How best to compare building an app with composing a song? Programming and Songwriting are very similar 🎶 ⌨️ Song: composed of sections Section: composed of instruments, notes, parts, measures, phrases Section → Route Instrument → Service Part → Component Notes → Contextual Components Other globals: tempo, master volume, playing state, where are we in the timeline Web Audio API: Powerful but low level. Provides primitives for making sounds Tone.js: Built on top of the Web Audio API. Provides primitives for making music Scale: string of notes, one after another Democratizing Frameworks Through Developer Experience – Sarah Yu Reach: Engineering apprenticeship program at LinkedIn ember-m3: alternative model implementation to DS.model What is developer experience (DX)? Things that make developers’ lives easier DX is often not prioritized 😞 Involves people 👩‍🦰👨‍🦰 Metrics can be hard to measure 📝 Much easier to just say you reduced the build size by n Bytes It’s a bug it that happens -Yehuda Katz When should you contribute to DX? Beginner: Getting started guides Intermediate: Advanced APIs Advanced: Self-documenting source code Where can you contribute? README.md Ember Learning Debugging tools Source code comments Why JS is Coming to Ember Templates – Matthew Beale “No more unification RFCs” 😨 <Welcome /> could live anywhere since resolvers are a runtime concern Local maximum → Global maximum Matt’s resolving Ember Microlib const template = [ [0, 'To you I say:'], [1, 'welcome'] ] setup(); render(template); rollup.js terser Dynamic resolution vs. static linking import { welcome } from './components' const template = [ [0, 'To you I say:'], [1, welcome] ] render(template); How can we bring the benefits of a statically linked system into Ember ❓ Handlebars Strict Mode 💪 What are the constraints in strict mode? No implicit this fallback No resolution. {{foo-bar}} is only ever a variable No dynamic resolution. {{component foo}} No partials Need a static solution for getting other components into template scope. createTemplateFactory({ "scope": () => [OtherComponent] }) Template imports You can import a default of named export into your template The right side of an import, the path, works just like it does in any system using Node.js resolution. Adopt ES Modules syntax module syntax into templates --- import Quote from './quote'; import { titleize} from '@ember/template-helpers'; import { animatedEach } from 'ember-animated/helpers'; --- {{#animatedEach @greetings as |myGreeting|}} To {{titleize this.subjectName}} I say: <Quote>{{myGreeting}}</Quote> {{/animatedEach}} Next steps: Get Handlebars Strict Mode into Final RFC and land the primitives Build an addon for template imports so we can experiment Start a design for what the ES module API is for built-ins like <LinkTo> or <Input> Performance + Payload size benefits Explicit templates Strict mode for templates RFC Solving Problems for African Soil – Ridhwana Khan Kasi Maths Why should you care? Outline of challenges Power/Electricity: Loadshedding and power outages (Rolling blackouts) 🔌 Plant breakdowns 🏭 Poor cellphone reception Basic digital literacy 💻 Reduced access to computers in public school and at home High data costs 💰 Low end smartphones Bandwidth speed First Paint (Is it happening?) → First Contentful Paint → First Meaningful Paint (Is it useful?) → Time to Interactive (Is it usable?) How can I help? 1️⃣ Reduce Bundle Size Minifying & concatenating JS Code splitting Tree shaking Measure Lighthouse ember-cli-bundle-analyzer Bundlephobia 2️⃣ Server/Static Rendering Fastboot and Prember 3️⃣ Service Workers Caching and offline ember-service-worker ember-pouch 4️⃣ Other Performance Tips Optimizing images Optimizing the JSON Adaptive loading Shift Left – Melanie Sumner Where did you start: Hobbyist? Computer Scientist degree? Coding Bootcamp? Self-taught? Change is the constant we can rely on 👈 Continuous learning is a must Assistive technology is not included is most curriculums Find your niche and grow Think beyond Enjoyable UX No vision Keyboard-only Low vision Accessibility settings High contrast mode What does a typical pattern look like? 🧩 Basic examples Variations Rendered code Copy & paste Too many DOM nodes can crash screen readers Patterns should also include anti-patterns ember-template-lint ember-a11y-testing It’s ok to not know everything. Lean on tooling Shift Left mindset: Intent matters Accessible interfaces can used the way they were intended to be used Don’t wait for the audit, move accessibility into the design workflow Elevate the quality of your code Technical Accessibility Issues for New Ember Apps RFC DAY 2 Autotracking: Reactivity and State in Modern Ember – Chris Garrett Reactivity: How apps update when things change Autotracking is a form of reactivity TodoMVC How do we let the template know to when to update? this.rerender() 😭 this.rerenderItem() 😭 Annotation overhead: All the extra thought that has to go into doing things the way the framework wants you to do them Grows combinatorially with the size of our application 😨😨 jQuery Reactivity can solve this by linearly increasing rate instead of exponentially increasing rate Declarative programming model for updating based on changes to state Declarative: “What, not how” ❗ HTML (Derived State) State: All the things that can change in your app Variables Properties User inputs Root State firstName = 'Liz'; Derived State get fullName() { return `${this.firstName} ${this.lastName}`; } Observable - RxJs Observable → Events → Transform → Subscriber (Push-based) Similar to classic Ember - set(), pushObject() allTodos = Observable.of([ { title: 'Code', completed: false }, { title: 'Plan EmberConf talk', completed: true } ]); Performance++ / Ergonomics– Virtual DOM - React “Where did the state change occur?” (Pull-based) Tree: Dirty → Rerender Class based components state = { allTodos: [ { title: 'Code', completed: false }, { title: 'Plan EmberConf talk', completed: true } ] } this.setState({ allTodos }); // Specifically communicates "What" to the framework Hooks let [allTodos, setTodos] = useState({ allTodos: [ { title: 'Code', completed: false }, { title: 'Plan EmberConf talk', completed: true } ] }); this.setState({ allTodos }); // Specifically communicates "What" to the framework Performance– useMemo / shouldComponentUpdate (manual optimization) → Scalability ⬇️ → Complexity ⬆️ Can we bend the curve? Performance++ and Annotation overhead– Autotracking: Use the JS state model (Pull-based) Focus on root state: Push to array, Add to object allTodos = new TrackedArray([ { title: 'Code', completed: false }, { title: 'Plan EmberConf talk', completed: true } ]); @tracked displaying = 'all'; Performance++ / Ergonomics++ Root State → Output Memoization: Return a previously computed value if nothing changed memoizedRender(...args) { if (deepEqual(lastArgs, args)) { return lastResult; } lastResult = render(...args); lastArgs = args; return lastResult; } Clock: state v0 → state v1 … → … state v15156; Did the clock increment? Update Tag: myClass.trackedProp ↔ state v15156 (last known clock when this was changed) Simple / Performant Dirty: Increment a number Validate: Array.map + Math.max Lazy (only checked on demand) Only need to annotate root state This is what bending the curve looks like What’s next? 🔮 Libraries, patterns, common abstractions - tracked-built-ins Tooling - Ember Inspector state timeline Extract to be used anywhere An Octane-Powered JAM Stack – Chris Manson JAM? JavaScript, APIs, Markup Fast sites delivered by prerendering files and serving from CDN (Serverless) Created by Netlify Evolution of some of the things we were already doing JAM Spectrum 🍓 Server-side Rendering 🏎️ Pre-rendering: Prember JAM Lifecycle: Serve HTML → Load JS Gatsby - $15M Funding 💰 VuePress Empress Stable 🧱 empress-blog - Shallow fork of Casper theme from Ghost Guidemaker - Powers EmberJS guides Field Guide - Ember website redesign Beta open-slide training-buddy Alpha rfc-process empress-blog Architecture Host App (Ember) ↔ empress-blog (Broccoli) + empress-blog-template (Handlebars/CSS) npm uninstall empress-blog-casper-template npm install empress-blog-attila-template A11y First and Everyone Wins – Ava Wroten Adding Functionality with Composable Components Equitable & Discoverable UX Automation Testing 15% of the world lives with some form on disability 🌍 Degrees of disabilities 🐕‍🦺 Limited mobility, Muscle slowness, Tremors, Low vision, Color blindness, Partial hearing loss W3C Pattern Rearrangable Listbox ember-sortable <SortableGroup> → <SortableGroupAccessible> (wrapper) <SortableItem> → <SortableItemAccessible> (wrapper) Splattributes <SortableGroupAccessible tabIndex="0" class="border focus:border-teal-400" /> <div ...attributes> {{yield}} </div> Modifiers <div {{key-up this.handleArrowUp key="ArrowUp"}}></div> @ember/test-helpers triggerEvent and triggerKeyEvent Test reordering and key events 🙌 test('it can listen for specific key up events', async function() { this.keyUp = ({ key }) => { assert.equal(key, 'Enter'); assert.step('key up'); } await render(hbs` <div {{key-up this.keyUp data-test-id="keyup"}}></div> `) let selector = '[data-test-id=keyup]'; await triggerKeyEvent(selector, 'keyup', 'Enter'); assert.verifySteps(['key up']); }); assert.dom(findAll('[data-test-id=item]')[0]).hasText('Item 1'); assert.dom(findAll('[data-test-id=item]')[1]).hasText('Item 2'); // Reorder await triggerEvent('[data-test-id=group]', 'focus'); await click('[data-test-id=sort-down]'); assert.dom(findAll('[data-test-id=item]')[0]).hasText('Item 2'); assert.dom(findAll('[data-test-id=item]')[1]).hasText('Item 1'); Quick feedback loop EmberQuest: Building an Octane Role Playing Game – Dan Monroe ember new emberquest 🎮 Hex tiles Pathfinding WebGL Canvas Web Audio ember-concurrency @task *reloadHealth() { // ... } Phaser 🕹️ ember-phaser ember install ember-phaser ember generate phaser-scene tomster ember generate service game ember generate component gameboard An Ember Dev’s Guide to CSS Grid – James Steinbach Grid: Responsive CSS-only layout method Column / Row / Gap control 🤝 Grid properties & values: grid-template-columns, grid-template-rows, fr, max-content, grid 😱😨 display: grid; grid-template-columns: 1fr 40em 20em 1fr; grid-template-areas: "header header header header" ". body sidebar . " "footer footer footer footer"; gap: 12px 16px; grid-template-columns: Set the proportions for tracks along the inline axis of the grid container 30% 150px 30%; grid-template-rows: Set the proportions for tracks along the block axis of the grid container 50px repeat(10, 100px); 🚨 Warning 🚨 Fixed heights cause overflow Better: auto, min-content, max-content Logical properties inline: start to end of a line of text in the block block: start to end of the block of text dir=rtl and writing-mode: vertical-lr support for free grid-template-areas: assign names to grid areas One rectangle, adjacent cells, strings (not integers) grid-template: assign rows, columns, and areas as a shorthand Every row ends with its height Every column ends with its width grid-template: "header header header header" auto ". body sidebar . " auto "footer footer footer footer" auto / 1fr 40em 20em 1fr; gap: Creates gaps between columns and rows Grid container values fr: 1 fraction of the grids free space Calculated after non-fr space is used Based on the total number of fr in the row or column repeat(<count>, <length>) repeat(12, 1fr) === 12 column Bootstrap grid-area: A grid-template-areas name from the parent Center an item display: grid; justify-content: center; align-items: center; Gotchas Images sizes: img obeys a the grid-cell size → object-fit: cover Animating grids: Some browsers animate, can’t animate between areas IE 11 😨 Stronger App Architecture Using Maps – Matt Gardner GIS (Geographic Information System) Mapping technology NYC Planning 📍 Changing expectation about how governments deliver digital services We use maps every day 🗺️ ZoLa Making data easy to consume Where can we build Housing? A brief history of maps John Snow: London Cholera outbreak map Florence Kelley: Income map by residential block Basemap: Static data, always present Data Layers: Polygons, Lines, Points Enter…The Tile: Avoid triggering a fullpage reload when navigating Dynamic interactions 🖱️ How are tiles made? Cylindrical map projection Assume that the world is a square 🟦 GeoJSON: Opinionated JSON format for storing spatial data Best for most use cases Leaflet ember-leaflet mapbox-gl-accessibility ember-mapbox-gl Test Stubs → Dependency Injection How to lie with maps 🤥 “Map users seldom, if ever, question these authorities, and they often fail to appreciate the map’s power as a tool of deliberate falsification or subtle propaganda.” Spatial correlation !== Meaningful data relationship The Power of Debugging – Samanta de Barros Challenges 1️⃣ Dev vs Prod Sources tab Breakpoints Pretty print formatting for minified JS 2️⃣ External Libraries Stack trace ⛔ Don’t be afraid to step in 🚶‍♀️ Addon vs NPM library code location 3️⃣ Not My Code Use the Ember Inspector Find the function location Talking to Your Dog with Ember – Robert Wagner wuf.plus 🐶 Web Audio API fftSize (Fast Fourier Transform) and frequencyBinCount getByteFrequencyData() getByteTimeDomainData() Determining dog bark types 🐕 ~1000-2000 Hz range and between ~80-90 dB (decibels) Finding db spikes Types: Alert, Greeting/Playful, Distress Deciphering audio data 🔊 @action async startRecording() { const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: false }); const options = { mimeType: 'audio/webm' }; this.mediaRecorder = new MediaRecorder(stream, options); this.mediaRecorder.addEventListener('dataavailable', e => { this.args.uploadAudioVideo({ blob: e.data }); }); this.mediaRecorder.start(); } Integration with Ember 🐹 ember-service-worker ember-web-app Future work Add more bark types Refine frequency ranges Add “Talk Back” feature The Moderate Programmer – Derek Gavey Moderate: Avoiding extremes of behavior The moderate programmer names things appropriately 3 words or less Avoid jargon and metaphors factory, object, class Use plurals where appropriate For booleans, prefix with is, has, can For functions, user a verb then noun The moderate programmer writes small functions Function does one thing Beware of flags in arguments Beware of too many arguments Components are functions too The moderate programmer writes tests Write your tests immediately (or you won’t write them) Integration tests are your best bet You have diminishing returns after n% code coverage The moderate programmer refactors RailsConf 2014 - All the Little Things -Sandy Metz “Duplication is far cheaper than the wrong abstraction” Write ugly code! Rule of 3 (abstract on your third duplication) Will future me/teammates understand this better? Weight the costs of the refactor The moderate programmer gives up Give up and ask for help Give up and take a break 🧘 Give up and throw out your code…it’s ok Why Contributing Seems Scary – Anne-Greeth van Herwijnen Contributing 🙋‍♂️ Everyone sees this differently Add / Remove code Setting up a meetup Code review Ideas Motivation → Social Norms → Community Motivation: Intrinsic / Extrinsic Social Norms: Ask ⁉️ ↔ Encouragement 😆 Community: Psychological sense of community → Commitment What can we learn? Thank every contributor 🤗🍻 Ask people to contribute where their strengths are Octane Octopus: The Multi-Faceted Migration – Jordan Hawker Why is the migration experience important? Past migration pains Stability Productivity Can continue building new Octane feature while you’re migrating Unlock new features quickly Reduce manual refactoring costs Minimize overhead of learning new patterns Many features are polyfilled and stable back to 3.8 Recommendations Phase 1: Upgrade to Ember 3.16 LTS Enable Octane features ember-cli-update Phase 2: Codemods ember-codemods Phase 3: Prepare for Glimmer ember-classic-decorator Remove classic Ember patterns Template-only components Phase 4: Adopt Glimmer Preliminary component refactors Empty tagName Migrate classNames, classNameBindings, attributeBindings {{on "click" (fn this.foo 'bar')}} event handlers Modifiers Finish Glimmer conversion computed() / this.set() → @tracked Convert lifecycle hooks Classic vs Octane Cheat Sheet Ember Atlas Recommended Migration Order

March 18, 2020 · 18 min

EmberConf 2019 Notes

Here is a highlighted overview of the major points from some of my favorite EmberConf 2019 talks: DAY 1 Opening Keynote – Yehuda Katz, Tom Dale Ember turns 8 years old in April 🎂 A Brief History of Ember from IE6 to ES2018 -Dr. Tomster 📖 Staying true to our values, not chasing trends Climb the mountain together 🏔 Shared tools that work when you’re starting out and scale up Shipping features is more important than tinkering with config files 🚢 Avoid having to stop and rewrite you application The Celery Test What decisions we make will communicate to the world what we really believe Before taking external advice, make decisions based on our values What we did ✅ Ember CLI, Templates, 6-week release cycle, RFC process, Code Mods, Engage with Standards, Community, Ember Addons What we did not do ❌ <script> tag, Web Components, Framework reboot, Ember Native Stability ↔ Progress (The tension between Stability and Progress) Aggressive Changes (Community Fragmenting 🙈) → Cautious Changes (Falling Behind 🙉) → Aggressive Changes (Community Fragmenting 🙈) Aggressive Changes: Ember 1.13 - DDAU, Many deprecations, Big foundational updates, Ecosystem churn Cautious Changes: Ember 2.x - Less notable features, more stabilization Ember 3.x - Find a balance between shipping things incrementally and keeping an eye towards coherence this.get('firstname'); this.set('firstname') → this.firstname; this.set('firstname') In 2.x this probably would not have shipped because of the asymmetric nature of the change {{user-avatar user=currentUser}} ⬇⬇⬇ <UserAvatar @user={{this.currentUser}} /> Unless you pay attention to every RFC and every PR how would you know when to adopt new features 🤷‍♀️ Where we are → (incremental changes) → Pit of Incoherence → (incremental changes) → Where we want to be Shipping relentlessly in the past year 🛳 Ember Editions 🔥 Bend of the curve of tradeoffs Points of maximum coherence Polished feature set Ember Octane 🚀🎉 Allocate a sprint to use the new features ❌ No jQuery required: Ember(128Kb) - jQuery(29Kb) 🤩 JS Classes Standard syntax and tooling integration Works with TypeScript Decorators and Class Fields Simply a syntax change: import { X } from Y will work the same in both Classic invocation and Modern invocation ⭐ Angle Bracket Invocation Disambiguate between Properties and Attributes Easier to scan visually ✨ Glimmer Components New modern and minimal base class Explicit 1-way bindings “Outer HTML” templates Explicit, immutable arguments 🌟 Tracked Properties New change tracking Fast, efficient updates “Just JavaScript” - No need for this.set() One Simple Rule 📌: “If you change a class field and want the DOM to update, make it tracked” Mutation is no longer a dangerous thing that you need to think about Migrate slowly, all underlying primitives seamlessly work together 📈 Use them anywhere, even with Native JS Classes import { tracked } from "@glimmer/tracking" export default class Person { @tracked firstName; @tracked birthYear; constructor(firstName, birthYear) { this.firstName = firstName; this.birthYear = birthYear; } randomizeAge() { this.birthYear = //... } } HTML → Template → DOM Output all share the same structure Ember Octane Preview available today! 📣🔥🚀 So…what’s coming next ⁉ New file system layout Template imports “Embroider” Next generation build pipeline for Ember apps Asset optimization Built on JS Modules Beta Ember Observer Ember app built with Webpack running in production Building a UI Styleguide in Ember – Frédéric Soumaré Why build your own Styleguide? Because you can… 😏 It has never been easier to build extensible clean layouts with CSS Flex Grid 4 Concepts: UI Elements → UI-Kit → UI StyleGuide → Design System Work on your app, start to realize a pattern of components being used on many pages Split your apps…now how do I use these components between both ❓ Ember Addons 🚀 ember addon my-ui-kit --yarn ember g component x-button Addon /app directory will merge with the namespace of the consumers /app directory Dev tips 🙌 cd <ui-kit-addon> yarn link cd <ember-app> yarn link my-ui-kit ember-cli-addon-docs Snippets, Live Demos, Docs ⭐ SASS color palette → JSON export my-ui-kit/index.js preprocessTree() hook ember-styleguide Designers ↔ Developers Your Desktop, the Studio – Kate Ruggeri Just completed one full year as a professional Ember Developer 🎊 How to become a better programmer (…or artist): 1️⃣ Practice 2️⃣ Critique 3️⃣ Reading Theory 4️⃣ Look at the Masters Looking is demystifying and be a powerful experience 🕵 How to steal? “Oh, I can do that too!” Masters are around you ❗ Learn to ask questions, developers love to share their secrets 🤝 Art studio is private, organized…Just like your office workspace Things can get overwhelming 😩 😓 You’re looking at a huge code base 🥵 You have lots of responsibilities and deadlines 😌 But…Your tools create a sense of control Junior Dev === Investment Carving time out on the clock to learn your tools Masters know and configure their tools 🛠 Pretty things are easier to understand git log vs. git log --pretty=format:%C(green)%h\ %C(yellow)[%ad]%Cred%d\ %Creset%s%Cblue\ [%cn] --decorate --date=relative Look outside of your field Surround yourself with things that inspire you “Keep it weird” “Have fun” Comparing Patterns in React and Ember – Preston Sego React needs decisions around tooling and patterns 😕 React is just components Simplicity of only having to work with 1 concept (sort of…) Ember comes with battle-tested abstractions ⚔ React vs Ember App creation React: Webpack React: npx create-react-app my-react-app No testing out of the box 😭 Errors have syntax highlighting 🤗 Components Presentational Contextual Container (Renderless) Higher-Order (React-only) State management Where does business logic go? Local state Context Provider/Consumer (React) Services manage the state in Ember React would need to create a state management system Redux Wrap nested providers around entire app, which leads to the Pyramid of Doom 😱 Data Down, Actions Up (React/Ember) Prop-drilling 😦 Concurrency Redux-Saga (React) ember-concurrency (Ember) Authentication ember-simple-auth 👍 Testing Stubbing context’s in React (unDRY, hacky) 🤢 Routing Ember: ember g route my-route does all of the heavy lifting React: Most people use React Router API / Remote Data Ember: Promise-aware model() lifecycle hooks React: No model hooks, useEffect(), no canonical way of fetching data APIs with Relational Data React: Custom fetch requests, Apollo GraphQL Query Params React: Easy to grab of the location object Ember: Big pain point right now ☠ ember-query-params-service hopes to address these issues Typed Ember: Strong Types for Better Apps – James C. Davis Open Science Framework - 100% TypeScript, 100% Open Source, 100% Ember ember-osf-web Why TypeScript? “Automatic” documentation with type annotations 🔥 Reduce run-time errors Helps with refactoring What’s a type? string, number, boolean A type is just a shape type Person = { name: string; height: number; birthday: Date; isMarried: boolean; } TypeScript is compiled to JavaScript Will not affect how JS works ember-cli-typescript Build-time type checking Break the build if you want when types do not check Sets up the basic type definitions you’ll need for Ember framework objects Blueprints Produce a nice syntax highlighted Type Error FAQs ❓ Do I have to convert everything at once? Nope! ✅ Where do I start? Models Services Shared Components What about addons? Precompile to JS so consuming apps don’t need to use TypeScript 🔁 Include type definition file as well Pain Points New syntax and new concepts to learn Type definitions for third-party addons @definitely-typed Type definitions for Ember and Ember Data Learn more at #e-typescript on the Ember Community Discord Crafting Web Comics with Ember – Jessica Jordan The Glasgow Looking Glass (1826) Japan: 12th / 13th century → Hokusai Sketches (1814) ⏩ 1990’s → Comics go to the Web Artists using the Web to share comics experiences 🎨 Nedroid @rubyetc What if I just use Ember? Anatomy of a comic Comic pages Defining pages as routes Comic panels Motion through sequence 🧠💭 Java Applets Flash Web Animations API Evergreen browsers + Polyfill let opts = { duration: 3000 }; let keyframeSet = [ { transform: 'translate(250px)' }, { transform: 'translate(0)' } ]; let keyframes = new KeyframeEffect(element, keyframeSet, opts); Steps timing function - easing: steps(5) this.animation.play() Why Ember? Clear separation of concerns Only load data where it should be loaded Composable Conventions Community ember-in-viewport Safety measures ⚠️ “Pokémon Shock” incident - Japan (1997) 😨 Photosensitive users Keyboard accessibility Anatomy of an Addon Ecosystem – Lisa Backer ember-service-worker Provides a framework for managing Service Worker code What is a Plugin? 🔌 Bundle that adds functionality to a host application through a well-defined architecture for extensibility An Addon is a Plugin Configuration (Start with Docs) Ember CLI hooks Ember Observer code search feature Time to dive into the code 🏊 ember-service-worker/index.js treeForVendor Broccoli Trees/Nodes Set of files that can be transformed by Plugins A build() function is called on each Plugin ⚒ package.json keyword naming convention to create a collections of ember-service-worker Plugins "keywords": [ "ember-addon", "ember-service-worker-plugin" ], Implement a plugin architecture? Babel Rollup Testing Not like testing a normal Ember application Testing the build of an application Unit tests for core functionality broccoli-test-helper Developing an Ember Test Strategy – Todd Jordan Ember 💕 Tests How do I prevent my tests from becoming a burden? Speed and feedback loops Deming Cycle 🔄 Plan → Execute → Analyze → Adjust Influenced Toyota (Continuous improvements, Tight feedback loops) Implementing Lean Software Development 📖 Boehm’s Law The later you find a missed requirement/bug, the more expensive it is The earlier you find and fix your bugs, the more successful your project will be Agile Manifesto 📜 Describe testing in an Agile environment How to distribute your tests? 🤷‍♀️ UI (🚶‍♀️💰💰💰💰💰) ↔ Service ↔ Unit (🏃‍♀️💰) Ember Application Test (33 min/1000 tests) ↔ Ember Rendering Test ↔ Ember Unit Tests (1.7 min/1000 tests) 40%/50%/10% Test type distribution for a sweet spot Push scenarios as far down the test pyramid as you can Avoid duplication between test types Don’t be afraid to delete tests that are not beneficial (Long running, etc) Test Workflow Test → Write code to make the test pass → Refactor Growing Object-Oriented Software, Guided by Tests 📖 Keep an eye on your feedback loops Test in a methodical way that drives Design Thought and discipline are faster than quickly cranking out code Don’t Break The Web – Melanie Sumner 1990s: Write code → Save file → FTP to server → Check in browser → Repeat Much easier now: ember new my-app; ember deploy production; 🤗 Web Accessibility analysis on the top million web pages 97.8% of websites had accessibility errors 😱 The presence of a JS Framework indicated a higher number of accessibility errors 85% - Low contrast 68% - Missing alt text 58% - Empty links 100% of these issues are preventable Are we focused on the right things? 😕 Too many excuses we tell ourselves for avoiding accessibility in our apps “But…Our clients didn’t ask for accessibility” You didn’t ask for sugar in your cookie 🍪 “But…Implementing accessibility is just too hard” “But…This just isn’t an Ember issue” ember-optional-features ember feature:disable application-template-wrapper <body> <header> <!-- --> </header> <main> <!-- --> </main> <footer> <!-- --> </footer> </body> Visibly support accessibility efforts DAY 2 Dealing with Data in 2019 – Igor Terzic Been working with Ember for entire professional life Working on Ember, Ember Data and Ember-related libraries for the past 8 years 2011: Java Swing app 😨 → CoffeeScript, GruntJS, Ember 😩 Made some bets that worked out really well and built trust 🤝 Programming Model: Separation of concerns Isolated the Model Layer with a schema // component model.save(); // template {{model.isSaving}} ember-cli-mirage - Now because you have a schema, mirage automatically knows how to configure your backend Isolated Serializer layer Fastboot - Easy inter-op Embracing the consistency JSON API - Minimal amount of configuration necessary to play nicely with Ember Identity Map Relationship consistency: belongsTo(), hasMany() A framework for ambitious web developers. 😑 2019 → 2025 Advanced data fetching, caching and mutating Dan Gebhardt: Give Apps Online Superpowers by Optimizing them for Offline Developer experience and visibility Productivity Tricks “Not doing work beats doing work in the fastest possible way, every time” Dynamic schema: ember-m3 → Ember Data core ❓ ember-data-storefront export default PostsRoute extends Route { async model() { await this.get('store').loadRecords('post'); return this.get('store').peekAll('post'); } } Goal: All Ember Data addons → No Private APIs The State of Community Documentation – Kenneth Larsen Documentation is generally the first encounter you’ll have with any Ember project We’re all responsible for documentation 👨‍👩‍👧‍👦 README.md Should serve a nice and concise introduction to your project Should not answer every single question 👎 Badges 👍 Generally too cluttered and filled with code examples 😢 Blueprint documentation needs some adjustment Extract out to CONTRIBUTING.md ✨ Github prompts doc changes Unhelpful phrasings “Simply run the tests. Just type npm test” “Just write your own compiler, then it simply works” Just, Simply, Simple, Actually, Easy, Easily, Obviously… 👎 Inconsiderate Writing ❌ Cultural differences are everywhere ember-cli-addon-docs to the rescue! 🦸‍♂️ Alex and ember-cli-alex: linter to help catch inconsiderate writing Communication and Convention – Julia Donaldson So…why Ember? But that learning curve though… 😩 Everything has a learning curve #realtalk Ember is not really about productivity Previously a Fashion Designer 👠 As a user, I should be able to move my arms and feet Creative solutions within a set of requirements (..just like Software) Fashion Designer → Code Bootcamp The “right” words Communication is a skill…a skill that can be learned Ideas 💡 The tools we choose, are simply vessels for our ideas Art and Fear by David Bayles 📖 To bring our ideas into the world, we need to be able to communicate them How do I communicate my thoughts in a way that is productive? Talking about code is hard Ember → Gives a vocabulary to frame my ideas 😃 Democratize the Language Communication 🔁 Confidence 🔁 Participation Web development is not about the individual anymore The tools we choose should connect us “Opens up someone elses React app…” 😲😱😵 Communication that scales Ember’s structure spawns creativity How do we define ambition? “Ambition is a dream with a V8 engine.” -Elvis Presley Ember is for Everyone – Kenigbolo Meya Stephen Code Afrique A group of software developers giving back to people under-represented in our industry People learn differently 💻 Theres no guaranteed way of ensuring people grasp the concepts Process: Variables → Object → Functions Don’t need to learn about traversing a binary tree Problems that come with teaching JavaScript Framework, Framework, Framework ❗ Typical pitfalls? Lazy loading Too many Computer Science concepts Seems to be a frontend framework designed for a backend developer Not just designed for beginners Ember Power 🦸‍♀️ Routers Templates Convention Simplify concept explanations 👨‍🏫 Explain to beginners without technical phrases Building Better Components – Dianne Eramo “The ratio of time spent reading vs writing is well over 10 to 1. […] Making it easy to read makes it easy to write” 📖✍ Keep Things Manageable 🌟 Single Responsibility Principle: Each component should be responsible for 1 concept Don’t Repeat Yourself Principle: Eliminate duplication Don’t prematurely abstract your code Ember Component Patterns 🔥 Reusable Component Pattern: DDAU, don’t mutate data the component doesn’t own Single Purpose Component Pattern Has a single clearly defined use case Context aware Pass in entire model as an argument Directly mutates data Reusable (Addons) ↔ Single Purpose (Forms) Provider (Renderless) Component Pattern Only concerned with how things work (load data) Does not render HTML or CSS <PercentageComplete @completed={{this.completed}} @total={{this.totalFields}} as |percent|> <ProgressBar @percentCompleted={{percent}} /> </PercentageComplete> Presentational Component Contextual Component Pattern Makes relationships between related components explicit Provides default behavior for consumers // components/templates/modal.hbs {{yield (hash header=(component "modal/header" closeModal=(action "closeModal")) body=(component "modal/body" style={{bodyStyles}}) footer=(component "modal/footer" closeModal=(action "closeModal")) )}} // templates/form.hbs <Modal @onClose={{onClose}} as |M|> <M.header @title="Edit User Application" /> <M.body> <EditUserForm @user={{provider.user}} @saveUser={{provider.saveUser}} /> </M.body> </Modal> Write the Component Interface 🔌 Expose the bare minimum that you know will be needed Every property provided is a feature that can break when you make changes Small component interface 👍 Manage UI state with declarative rendering Declare all component state inside the component file Never rely on the DOM for you state ⚠️ Ensure component re-renders whenever any of the state changes (Computed Properties, this.set()) Composable Concurrency Tasks – Isaac Ezer ember-concurrency Generators function* () A function which can yield intermediate values and pause/resume execution for...of loop Directed graph iteration with Generators: N x N adjacency matrix Browser support Ember Concurrency 🙌 Removes the need for manual state tracking and isDestroyed checks Simply yield intermediate promises Derived state myTask.lastSuccessful.value Maked “chained” promises cancelable by being able to abort task execution at each yield Higher Order Ember Concurrency Tasks “Wrapping ember concurrency tasks” ember-concurrency-test-waiter: Notify our test runner that a Task is in flight ember-concurrency-retryable: Task exponential backoff New to Ember: What ARE All These Things? – Jennifer Wong The ABC’s of Ember Rock & Roll with Ember.js A → A() B → {{#basic-dropdown}} C → ember-can Computed Property ember-changeset D → DS ember-decorators E → Ember: The Documentary F → ember-cli-flash G → Glimmer.js ✨ H → Helpers ember-composable-helpers ember-truth-helpers I → { inject as service } J → JSON API Adapter K → Ember.K L → {{link-to}} M → ember-cli-mirage (mut) N → Naming Conventions O → {{outlet}} P → ember-power-select Q → QUnit ember-qunit R → RSVP S → ember s T → task() U → Utils V → View W → ember-wormhole X → emberx-select Y → {{yield}} Z → Zoey EmberConf MiniTalks How to Grow or Save Your Favorite Open Source Project – Jen Weber All volunteers are selfish Few people act out of true altruism for very long The happiest volunteers get something in return Reciprocity Commitment & Consistency Always say “Thank You” to other volunteers How I Learned to Stop Worrying and Love the Mono Repo – Hassan Abdel-Rahman What is a Mono Repo? Single repository with multiple node modules Code cannot get out of sync with itself 🔁 Atomic changes across multiple modules Testing Issue management Yarn Workspace Single shared node_modules How to Mono? ember g addon for each in-repo addon Move boilerplate addons into packages/ directory Convert to use Yarn Workspaces { "private": true, "workspaces": ["workspace-a", "workspace-b"] } Ember Mono Repo example app Lerna for publishing From Mainframe to Mainstream: A Case Study in Emberification – Ryan Mark Rewrite a major Fortune 500 company’s core application including Testing and Deployment Mainframe terminals suck ember-cli-deploy, Spring, Jenkins #winning Productivity → Adoption → Success How to Build a Blog Engine in 15m With Ember and NodeJS – Chris Manson empress-blog Quick way to bootstrap a new Blog with Ember 🔥 How do I get setup? ember new super-blog cd super-blog ember install empress-blog empress-blog-casper-template What’s Behind Ember Observer’s Scores? – Katie Gengler Can you score based on accessibility? ❌😣 Can you score if addons are “Octane Ready” or not? ❌😣 Solution: Math ➗ Weighted Average Smarter checks, New checks and Partial scores Broccoli Update – Oli Griffiths Broccoli.js 🥦 In the beginning: ember-app-kit Grunt 😞 Why Broccoli? Simple API Flexible Broccoli 2.0 🥦✨ tmp/ directory moved outside of the project and more Update to 32% faster builds Just update to Ember CLI 3.5+ and you’ll see these updates Broccoli now supports ECMAScript modules syntax Adopting TypeScript No Bad Legos: A Toy Box For Everybody – Howie Bollinger Component Driven Development But what about accessibility? 🤷‍♂️ CEO, Stakeholders, Product Owner, QA, Designers, Developers, Customer Experience Everything is awesome, because you’re part of a team Accessibility is not just a checklist WCAG 2.1 AXE Accessibility Engine Chrome + AXE Extension “Why can’t this be automatic?” Are you there, Axe? It’s me, Ember. ember-a11y-testing What does this mean for developers and testing? assert.ok(find('img').getAttribute('alt'))' 😩 await a11yAudit('img'); 😍 Closing Keynote – Sarah Allen What does it mean to be heroic? 🦸‍♂️❓ We choose our heros Saved the project! Worked nights and weekend! Last minute fix!!! But what about the team that quietly ships without fuss? Reality is broken Change the rules Abstraction Mechanism which permits the expression of relevant details and the suppression of irrelevant details “I wanted to make it easy for people to write good programs” -Liskov Recognize when your abstraction is wrong Perception !== Reality We can’t assess things accurately without the passage of time 🕑 What we hold to be true is only our closest approximation at the moment What is relevant? Just-World Fallacy The general belief that the world is morally ordered, such that people generally get what they deserve Simply holding meritocracy as a value seems to promote discriminatory behavior Apophenia: Seeing patterns where they don’t actually exist Iterate. Celebrate. “Focus on something you can fix”

March 19, 2019 · 16 min

EmberConf 2018 Notes

Here is a highlighted overview of the major points from some of my favorite EmberConf 2018 talks: DAY 1 Opening Keynote – Yehuda Katz, Tom Dale Ember turns 7 in April 🎂 5th anniversary of EmberConf! Melanie Sumner is joining the core team ⭐ Huge ecosystem of addons Future: Don’t change the fundamentals, just build a better Ember 👷 This will be the focus of the 3.x series Fewer Concepts Latest JS Optimize of Success Ember features ✨ New file system layout Related files colocated (template.hbs, component.js) Optional jQuery 30kB filesize after minification and gzip Drops out of the box Ember size by 1/5 🔥 Simplified testing async and await Use custom codemods to fully automate the heavy lifting for the conversion Mocha integration 1st class JS Modules Only import the modules you need Use codemods to fully automate this conversion process Treeshaking Editor integration Object model Computed properties JS classes @decorators allows us to implement computed properties and services inside JS classes JS Class fields Declare and initialize properties within the JS class body TypeScript Fragment components Remove the wrapping <div> elements on components without tagName: '' hack Setters @tracked properties Automatically infers dependencies on other Properties No more dependent keys @tracked get slug() { } Component arguments this.args {{@post.body}} All of the above features are on Release, Beta, or Canary channels today! 🏆 Request for Comments (RFCs) 💬 Angle bracket components single word component names Named blocks Pass in more than 1 block into a single component Ember → GlimmerJS LinkedIn created two versions of the list route in Preact and GlimmerJS Glimmer performed slightly better Improving Glimmer VM Binary bytecode: .hbs → .gbx bytecode SSR (Server Side Rendering) Async rendering Repairing rehydration Ember Schedule App WebAssembly (WASM) Run code at native speed in browsers 💨 In the process of converting low level code in Glimmer into WASM Ember Schedule App in WASM WASM2ASM for continued IE11 support Ember has never been more technically advanced than it has been at this moment ⚡ Ambitious for All: Accessibility in Ember – Melanie Sumner Accessibility: Making your web apps usable by people of all ability levels in the way it was designed to be used Web Standards WAI-ARIA WCAG A, AA, & AAA conformance levels #a11y Microsoft Azure video indexer Adjust the language model Image descriptions Ember A11y Project “Ship it now and we’ll fix it later” 🚫 Challenges in Ember :suspect: Route transitions Modals and popups Track the focus within the modal Shouldn’t be able to navigate outside of the modal aria-* attribute support Click all the things Whatever you can do with a click, you should be able to do with a keyboard Nested interactive elements ⛔ Passwords The “easy” wins Use semantic HTML5 Link vs. Button Links for routes Buttons for actions Keyboard arrow-key navigation ⬆️ ⬇️ ⬅️ ➡️ Color contrast Image alt attributes ember-component-attributes addon if you don’t want to go in and change your existing components Everything they didn’t tell you about the Ember Community – Jessica Jordan Lots of identity around specific sub-cultures we create for ourselves 👪 The Emberista sub-culture 🐹 Group within the larger JS community, often having beliefs or interests at variance with those of the larger culture Ember NPM downloads fairly stable over the last year (~300K/month) CLIs in other JS sub-cultures have a larger variance over the last year Addons for any use case Niche — Ember Pell Large scale — Ember Power Select RFCs 💬 Ember helped inspire React to implement RFC in December 2017 Ember Status Board Ember Slack Community The Next Generation of Testing – Tobias Bieniek Async andThen() helper is no longer used ❌ 5 years old & unintuitive API Replace with the promised based async / await 🔥 ember-native-dom-helpers uses native DOM API’s without jQuery ember-native-dom-helpers → @ember/test-helpers Both Mocha and QUnit allow nested modules inside tests Grand Testing Unification Scope was initially way too big Core team extracted several smaller scoped RFCs out of these core ideas RFC 232 moduleFor('x-foo') and moduleForComponent('x-foo') → module('x-foo') + setupTest(hooks); RFC 268 moduleForAcceptance('Acceptance | login') → module('Acceptance | login') + setupApplicationTest(hooks); 4 main types of tests 1️⃣ Plain QUnit test Not Ember specific 2️⃣ “Container” tests For Controllers, Routes, Services… Previously your unit tests The ember-qunit setupTest(hooks) allows for APIs like this.owner inside the test() 3️⃣ Rendering tests Previously your component integration tests setupRenderingTest(hooks) Actually uses setupTest(hooks) under the hood 4️⃣ Application tests Previously your Acceptance tests setupApplicationTest(hooks) ember-cli-qunit > v4.2.0 allows you to use the new APIs How to migrate all of my tests? Migrate to async / await Use ember-native-dom-helpers ember-native-dom-helpers-codemod ember-qunit-codemod Rename ember-native-dom-helpers imports → ember/test-helpers ember-test-helpers-codemod Mocking this.owner.register('service:cookies', Service.extend({})) this.owner.lookup('service:features') Loading States First, let promise = click('.submit') Notice: no await click() Next, await waitFor('.loading-spinner') Now you can do your assertions Finally, await promise to finish the click Custom test helpers export async function addContact() { await FIllIn(); await click(); } Test selectors Use data attributes [data-test-title] instead of h2 ember-test-selectors uses AST transform to strip test selectors out of productions builds qunit-dom Very readable assertions assert.dom('input').exists({ count: 3 }) Say More – Jamie White Make your tests say more 📣 Ember’s testing toolkit is incredible Great tools so it’s even more important to ask questions of them What if we could impose access via accessibility through our UI testing Rule of least power A less powerful and more constrained language fillIn('input[name=title]') → fillIn('Title') Test: Ensure the user wouldn’t have to tab backwards to get to the submit button Test: Ensure clicking submit works with a keyboard await click() → await keyboardClick() Test: Ensure the application made 1 atomic network request after clicking “Submit” Who Moved My Cheese? Ember’s New Filesystem Layout – Matthew Beale Ember project is pretty good at big changes 🌟 Deprecations Codemods Optional features ember install @ember/optional-features ember feature:list ember feature:enable someFeature ember feature:disable someFeature How will core ship the new filesystem layout ❓ RFC → Canary → Feature “Go” → convert addons → convert apps → deprecate Module Unification - Ember’s new file system layout ✨ Co-location for related files Improved isolation for single-use components and helpers Improved isolation of addon APIs app.js → main.js app/ → src/ Tests can be colocated in the file system src/data/models/user/model-test.js Styles can be colocated in the file system src/ui/routes/sign-in/style.scss src/ui/routes/${name}/route.js ↔ src/ui/routes/${name}.js Local lookup Only able to access certain components for a specific file if they are nested in the file system layout Create a private interface Great for contextual components Addon Namespaces {{gadget-tools::gadget-list}} {{gadget-tools::list}} {{! shorthand }} {{gadget-tools}} {{! shorthand with `gadget-tools/src/ui/components/main/` filesystem }} double colon symbol means to now reference a helper or component from within the namespace Addon migration strategy Module Unification addons will play nice with Classic apps fallback-resolver Must run canary CLI today to generate a new layout application npm install -g ember-cli/ember-cli MODULE_UNIFICATION=true ember new my-app ember-module-migrator to migrate an existing app to the new layout Mastering the Art of Forms – Danielle Adams Forms are everywhere 📄 Might be the first thing your user will see Component Patterns / Data Management / User Experience / Accessibility Design questions ❓ What field type is this? Is this required? Is it dependent on another component? Does it supply functionality, UI elements, or both? Component Patterns Strategy: Combining your label and input into a single custom component <label>Thing</label><input> → {{input/text-field}} Standardizes your API of the form elements Standardizes the UI of the various form elements across the app Strategy: Contextual component form group {{yield (hash questionText=(t 'radio-button-group.feeling-lucky') radioButtonGroup=(component 'radio-button-group options=radioOptions) luckyNumberInput=(component 'input/number-value' id='input.lucky-number' value=model.luckyNumber) ) }} {{#form-group/lucky-number model=human as |formGroup|}} {{formGroup.questionText}} {{formGroup.radioButtonGroup}} {{formGroup.luckyNumberInput}} {{/form-group/lucky-number}} Same benefits as the first Strategy Reusable without being bound to their initial layout Components should fit together like a game of Tetris Data Management 📊 Data required by the view should not hold up a page from rendering The component can be responsible for fetching data willRender() Handle retries from the component ember-concurrency User is able to interact with the app sooner Relative data is scoped within the component itself Validate data from the component level ember-cp-validations Is the element an input? You can probably use 2-way bindings User Experience & Web Accessibility 💻 Always label your inputs with the for attribute <label for="foo"><input id="foo"> Use logical tabbing order How To Build A Bonfire: On Training and Hiring New Devs – Taylor Jones Ember isn’t exactly the first thing developers are running towards these days ❄️ Unfortunately, Stability without stagnation doesn’t create a buzz How do you convince people outside of our bubble to come join us “We’ve gotta hire somebody!!!” 😰 🙋 “Well why don’t you just hire more engineers?” It’s not always that easy… 🙅 First takeaway — Start small when developing a culture of teaching and learning How do we scale it? Foundations vs. Features How do we move on to helping our whole team become skilled at Ember? Newbies Teach JavaScript fundamentals along side Ember fundamentals Should be limited in exposure until they actually dive into Ember Veterans You may have a hard time ushering in Ember’s way of thinking Less impressionable and likely more opinionated 🙋 “But I’m used to React…” Emphasize common threads around the ideas of Components and the React Router Ember’s design patterns are much more structured No more webpack 🙋 “But I’m used to Angular…” Explaining the consistency of Ember vs the drastic deprecations of Angular Shared ideas around Controllers, Routers, and Services 🙋 “Well I used Ember 5 years ago…” A lot of Ember has stayed the same but a lot has changed and there are many new best practices Can be tempted to fall back on old knowledge of the framework The structure and opinions that Ember presents can be really hard for folks to adjust to Everyone isn’t going to love Ember as much as you do…and that’s ok! Living Animation – Edward Faulkner Animation is actually kind of hard :rage2: There’s overhead and cost associated with having to animate on-screen elements Using animations to teach and help guide your user’s attention Software developers are actually all teachers 🎓 Teaching your users how to effectively use your app OS X minimization animation Ember Concurrency task documentation examples You don’t always need a library to animate CSS is very expressive for many use cases CSS transitions and animations Web Animations API requestAnimationFrame() liquid-fire Looking into “game-engine-inspired” principles Strong separation between app logic and animation layers Establish rules and let the motions emerge Ember Animated “Glimmerization” of Liquid Fire {{#animated-each}} → {{#animated::each}} {{#animated-if}} → {{#animated::if}} {{#animated-value}} Asymmetric easing functions easeOut when moving on screen (decelerate in) easeIn when moving off screen (accelerate out) Animated value {{#animated-container}} {{#animated-value counter rules=rules duration=1000 as |v|}} <span>{{v}}</span> {{/animated-value}} {{/animated-container}} Once we get docs, we can go live and push for v1.0 DAY 2 The Future of Data in Ember – Dan Gebhardt The future of data in Ember is __________? 😕 Web standards? Ahead of standards? Realtime? RESTful? Graph-based? Operational? Offline? Ember needs to meet you where you are and get you where you need to be 🌟 GET /api/v1/contacts GET /api/v1/contacts/:contact:id Lets build an app…Original plan: fetch + JSON return this.fetch('api/v1/contacts') A new requirement comes in… work offline Service workers ember-service-worker ember install ember-service-worker ember install ember-service-worker-index ember install ember-service-worker-asset-cache ember install ember-service-worker-cache-fallback Offline works now Next Step: A new requirement comes in… add admin pages to edit Now update data layer to use Ember data return this.get('store').findAll('contact') GET /api/v2/contacts/ GET /api/v2/contacts/:contact_id POST /api/v2/contacts/ PATCH /api/v2/contacts/:contact_id DELETE /api/v2/contacts/:contact_id Final Step: A new requirement comes in… everything needs to work offline ember-orbit How do we allow apps to evolve with less friction? Augment capabilities incrementally Only increase complexity with an increased need for capabilities JSON API 50+ client libraries 14 languages HTTP compliant basic CRUD → compound documents, sparse data sets → operations, local identities, profiles (v1.1) Composable, well-defined interfaces Monolithic full stack solution → interchangeable components Ember Data: Serve the needs of 80% of all Ember apps Evergreen behavior composability + interchangeability Currently — Tight coupling: Store ↔ Model Ember Data Record RFC Formalize interface between Store and Model Store, models, basic CRUD → partial records, embedded records, changesets → offline, store forking, optimistic UIs Orbit - Data access and synchronization library Offline (Optimistic UI) Pluggable sources 🔌 Data synchronization 🔄 Editing contexts Undo/Redo How does Orbit fit with Ember Data? 😟 Orbit : Ember Data :: Glimmer : Ember Ember Data can provide Orbit’s capabilities in a convention-driven package Orbit and it’s ecosystem can provide a laboratory for experimentation Future? 👽 GraphQL usage will continue to grow… Apollo will continue to innovate REST+ solutions, like JSON API v1.1 will also grow Static analysis will improve runtime efficiency Immutable data structures will see increased internal usage (under the hood) Demand for offline PWAs will grow in order to compete with native apps Orbit will see continued growth across the frontend and in Node Smartphone Symphony – Gavin Joyce ember-present - addon for creating presentations where the slides are ember components bit.ly/emberconf 📱 🎶 🎵 🎶 Deep Dive on Ember Events – Marie Chatfield Once works breaks the app 😰 Only listening for events with Ember <div {{action "toggle"}}> <div {{action "advanceTour" bubbles=false}}>Toggle Button</div> </div> If I add 1 word onclick: Now we have a combination of listening for events with Ember and the Native DOM <div onclick={{action "toggle"}}> <div {{action "advanceTour" bubbles=false}}>Toggle Button</div> </div> Event propagation Every node’s parent has a chance to handle the bubbled event event.stopPropagation() on the child node will stop the default bubbling Ember Event listeners {{action "clickMe"}} Abstraction on top of the native DOM event listeners Ember: bubbles=false === DOM: event.stopPropagation() The parent-most element <div class="ember-application"> is where Ember hooks into its event handlers ⚠️ Deep Dive!!! ⚠️ Ember’s event_dispatcher.js has the complete list of it’s default events Ember’s setupHandler(rootElement, event, eventName, viewRegistry) function call for (event in events) { if (events.hasOwnProperty(event)) { this.setupHandler(rootElement, event, events[event], viewRegistry); } } rootElement.on('${event}.ember', '.ember-view', function(event) { }) So for example: rootElement.on('click', '.ember-view', function() {}) will setup delegated event listeners on each .ember-view in the DOM tree Delegated event listener When an event happens on any children for the parent node, then the event will propograte up through the DOM tree to the delegated parent Allows us to reuse the same event handler throughout the lifecycle of our app Ember event listeners cannot event.stopPropagation() to DOM event listeners because the DOM event listeners have already been triggered by the time Ember has a chance to fire it’s handlers Quick examples: {{! DOM event listener (closure action) }} <div onclick={{action "handleClick"}}></div> {{! Ember event listener }} <div {{action "handleclick"}}></div> {{! Ember event listener }} {{some-component click=(action "handleClick")}} Pick one event listener strategy API and stick with it ❗ Ember events use more memory but have less overall DOM event listeners because of delegation DOM events use less memory but have more overall DOM event listeners due to no delegation Overall, speed is about the same for both Optionally add a listener? 😕 Does not work: <div {{if isActive (action "handleClick")}}> ❌ Just use semantic HTML: <button {{action "handleClick"}} disabled={{isInactive}}> ✅ Could also just use a DOM event listener <div onclick={{if isActive (action "handleClick")}}>✅ DOM Event listeners always fire before Ember event listeners! ❗ Consistency and predictability are the most important things when handling events in Ember ❗ Prying Open the Black Box – Godfrey Chan Stack Trace: TypeError: Cannot read property 'get' of undefined 🚨 Should be read top → bottom ⏬ Clicking to the file in the stack trace, the browser will take you directly to the line where the error occurred “Pause on Exceptions” button will freeze the stack at a moment in time Allows us to use the console and sources tab to inspect at the exact moment an issue occurred debugger; snippet allows you to pause execution and inspect the state of your app “Step Over” button allows you to go forward in time within the current stack frame ↩️ “Step Into” button allows you to drill down into the implementation of the currently highlighted function ⤵️ “Step Out” button allows you to pop back up into the previous stack frame ⤴️ “Resume” button advances time until the next breakpoint ▶️ Ember will often have a lot of items in the stack because it’s handling lots of things behind the scenes (like managing the run loop) “Blackbox Script” Right click on any frame you don’t want to see, you will end up directly inside the super class implementation ⛔ Great for bypassing specific internal Ember code within the stack trace Breakpoints Conditional breakpoints XHR/fetch breakpoints URL contains foo.json Right click: “Continue to here” Right click: “Never pause here” import { assert debug } from '@ember/debug'; Stripped from production builds {{debugger}} in your templates Ember inspector: $E sends the object to your console Right click: “Show function definition” $0 shows the currently highlighted element inside the console Right click element: Break on > subtree modifications EmberConf MiniTalks Thanks to all of the community contributors! 😍 Lightning deploy strategy with ember-cli-deploy ⚡ ember-cli-deploy-lightning-pack Build → Deploy (Assets to S3/index.html blob to Redis) → Activate How can we share our documentation? 😕 ember-cli-addon-docs Goal: No-brainer for every addon author to use broccoli-static-site-json Parse markdown and output JSON files ember-learn/deprecation-app 🐹 Creating fluid app-like experiences with Ember – Nick Schot Goal: Create an Ember app in the browser that performs as close to Native as possible 💥 {{mobile-bar isLocked=false}} follows downward touch scroll collapses the top header on scroll down, reappears on scroll up Transitions with ember-animated Enhance perceived performance User experience {{mobile-page}} {{top-toolbar}} Managing scroll state Get restored when navigating up the route hierarchy Get reset when navigating back down the route hierarchy Responsiveness ember-responsive {{#if media.isMobile}} CSS Media Queries Use ember-responsive to disable or modify mobile transitions on Desktop Progressive Web App enhancements Hybrid apps Keeping (perceived) performance up 💨 Async model hooks Use ember-concurrency to make model hook async Use loader component Svelte list rendering vertical-collection Demo App ember-mobile-bar ember-mobile-pane ember-mobile-menu ember-mobile-core

March 13, 2018 · 15 min

Road to Ember 3.0 Reaction

Well, nearly 3 years later and here we are again with another reaction for the latest Ember major version release and this one’s going to be short and sweet. I honestly do not have enough positive things to say about this release plan. It is yet another validating reason that firmly solidifies Ember’s status as the best frontend framework. Basically, if your app is running without deprecations right now on an Ember version 2.14 and above then you are 100% set and ready to go for 3.0. ...

October 3, 2017 · 1 min

Ember Route Hooks - A Complete Look

If you are like me and want to get your hands on something to hack around, I created this Ember Twiddle. Play around with it to get a better feel for Ember’s route hook order. Add your own custom logging, transitions, nested routes and other things. The route hook lifecycle in Ember can be broken up into two distinct phases: the validation phase and the setup phase. These two phases are surrounded by two separate actions that get triggered within the context of the route: willTransition() at the beginning and didTransition() at the end after a successful transition. ...

May 27, 2017 · 7 min

EmberConf 2017 CliffsNotes

Here is a highlighted overview of the major points from some of my favorite EmberConf 2017 talks: DAY 1 Opening Keynote – Yehuda Katz, Tom Dale 5 Years of EmberConf! 🎂 Announcing Amber.js - Dec 8, 2011 New core team members ⭐ Katie Gengler, Chat Hietala, Ricardo Mendes Ember 2.x Series What didn’t work: 👎 Routable components Deprecating controllers <angle-bracket> components Pods What did work: 👍 Fastboot Engines Glimmer / Glimmer 2.0 (~30% smaller download size and 2x app speed improvement) Overall better experience What have we learned? 📖 Big up front design Small Kernel → Addon Fastboot - Ember simply landed the App.visit() API → ember-fastboot addon Drop-in compatibility for new features Experimentation is key 🔑 ember-redux ember-concurrency ember-orbit Glimmer 2.0 Pre Glimmer: Less modular than we thought - Ember + HTMLBars Extract and rationalize - Ember view layer + Glimmer 2.10 was a drop-in replacement for 2.9 Test suite runs on both the old engine and the new engine at the same time Architecture: wire format [[11, 'div'], [11, 'span'][1, [33,'hello']...] Reduce “In-Browser” work Take advantage of declarative nature Glimmer VM Web problem: Boot fast AND stay fast once booted You can go the fastest if you don’t care about updating The truth about traditional JavaScript benchmarks Ember Community Survey Glimmer.js Rendering engine used to power Ember → Now can be used standalone Bind dynamic content from component to template without esoteric naming systems TypeScript + Ember! Computed property accessors Decorators “Just JS” actions No more .get or .set This is the component API we want for Ember’s Custom Component API RFC Module Unification RFC already merged - implementation has begun Links the Ember and Glimmer worlds together Write in Glimmer, drop into Ember app Going Progressive with Ember – Samanta de Barros Progressive Web Apps Fast ⚡ Work offline ❌ Install on the device 📱 69% of web traffic today comes from smartphone devices Native vs. Web Gap is rapidly shrinking Web app manifest JSON Currently, only chrome support iOS needs custom <meta> tags in <head> Windows needs an extra browser config file ember-web-app - ember install ember-web-app Generates all of these files for you and related <meta> tags Service Worker is serviceworker ready? Intercepts every request Save assets on install event Background sync Push notifications API ember-service-worker Plugin approach broccoli-serviceworker Generates SW based on config Application cache Works on all browsers broccoli-manifest User data offline? Local storage, WebSQL, IndexedDB Local Forage - Wraps all 3 ember-localforage-adapter ember-pouch First page render ember-cli-fastboot Lighthouse - Chrome extension A Neurobiologist’s Guide to Mind Manipulation – Casey Watts caseywatts.com/mindmanipulation - Print items in purple Cognitive restructuring “In-moment” vs “Reflecting” How the brain works Inner vs Outer brain Inner - Old, limbic system, fast ~ms Outer - Cortex, thoughts, slow ~s Brain as a system Feedback loop: input → process → output Autopilot: input → output (no process) Automatic thoughts/feelings vs. Deliberate thoughts/feelings CBT - Cognitive Behavioral Therapy npm install constant-introspection 0 Whoop (introspect) → 1 Input (how did I get here?/current bodily state) → 2 Emotions & Thoughts (expand emotional vocabulary/emotion processing techniques) → 3 Response Unhelpful Thoughts Other tools Therapist Book: Feeling Good by David D. Burns Headspace (app) Joyable (webapp) Psychological Safety PsycSafe Group: current members feel safe PsycSafe Traits: Communication & Empathy Making the team feel more PsycSafe → raise collective group IQ Goal: Improving Team PsycSafety Communication Earned Dogmatism Effect: “I am experienced, therefore my idea is right” Reveal there is information missing Declare Unknowns: “We don’t fully understand X yet” “We don’t know how complicated auth will be!” Framing: “learning opportunity” not “BAD WRONG BAD” Server went down - learning opportunity to improve Acknowledge Fallibility: “I make mistakes and I know it - tell me what you notice” Model Curiosity: Ask many questions Empathy Propinquity: Social closeness Task: “[potential issues]” vs. Relationship: “You aren’t competent” PEARLS - Partnership, Empathy, Acknowledgement, Respect, Legitimation, Support Validation: Recognition and acceptance of another person’s [thoughts, feelings, sensations, and behaviors] as understandable (even if you don’t agree) Depersonalize Ideas - “Idea A” not “Casey’s Idea” Vulnerability: Increases trust Understanding JavaScript Performance – Godfrey Chan Hierarchy of Speed Laws of Physics (base) → Hardware → Kernels → User-land → Human Factors (top) Everything above builds on the layers below Hierarchy of JS Performance JS Engines (base) → Libraries → Your Code (top) factoryFor RFC Deprecate component eventManger RFC Framework Time Budget 1,000ms initial render JS Engines - nanoseconds (50 nanoseconds 10,000,000x) let obj = {} Written in C JS - Everything is a dictionary Hidden class “Shape” / “Map” Tools Native syntax - node --trace_opt --trace_deopt --allow-natives-syntax my-script.js Libraries - microseconds (50 microseconds 10,000x) Ember.get() Written in JS, Called many times, Generic code Tools CPU Profiler, Flame graphs Your Code - milliseconds ~ seconds (50ms 10x) {{my-component}} Problems: Hidden loops Big Data Download time, Parse time, Compounding Backtracking - Invalidating already flushed content Error since Ember 2.10 Tools Network tab, Timeline view (Chrome), User Timing API Micro vs Macro Macro: Do fewer things - improve this layer Don’t do the work, Reuse the work, Defer the work Micro: Do faster things - help the next layer Use helpers, {{unbound}}, Custom components ember-bench Big picture: 1000 paper cuts, lots of repeated work Ember: Helps us do fewer things via better coordination with macro optimizations Counter-spells and the Art of Keeping Your Application Safe – Ingrid Epure Gifar image vulnerability attack ~2008 💾 Image EXIF embedding PHP code ~2012 💾 First rule of web security: Never (EVER) trust user submitted data 🔐 Reflected XSS GET http://myapp.com/list/all?search_term=<img """><script>alert(document.cookie)</script>"> Ember: HTML escaping Ember escapes by default To bypass use Ember.String.htmlSafe() Content Security Policy ember-cli-content-security-policy Whitelists “safe” scripts, fonts, images, etc. Content-Security-Policy "script-src 'self' static.mysite.com" Use CSP V2 and V3 only hash-source and nonce-source for inline script support Avoid htmlSafe() ❌ Use only with proper sanitization Never use directly on user input Use Ember Contextual Components Good helpers - Let the browser worry about it Use DOM to create text nodes Set style attributes Append child Avoid Triple Curlies - {{{foo}}} ❌ Always use rel="noopener noreferrer" with target=_blank target=_blank vulnerability Built-in lint rules via ember-cli-template-lint Animate the Web with Ember.js – Jessica Jordan Frame-by-Frame Animations Image Sequence + Display Frequency Phi phenomenon Flash animations → HTML 5 animations Why open web standards? Open Consistent Available HTML 5 <canvas></canvas> Powerful Web API Canvas context object - bower install --save canvas-5-polyfill Sprite sheet + ctx.drawImage() Ember & Web Animations API Web Animations API - animation of the future ember-web-animations-next-polyfill - ember install ember-web-animations-next-polyfill Keyframe effects Multi-layer Components Sub components {{#each ...}}{{comic-layer}}{{/each}} Data Loading Patterns with JSON API – Balint Erdi Why JSON API? Convention over Configuration for APIs Ember Data Store: this.store() findRecord('band', 1); - return from the store as well as trigger a reload over the wire findAll('band'); peekRecord('band', 1); - peek* does not trigger a reload, simply returns what is in the store peekAll('band'); shouldBackgroundReloadRecord & shouldBackgroundReloadAll Fetching relationship data Lazy fetching Simple, on demand data fetch Might trigger N requests, flicker Pre-loading: model() hook return Ember.RSVP.hash() Moves relationship data to route’s model() hook - blocks rendering of template Better UX but the N request issue persists, RSVP.hash() is a model hook anti-pattern Compound document syncing (side-loading) this.store.findRecord('band', params.id, { include 'songs', reload: true }); /band/1?include=songs Leverage JSON API, explicit control over fetching relationship data Delays rendering of the child template Ember Data Patterns https://balinterdi.com/emberconf/ Slides Higher Order Components – Miguel Camba Higher Order functions Functions that return functions Create closures Higher Order components Components that return components hash helper used to explicitly define a Public API for the component {{yield (hash avatar=(component "user-avatar") image=user.pic size="big")}} Now this is accessible as a variable in the block from the callee in the parent template - {{t.avatar}} API design is very important 🎨 Less options are better Don’t abuse bindings to communicate with parent Minimize mandatory options with sensible defaults Options are passed to the component that cares about them A well crafted component should be easy to adapt to new uses Initial approach: Bindings - {{x-toggle checked=checked}} Solution DDAU - onChange=(action (mut checked)) Now what if I want different colors and size 😖 Presentational and Container Components by Dan Abramov Contextual Components Flexibility, composability and the right level of abstractions Use hasBlock template helper to make the contextual component “Opt In” Now just pass in non-block form for sensible defaults DAY 2 Empowering the Next Million Creators – Edward Faulkner How do we grow to empower wider audiences of people? Continuum from small applications with less features → bigger application with more features npm install your way up from Glimmer.js to Ember Small: Glimmer.js Medium: Ember.js Big: Drupal, Wordpress Glimmer.js - Flexible, Expandable Modern-web platform The web is about HTML Good level of power for the task it is assigned Fairly easy to learn and pick up Templates in Ember are just a superset of HTML - Flexible (Ember strength) Addon ecosystem Drupal: You need your site up and running. Problem: developers are very expensive Focus on a few unique tasks → offload the rest on to the community A community that invests in shared standards NEW 🚨🚨🚨: Card stack application architecture Drop-in tools to give you a WYSIWYG editor for your Ember components (Big on the continuum scale) ember install @cardstack/cardstack-tools {{#cardstack-tools}}{{outlet}}{{#cardstack-tools}} ember install squishable-container - simple component that takes it’s initial size and is able to scale itself {{#cardstack-tools}}{{#squishable-container}}{{outlet}}{{squishable-container}}{{#cardstack-tools}} ember-toolbars {{cardstack-content}} ember install @cardstack/core-types - I’m NPM installing my way to my final app state ember install @cardstack/mobiledoc - Rich text editing on the web ember-overlays @cardstack/hub - layer that bridges together all sources of data your application needs, into a single source that follows the same authentication and configures to your application standards Authentication & Authorization SVG Animation and Interaction in Ember – Jen Weber SVG - images made of code SVG Basics SVG elements can be transformed with CSS Simply style using CSS outline → stroke background-color → fill Follows paint order, not z-index. Lowest in DOM order forms top layer visible to the user <g> group wrapper Using SVGs in Ember Easily add actions to SVGs Binding attributes and classes Avoiding pitfalls <rect class="temperature {{tempStatus}}" width="117.6" height={{thermHeight}} /> Doesn’t always work (height goes down instead of up!) Top left corner is 0,0 Shapes are positioned using x and y coordinates within the SVG viewBox Elements can be spinned, stretched, squished, etc. <rect class="temperature {{tempStatus}}" width="117.6" height={{thermHeight}} transform="rotate(180 365 710)"/> Fixes the issue by essentially rotating the axis of the rectangle so the height eases up instead of down Default Ember component <div> wrapper inside SVG === bad. Use tagName='g' instead Paint order Problems: Use Ember.computed.sort() so data with the lowest y coordinate gets rendered first Upgrade app > Ember v1.8.0 Use computed properties in the model to manipulate plotted/transformed SVG data & coordinates Accessible SVG SVG Optimization Tools Mastering Ember from the Perspective of a N00b – Madison Kerndt Dreyfus model Novice → Advanced Beginner → Competent → Proficient → Expert Biggest shift: Proficient → Expert Proficient developer sees all the details and complexities in the Tree Expert developer sees all of the details and complexities in the Forrest Intuition: ability to understand something without the need for conscious reasoning Adriaan de Groot Neuroscience and psychology research using Chess Can you remember the pieces? In order to retain information, we have to organize it in a way that is meaninful → Intuitiion Zone of Proximal Development - What a learner can do with and without help Optimal pacing is challenging people just beyond their learning ability level Mental Model Router → Route → Model → Parent Template → Component {{outlet}} - lets you specific where a child route should render inside of a template State, Time, and Concurrency – Alex Matchneer State is the data in your app that changes over time Concurrency is when you have more than one state change operation occurring at the same time. ember-concurrency ⚠️ Error: Calling set on destroyed object No isSubmitting flag No isDestroyed check No “Am I Still Running?” checks No .set() calls necessary at all Task Better syntax for expressing async operations Allows for cancellation Declarative API Derived State Task Modifiers .drop() .enqueue() .restartable() Task Groups Derived State: Helpful “out-of-the-box” state <TaskInstance>.isRunning <TaskInstance>.performCount <TaskInstance>.concurrency Anti-Pattern: Manual state tracking this.set('isShipping', true); yield asyncTask(); this.set('isShipping', false); Redundant, Point of easy failure, Error-prone Respect the 4th Dimension :clock: When you .perform() a Task it creates a TaskInstance Essential State vs Accidental State Solution: Derived State (Computed Properties) Declarative APIs > Imperative APIs Slides Confessions of an Ember Addon Author – Lauren Elizabeth Tan ~3.5k addons out there today What makes an addon good? #1. Solve an interesting problem #2. Straightforward to setup and use (docs and examples) #3. API needs to be deliberate #4. Reliable (tests) EX: ember-power-select, ember-concurrency, liquid-fire, ember-cli-deploy, ember-cli-mirage DDD - Documentation Driven Development If it’s not documented, it doesn’t exist First class citizen JSDoc, YUIDoc Any successful project requires two things Solve a problem Convince people to use your addon Project doesn’t end after you type npm publish Addon Anatomy Folder structure looks very similar to regular Ember App Certain folders in Ember-land, certain folders in Node-land /addon doesn’t get merged into consuming app’s tree Allow for overriding Be deliberate about what get’s merged into consuming app ⚠️ Addon internals are not actually private ⚠️ There are still ways for consuming apps to access 🔓 Blueprints Addon hooks in index.js are really powerful ember-test-selectors - Removes itself from the application during a prod build ember-composable-helpers - Whitelist/Blacklist specific helpers from your application filterHelpers() ember-cli-deploy - Augments ember-cli with custom commands One Weird Trick Tell a story - Write great docs What is the Public API? - Ramda documentation is a great example Show don’t tell - ember-burger-menu Testing your addon - ember-try Test with a real browser Configuration ember-metrics - allows different behaviors based on configuration found in config/environment.js ember-cli-build.js ember-factory-for-polyfill Dash offline documentation Always SemVer EmberConf MiniTalks Ember Beta Docs QUnit-CLI - npm install -g qunitjs; qunit --help; QUnit.todo(); - Expects failures but report Green to test reporters QUnit.begin(); → QUnit.on('runStart'); Heimdall Reduce/Reuse/Recycle ♻️ ember install ember-perf-timeline ember install ember-heimdall Timeline integration Stripped from prod code Spin Me a Yarn – Serena Fritsch NPM released in 2010 11k packages published per week Yarn - Fast, reliable, and secure dependency management Package 📦: Piece of software that can be downloaded; may depend on other packages Multiple levels of dependencies (nested) Allows us to install packages with different versions So you want to write a package manager by Sam Boyer Install phase: Dependency Resolution 🔍 Fetching Packages 🚚 Linking Packages 🔗 package.json: “What I want” vs. yarn.lock: “What I had” NPM === Nondeterministic Always git commit your yarn.lock file Ember CLI 2.13 onwards is “yarn aware” An Animated Guide to Ember Internals – Gavin Joyce Classic action vs Closure action Boot: Journey through Ember.js Glue: Booting Up by Mike North 27 events handled by default and triggered on body Initial Render: Handlebars template → Wire format Compilation step: Wire format → Op Codes Op Codes are then executed at runtime Glimmer VMs Append VM - Run initially Update VM - Run on update

March 28, 2017 · 12 min

EmberConf 2016 CliffsNotes

Here is an overview for some of the major points from some of my favorite Emberconf 2016 talks: DAY 1 Opening Keynote – Yehuda Katz, Tom Dale Community momentum 1000 conference attendees Zoey Tomster Huge ember-cli adoption (332,000 installs last month alone) Community survey Over 1800 participants 76% using Ember 2.x 36% using Ember 1.13 Lessons learned from 1.13 RFC 56 - Refining the Release Process LTS Releases - Bug fixes for 36 weeks, Security fixes for 60 weeks, Every 4 releases Subteams - Need centralization for leadership, but at the same time, we don’t want too much bottleneck on the core team Core Team Ember Data Team Ember CLI Team Learning Team Community Smoke and Mirrors Ember Observer Ember Concurrency Angular adopted Ember CLI as it’s CLI platform Mobile Painful currently to click a pinterest link from Twitter to the actual Native app Many of the native features are now available to web applications Service Worker / Add to Home Screen / Web Workers / Geolocation / IndexedDB / Animation / Camera How to deliver native-caliber features without giving up “instant” Improving load time Fast Boot - ember-fastboot SEO and server-side rendering Shipping [email protected] with Ember v2.7.0 Project Svelte - Tree shaking to eliminate unused modules Engines String Loading -Ship JS Modules as strings to only pay evaluation cost for modules that are being used Service Worker App Cache - Reliable Glimmer 2.0 DBMON Example - 2x speed boost Ember 2.4 12FPS Glimmer 2.0 22 FPS Uptime Boxes Example - 3x speed boost Initial Render - Canary + Glimmer 2.0 1.5-2x faster Glimmer 2.0 Templates are 5x smaller than HTMLBars Written in Typescript The way we build web applications is changing Ember - an SDK for the web ember-appcache-demo by Erik Bryn Using Service Workers in Ember – John Kleinschmidt Not eveyrone in the world is as “connected” as we are here in the United States Service Workers Bootstrapping for web applications offline Only works with HTTPS URLs currently isserviceworkerready? Developer tools make it easy for debugging broccoli-serviceworker Update app/config/environment.js file with cache URLs, etc. to precache the entire application Toolbox API support to go network first/fallback to cache or cache first (networkFirst/cacheFirst) Using service worker to alter network requests based on network type. 2G Networks get smaller payloads for example Safari browser support doesn’t look good at the moment. Using App Cache as fallback for a much wider browser support story Selecting Good Ember Patterns – Brenna O’Brien Select element is 2 way bound by default {{view "select"}} has since been deprecated DDAU approach Actions Up: onchange={{action "selectDidChange"}} value="target.value"}} Data Down: selected={{is-equal language selectedLanguage}} Closure actions for better nested component action handling Dynamic key lookup, use {{get}} helper {{mut}} helper for 2 way binding. onchange=(action (mut selectedFruit)) {{ted-select}} http://tedconf.github.io/ember-ted-select Building Desktop Apps with Ember and Electron – Felix Rieseberg Electron - Chromium + Node + Native APIs (Atom, Slack, MS Visual Studio) Electron is simply a Node process that spins up Chrome windows. Communication happens through IPC to handle messages. ember-electron (based on ember-cli-nwjs and ember-cli-remote-inspector) CLI TDD and server-mode tests Build/run workflow with live reload ember install ember-electron - installs prebuilt electron binaries Run ember electron instead of ember server to spin-up a new desktop app Can use ember inpsector remotely over web sockets to debug. You have access to Node APIs as well ember election:test ember electron:package --platform darwin Building Mobile Applications with Ember – Alex Blom Cordova vs PhoneGap PhoneGap implements Cordova PhoneGap is Adobe’s proprietary service built on top of Cordova Good Code === Good Hybrid Desktop lets us be lazier JS ecosystem is littered with bad/leaky code ember-cli-cordova -> ember-cordova ember new mobile-project; ember install ember-codova Splash screen handling via SplashScreenMixin (hides on afterModel hook) Platform service platform: inject.service("device/platform") if (platform.get('isIOS')) Cordova service cordova: inject.service() onVolumeUp Keyboard service keyboard: inject.service("cordova/keyboard") Viewport changes when keyboard is on the screen Performance Crosswalk - Built by intel Package with Cordova Specifically for Android (20mb filesize) ~5x-10x speed improvement on older devices (Especially 4.x) Consistent browser environment for stuff like CSS Know your WebView - WKWebView is more performant Using too much memory has negative implications Memory Leaks Garbage Collection: 2 types (Young Generation & Old Generation) Old Generation collection is very expensive Don’t create variables you don’t need null out references to unused DOM fragments (willDestroyElement hook) Profiles > Take Heap Snapshot Containment View > Detached Nodes (these are bad and just hogging resources) window.performance window.performance.mark('foo') Manage Reflows Resizing browser window Computed styles in JS Adding/removing elements from the DOM Changing an elements classes Use CSS Transforms Use visibility:hidden to avoid reflow Animations - Use Velocity JS Warp Speed Memory Management – Kelly Senna Why memory management? User experiences are not equal Browsers are not free from performance concerns Memory life cycle: Allocate > Use > Release Garbage collection Young - Initial memory allocation is collected here Old - moved to this queue from Young when the garbage collector notices these memory allocations are still referenced Gotchas Misued variables DOM Changes - Batch operations for better memory support Dangling callbacks Dissecting an Ember CLI Build – Estelle DeBlois Ember without CLI is like Peanut Butter without Jelly Broccoli used within Ember CLI to manage the build pipeline using a Tree primitive Tree: Directory of files Entire build pipeline can be represented as a DAG (directed graph) BROCCOLI_VIZ=true ember build dot -Tpng graph.<version>.dot > out.png broccoli-stew for easy debugging DAY 2 Ember CLI The Next Generation – Stefan Penner ember-cli being adopted by angular-cli and react-cli Migrating away from Bower to NPM Move bower support to ember-cli-bower addon Big apps are a sign of success Engines are a great solution of large apps and app.js files Idiomatic Ember: Sweet Spot of Performance and Productivity – Lauren Tan “All good ideas will eventually end up in Ember” - Yehuda Move actions that deal with data into the Route Use declarative helpers in your templates for easy composability without side effects Be very wary to not overuse this power Helpers are better suited for UI and presentational logic in contrast to CP’s which are highly coupled to data ember-composable-helpers` CP’s should be used to express business logic Reusable React to changes Changes can be implicit Helpers (simple functions/class based) Pure and free of side effects Generic utility function and UI logic Think functional programming Composable Can be used as an action Component Hooks Dealing with side effects Can cause infinite loops (didRender -> side effect of rendering again) Don’t use observers Immutability is for UI, You, and I – Charles Lowell Break component out into two pieces: Content & Player Forms a movie - Immutable UI architecture Extract the Model into its own object Replace the entire model with every change POJOs are powerful Logging “just works” Bye-Bye computed properties Replace with ES5 getters Unambiguous causality - No doubt as to which event gave rise to which state 1 event = 1 state Undo/Redo becomes possible (similar to browser back/forward button in your Ember app today) ember-impagination How to Build a Compiler – James Kyle Babel, 6-to-5, etc. Compiler transforms source code from a higher level language into a lower level source language Low Level: Binary, Machine Code, CPU Architecture, Assembly Source Code: Abstraction to allow humans to understand whats happening, and be productive when writing code Compiler: Takes the Source Code -> Lower Level code Parsing Lexical Analysis - Tokens Syntactic Analysis - AST (Abstract Syntax Tree) Transformation - Manipulates AST nodes Tree Traversal Code Generation - Stringify AST Recursively calls itself to print nested nodes

March 31, 2016 · 6 min

Spotlight: Ember Closure Actions

I am really excited be spotlighting one of my favorite Ember features in a long time, closure actions. The goal of this blog post is to get you familiar, at a high level, with some of the basic closure action behaviors and help establish a solid foundational understanding. Closure actions are brand new as of the current Ember v1.13.0 release. This feature creates a whole new action handling approach which simplifies the entire process in general, as well as allows for the new function-passing solution to replace the old action bubbling mechanism. Under the hood, the {{action}} helper is now improved to allow for the creation of closed-over functions which pass the action handlers between components and controllers. ...

July 25, 2015 · 4 min

PSA: Test Your Ember Apps Against Beta and Canary

A couple of weeks ago, I returned home from another amazing week in Portland attending EmberConf. This was my second straight year attending the conference and it lived up to each and every one of my high expectations set from last years experience. I cannot give enough praise to Leah and the people behind the scenes who put in all the work to flawlessly assemble such a massive event. Among all of the interactions, talks, and technical discussions, one of my biggest takeaways was actually something that turns out to be quite small but has paid off tremendously for all of my Ember applications. I was a developer who would simply live on the latest Ember Release build and just update as needed when the next minor release version was tagged. ...

March 20, 2015 · 2 min