Ember-CLI as Compiler

What does that mean?

A bit about me

On the Ember Learning Team

When I'm not working, I'm often playing with my three sons

David Baker

@acorncom

Run an Ember consultancy in town

Some questions I hear regularly

Why are we doing a new folder structure?

When are we getting ES6 modules?

Why all the work on GlimmerJS?

Is Ember-CLI needed? Why not Webpack?

When are routable components coming?

Because Ember-CLI is becoming

a compiler for Ember apps

A compiler is computer software that ... translate[s] source code from a high-level programming language to a lower level language (e.g., assembly language, object code, or machine code) to create an executable program - Wikipedia

module.exports = {
  browsers: [
    'ie 9',
    'last 1 Chrome versions',
    'last 1 Firefox versions',
    'last 1 Safari versions'
  ]
};

config/targets.js

// snipped ...

e.args=t.namedArgsSnapshot(),e.didUpdate()}getDestructor(t){return t.component}}
class ar extends Xi{}var or={
  "component:/glimmer-testing/components/glimmer-testing":ar,
  "template:/glimmer-testing/components/glimmer-testing":{
    id:"Q5a4YIKw",
    block:'{"symbols":[],"statements":[[6,"div"],[7],[6,"h1"],[7],[0,"Welcome to Glimmer!"],[8],[8],[0,"\\n"]],"hasEval":false}',
    meta:{specifier:"template:/glimmer-testing/components/glimmer-testing"}
  }
},
lr={app:{
  name:"glimmer-testing",rootName:"glimmer-testing"},
  types:{
    application:{
      definitiveCollection:"main"
    },
    component:{
      definitiveCollection:"components"
    },
    "component-test":{unresolvable:!0},
    helper:{definitiveCollection:"components"},

// snipped ...
<div><h1>Welcome to Glimmer!</h1></div>

Do we really need a compiler?

Code-splitting

app
├── controllers
|   └── login.js
├── routes
|    └── login.js
└── templates
     └── login.hbs

Let's say we wanted to split this login route out separately ahead of time (AoT). How do we do it?

Files

app.js

Split

login.js

import Ember from 'ember';
import { task } from 'ember-concurrency';

export default Ember.Controller.extend({
  session: Ember.inject.service(),

  email: '',
  password: '',

  login: task(function * () {
    // login using simple-auth
  })
});
<form onsubmit=(perform login)>

 <div>
   {{input type="email" value=email}}
 </div>
 <div>
   {{input type="password" value=password}}
 </div>

 {{snazzy-addon-component}}

 <button type="submit">Login</button>

</form>

controller.js

Entire framework

template.hbs

Dynamically looked up

More dynamic lookups

"An SDK for the web"

  • New folder structure
  • ES6 Modules
  • Glimmer

Projects in-flight

Disclaimer

Looking at tea-leaves, fortune telling is a dubious science (much like weather forecasting)

New app layout

aka new pods, new folder structure or module unification

src/ui
└── routes
    ├── application
    │   └── template.hbs
    ├── index
    |   ├── controller.js
    |   ├── route.js
    |   └── template.hbs
    └── posts
        ├── -components
        │   ├── -utils
        │   │   └── strings.js
        │   ├── capitalize.js
        │   └── titleize.js
        └── post
            └── -components
                └── post-viewer
                    ├── component.js
                    └── template.hbs

App benefits

  • Now
    • Co-located files/pods
    • "local" components
  • Future
    • co-located tests
    • co-located styles?

Framework benefits

  • Now
    • Stop using old/inefficient resolver
    • Agree on formal rules for resolver as community
    • Rules allow for a module map for framework use (more on this later)
  • Later
    • automated code-splitting by route
    • other ideas I don't know about 😀

API changes cost a community

  • Components
    • Key Benefit: easier to reason about, cleaner API
    • Cost: rewrite into components from views
    • Long-term: avoiding rope to hang devs, more rigor for framework folks, clearer what could access
  • Ember-CLI
    • Key Benefit: add-ons, testing, Babel, ES6
    • Cost: shift from globals -> modules
    • Long-term: shift to shared tools as community
App devs Framework devs Long term
New pods Better organization Agreed on file locations ??

Key Benefit for

Big Picture

ES6 Modules

Can we get separate bundles like React/Webpack?

import Ember from 'ember';

export default Ember.Route.extend({
  customService: Ember.inject.service(),

  model() {
    // normally Ember Data store
    return this.get('customService').findPosts();
  }
});

Currently

app/routes/index.js

ES6 module?

import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';

export default Route.extend({
  customService: service(),

  model() {
    // normally Ember Data store
    return this.get('customService').findPosts();
  }
});

Coming in 2.16

app/routes/index.js

True ES6 module

But how will this "shake"?

¯\_(ツ)_/¯  Some thoughts here, but not ironed out yet

App devs Framework devs
New pods Better organization Agreed on file locations

Benefit for

Big Picture

import { default as __ui_components_my_app_component__ } from '../ui/components/my-app/component';
import { default as __ui_components_my_app_page_banner_component__ } from '../ui/components/my-app/page-banner/component';
import { default as __ui_components_my_app_page_banner_template__ } from '../ui/components/my-app/page-banner/template';
import { default as __ui_components_my_app_page_banner_titleize__ } from '../ui/components/my-app/page-banner/titleize';
import { default as __ui_components_my_app_template__ } from '../ui/components/my-app/template';
export default {
  'component:/my-app/components/my-app': __ui_components_my_app_component__,
  'component:/my-app/components/my-app/page-banner': __ui_components_my_app_page_banner_component__,
  'template:/my-app/components/my-app/page-banner': __ui_components_my_app_page_banner_template__,
  'component:/my-app/components/my-app/page-banner/titleize': __ui_components_my_app_page_banner_titleize__,
  'template:/my-app/components/my-app': __ui_components_my_app_template__
};
App devs Framework devs
New pods Better organization Agreed on file locations
Named imports Clearer APIs Statically analyze app

Benefit for

Big Picture

Unlocks other options

  • Per Route strategy
    • https://github.com/ember-cli/rfcs/pull/110
  • Other items in future?

Glimmer / GlimmerJS

These guys are really geeking out on the Comp Sci stuff, aren't they?

Warning: we're about to get into some Computer Science terms ...

What exactly are they doing?

What is Glimmer?

  • GlimmerJS (view library)
  • Glimmer (template compiler)

VM Compiler

Handlebars Template

AST (Abstract Syntax Tree)

IR (Intermediate Representation)

Bytecode (different forms, .gbx)

We iterate down from a high level to a very low-

level format that is more

efficient to pass around.

How does it run?

Compile time (CLI)

- Handlebars

- AST

- IR

Runtime (browser)

- IR JSON -> compiler ->app

Part of it built ahead of time (AoT) using Ember-CLI

- Pass the IR

- additional compiler

Part of it built up at runtime in the browser

The work we've been doing has been about putting in place requirements for staticness that, if met, mean we can

do linking at buildtime - @tomdale

How does it run?

Compile time (CLI)

- Handlebars

- AST

- IR

Runtime (browser)

- IR JSON -> app

Part of it built ahead of time (AoT) using Ember-CLI

- Pass the IR

- additional compiler

Part of it built up at runtime in the browser

In the Future

Compile time (CLI)

- Handlebars

- AST

- IR -> .gbx

Runtime (browser)

- .gbx -> app

Pass the .gbx file

We can now just run instead of doing a "linking" step in the browser first. Faster and smaller

There's one more thing ...

Caution: future-looking thoughts ahead

Rendering currently

Compile time (CLI)

- Handlebars

- AST

- IR -> .gbx

Runtime (browser)

- .gbx

- do an initial render

- shift to re-render/append mode

Pass the .gbx file

In the future

Compile time (CLI)

- Handlebars

- AST

- IR -> .gbx

Runtime (browser)

- .gbx file -> load app from HTML

- start in re-render/append mode

.gbx file

With Fastboot

Fastboot

- .gbx / app JS files

- do initial render to HTML

- send HTML / .gbx file? to browser

.gbx file?

HTML

References:

- https://twitter.com/chadhietala/status/908534322222764032

- https://github.com/glimmerjs/glimmer-vm/pull/631​​

- https://github.com/glimmerjs/glimmer-vm/pull/549

- https://twitter.com/tomdale/status/905479299964313604

The work we've been doing has been about putting in place requirements for staticness that, if met, mean we can do linking at buildtime - @tomdale

App devs Framework devs
New pods Better organization Agreed on file locations
Named imports Clearer APIs Statically analyze app
Glimmer improvements Angle bracket components? Unlock Glimmer optimizations?

Benefit for

Big Picture

Code-splitting

app/src
└── ui
    └── routes
        └── login
            ├── controller.js
            ├── route.js
            └── template.hbs

Let's say we wanted to split this login route out separately

Files

ES6 modules

login.js

Glimmer

Code-splitting

import Controller from '@ember/controller';
import { task } from 'ember-concurrency';

export default Controller.extend({
  session: service(),

  email: '',
  password: '',

  login: task(function * () {
    // login using simple-auth
  })
});
<form onsubmit=(perform login)>

 <div>
   {{input type="email" value=email}}
 </div>
 <div>
   {{input type="password" value=password}}
 </div>

 {{snazzy-addon-component}}

 <button type="submit">Login</button>

</form>

controller.js

ES6 module

template.hbs

Assume handled (details fuzzy for now)

Trouble

Code-splitting

Files

Glimmer

login.js

ES6 modules

Code-splitting

import Controller from '@ember/controller';
import { task } from 'ember-concurrency';

export default Controller.extend({
  session: service(),

  email: '',
  password: '',

  login: task(function * () {
    // login using simple-auth
  })
});
<form onsubmit=(perform login)>

 <div>
   {{input type="email" value=email}}
 </div>
 <div>
   {{input type="password" value=password}}
 </div>

 {{snazzy-addon-component}}

 <button type="submit">Login</button>

</form>

controller.js

template.hbs

Note we need these

And this

Ember-CLI's job

  • Handles bookkeeping between steps
  • Helps ensure static requirements met
  • Helps get our app where we want it

Shifting toward static?

  • Ember community's background in Ruby
  • Objective C -> Swift

Ember-CLI: our secret weapon

  • New folder structure
  • ES6 modules
  • Glimmer

Questions?

Ember-CLI as Compiler: what on earth does that mean?

By David Baker

Ember-CLI as Compiler: what on earth does that mean?

The Ember core team increasingly talks about Ember-CLI being a compiler. But what are they talking about and why? We'll look at a some key shifts in Ember-land that unlock some very interesting optimizations down the road.

  • 765