Slide 1

Slide 1 text

PLATFORM STATE OF THE UNION VERY VIRTUAL SUPER ONLINE

Slide 2

Slide 2 text

POLARIS ALIGNING WITH MODERN PACKAGES

Slide 3

Slide 3 text

PACKAGES HOW DO THEY WORK? package.json { "name": "my-app", /* ... */ "devDependencies": { "moment": "^2.29.2" /* ... */ } } import moment from 'moment';

Slide 4

Slide 4 text

PACKAGES HOW DO THEY WORK? import moment from 'moment'; node_modules moment moment.js

Slide 5

Slide 5 text

HOW IT ALL BEGAN THE “SCRIPT” IN JAVASCRIPT

Slide 6

Slide 6 text

HOW IT ALL BEGAN THE “SCRIPT” IN JAVASCRIPT My App

Slide 7

Slide 7 text

HOW IT ALL BEGAN THE “SCRIPT” IN JAVASCRIPT app/app.js window.App MySelectComponent = Ember.Component.extend({ /* ... */ }); app/router.js App.MySelectComponent = Ember.Component.extend({ /* ... */ }); app/components/nav-bar.js App.MySelectComponent = Ember.Component.extend({ /* ... */ }); app/components/select-menu.js App.MySelectComponent = Ember.Component.extend({ /* ... */ }); app/components/my-select.js App.MySelectComponent = Ember.Component.extend({ /* ... */ }); dist/my-app.js // app/app.js window.App = Ember.Application.create({ /* ... */ }); // app/router.js App.Router.map({ /* ... */ }); // app/components/nav-bar.js App.NavBarComponent = Ember.Component.extend({ /* ... */ }); // app/components/select-menu.js App.SelectMenuComponent = Ember.Component.extend({ /* ... */ }); // app/components/my-select.js App.MySelectComponent = Ember.Component.extend({ /* ... */ });

Slide 8

Slide 8 text

app/app.js window.App MySelectComponent = Ember.Component.extend({ /* ... */ }); app/router.js App.MySelectComponent = Ember.Component.extend({ /* ... */ }); app/components/nav-bar.js App.MySelectComponent = Ember.Component.extend({ /* ... */ }); app/components/select-menu.js App.MySelectComponent = Ember.Component.extend({ /* ... */ }); app/components/my-select.js App.MySelectComponent = Ember.Component.extend({ /* ... */ }); dist/my-app.js // app/app.js window.App = Ember.Application.create({ /* ... */ }); // app/router.js App.Router.map({ /* ... */ }); // app/components/nav-bar.js App.NavBarComponent = Ember.Component.extend({ /* ... */ }); // app/components/select-menu.js App.SelectMenuComponent = Ember.Component.extend({ /* ... */ }); // app/components/my-select.js App.MySelectComponent = Ember.Component.extend({ /* ... */ }); “bundling” “bundle” TANGENT

Slide 9

Slide 9 text

JAVASCRIPT MODULES THE NATIVE MODULES SYSTEM app/components/my-select.js import Ember from 'ember'; export default Ember.Component.extend({ classNames: ['my-select'], init() { this._super(); this.set('isActive', false); }, click(event) { event.preventDefault(); this.toggleProperty('isActive'); }, /* ... */ }); app/components/my-select.js App.MySelectComponent = Ember.Component.extend({ classNames: ['my-select'], init() { this._super(); this.set('isActive', false); }, click(event) { event.preventDefault(); this.toggleProperty('isActive'); }, /* ... */ }); !

Slide 10

Slide 10 text

JAVASCRIPT MODULES THE NATIVE MODULES SYSTEM app/components/my-select.js import Ember from 'ember'; export default Ember.Component.extend({ classNames: ['my-select'], init() { this._super(); this.set('isActive', false); }, click(event) { event.preventDefault(); this.toggleProperty('isActive'); }, /* ... */ }); app/components/my-select.js App.MySelectComponent = Ember.Component.extend({ classNames: ['my-select'], init() { this._super(); this.set('isActive', false); }, click(event) { event.preventDefault(); this.toggleProperty('isActive'); }, /* ... */ }); !

Slide 11

Slide 11 text

EMBER BUILD PIPELINE OUR ANSWER TO THE MISSING PIECES my-app > _ ember build Bundles

Slide 12

Slide 12 text

EMBER BUILD PIPELINE OUR ANSWER TO THE MISSING PIECES app/components/loading-spinner.js app/components/date-picker.js import Component from '@ember/component'; import task from 'ember-concurrency'; import moment from 'moment'; import ENV from 'my-app/config/environment'; export default class DatePicker extends Component { /* ... */ } dist/my-app.js /* ... */ define('my-app/components/loading-spinner', [], function() { /* ... */ }); define('my-app/components/date-picker', [ '@ember/component', 'ember-concurrency', 'moment', 'my-app/config/environment' ],function(Component, task, moment, ENV) { class DatePicker extends Component { /* ... */ } return DatePicker; }); define('my-app/config/environment', [], function () { return { environment: 'development', modulePrefix: 'my-app', /* ... */ }; });

Slide 13

Slide 13 text

EMBER BUILD PIPELINE OUR ANSWER TO THE MISSING PIECES app/components/loading-spinner.js app/components/date-picker.js import Component from '@ember/component'; import task from 'ember-concurrency'; import moment from 'moment'; import ENV from 'my-app/config/environment'; export default class DatePicker extends Component { /* ... */ } dist/my-app.js /* ... */ define('my-app/components/loading-spinner', [], function() { /* ... */ }); define('my-app/components/date-picker', [ '@ember/component', 'ember-concurrency', 'moment', 'my-app/config/environment' ],function(Component, task, moment, ENV) { class DatePicker extends Component { /* ... */ } return DatePicker; }); define('my-app/config/environment', [], function () { return { environment: 'development', modulePrefix: 'my-app', /* ... */ }; });

Slide 14

Slide 14 text

EMBER BUILD PIPELINE OUR ANSWER TO THE MISSING PIECES app/components/loading-spinner.js app/components/date-picker.js import Component from '@ember/component'; import task from 'ember-concurrency'; import moment from 'moment'; import ENV from 'my-app/config/environment'; export default class DatePicker extends Component { /* ... */ } dist/my-app.js /* ... */ define('my-app/components/loading-spinner', [], function() { /* ... */ }); define('my-app/components/date-picker', [ '@ember/component', 'ember-concurrency', 'moment', 'my-app/config/environment' ],function(Component, task, moment, ENV) { class DatePicker extends Component { /* ... */ } return DatePicker; }); define('my-app/config/environment', [], function () { return { environment: 'development', modulePrefix: 'my-app', /* ... */ }; });

Slide 15

Slide 15 text

EMBER BUILD PIPELINE OUR ANSWER TO THE MISSING PIECES app/components/loading-spinner.js app/components/date-picker.js import Component from '@ember/component'; import task from 'ember-concurrency'; import moment from 'moment'; import ENV from 'my-app/config/environment'; export default class DatePicker extends Component { /* ... */ } dist/my-app.js /* ... */ define('my-app/components/loading-spinner', [], function() { /* ... */ }); define('my-app/components/date-picker', [ '@ember/component', 'ember-concurrency', 'moment', 'my-app/config/environment' ],function(Component, task, moment, ENV) { class DatePicker extends Component { /* ... */ } return DatePicker; }); define('my-app/config/environment', [], function () { return { environment: 'development', modulePrefix: 'my-app', /* ... */ }; });

Slide 16

Slide 16 text

EMBER BUILD PIPELINE OUR ANSWER TO THE MISSING PIECES app/components/loading-spinner.js app/components/date-picker.js import Component from '@ember/component'; import task from 'ember-concurrency'; import moment from 'moment'; import ENV from 'my-app/config/environment'; export default class DatePicker extends Component { /* ... */ } dist/my-app.js /* ... */ define('my-app/components/loading-spinner', [], function() { /* ... */ }); define('my-app/components/date-picker', [ '@ember/component', 'ember-concurrency', 'moment', 'my-app/config/environment' ],function(Component, task, moment, ENV) { class DatePicker extends Component { /* ... */ } return DatePicker; }); define('my-app/config/environment', [], function () { return { environment: 'development', modulePrefix: 'my-app', /* ... */ }; });

Slide 17

Slide 17 text

EMBER BUILD PIPELINE OUR ANSWER TO THE MISSING PIECES app/components/loading-spinner.js app/components/date-picker.js import Component from '@ember/component'; import task from 'ember-concurrency'; import moment from 'moment'; import ENV from 'my-app/config/environment'; export default class DatePicker extends Component { /* ... */ } dist/my-app.js /* ... */ define('my-app/components/loading-spinner', [], function() { /* ... */ }); define('my-app/components/date-picker', [ '@ember/component', 'ember-concurrency', 'moment', 'my-app/config/environment' ],function(Component, task, moment, ENV) { class DatePicker extends Component { /* ... */ } return DatePicker; }); define('my-app/config/environment', [], function () { return { environment: 'development', modulePrefix: 'my-app', /* ... */ }; });

Slide 18

Slide 18 text

EMBER BUILD PIPELINE OUR ANSWER TO THE MISSING PIECES app/components/loading-spinner.js app/components/date-picker.js import Component from '@ember/component'; import task from 'ember-concurrency'; import moment from 'moment'; import ENV from 'my-app/config/environment'; export default class DatePicker extends Component { /* ... */ } dist/my-app.js /* ... */ define('my-app/components/loading-spinner', [], function() { /* ... */ }); define('my-app/components/date-picker', [ '@ember/component', 'ember-concurrency', 'moment', 'my-app/config/environment' ],function(Component, task, moment, ENV) { class DatePicker extends Component { /* ... */ } return DatePicker; }); define('my-app/config/environment', [], function () { return { environment: 'development', modulePrefix: 'my-app', /* ... */ }; });

Slide 19

Slide 19 text

EMBER BUILD PIPELINE OUR ANSWER TO THE MISSING PIECES app/components/loading-spinner.js app/components/date-picker.js import Component from '@ember/component'; import task from 'ember-concurrency'; import moment from 'moment'; import ENV from 'my-app/config/environment'; export default class DatePicker extends Component { /* ... */ } dist/my-app.js /* ... */ define('my-app/components/loading-spinner', [], function() { /* ... */ }); define('my-app/components/date-picker', [ '@ember/component', 'ember-concurrency', 'moment', 'my-app/config/environment' ],function(Component, task, moment, ENV) { class DatePicker extends Component { /* ... */ } return DatePicker; }); define('my-app/config/environment', [], function () { return { environment: 'development', modulePrefix: 'my-app', /* ... */ }; });

Slide 20

Slide 20 text

EMBER BUILD PIPELINE OUR ANSWER TO THE MISSING PIECES app/components/loading-spinner.js app/components/date-picker.js import Component from '@ember/component'; import task from 'ember-concurrency'; import moment from 'moment'; import ENV from 'my-app/config/environment'; export default class DatePicker extends Component { /* ... */ } dist/my-app.js /* ... */ define('my-app/components/loading-spinner', [], function() { /* ... */ }); define('my-app/components/date-picker', [ '@ember/component', 'ember-concurrency', 'moment', 'my-app/config/environment' ],function(Component, task, moment, ENV) { class DatePicker extends Component { /* ... */ } return DatePicker; }); define('my-app/config/environment', [], function () { return { environment: 'development', modulePrefix: 'my-app', /* ... */ }; });

Slide 21

Slide 21 text

EMBER BUILD PIPELINE OUR ANSWER TO THE MISSING PIECES app/components/loading-spinner.js app/components/date-picker.js import Component from '@ember/component'; import task from 'ember-concurrency'; import moment from 'moment'; import ENV from 'my-app/config/environment'; export default class DatePicker extends Component { /* ... */ } dist/my-app.js /* ... */ define('my-app/components/loading-spinner', [], function() { /* ... */ }); define('my-app/components/date-picker', [ '@ember/component', 'ember-concurrency', 'moment', 'my-app/config/environment' ],function(Component, task, moment, ENV) { class DatePicker extends Component { /* ... */ } return DatePicker; }); define('my-app/config/environment', [], function () { return { environment: 'development', modulePrefix: 'my-app', /* ... */ }; }); dist/vendor.js define('ember-concurrency', [ '@ember/application', '@ember/object', '@ember/object/computed', /* ... */ ], function () { /* ... */ }); define('moment', [], function () { /* ... */ }); define('@ember/application', [], function () { /* ... */ }); define('@ember/component', [], function () { /* ... */ }); define('@ember/object', [], function () { /* ... */

Slide 22

Slide 22 text

EMBER BUILD PIPELINE OUR ANSWER TO THE MISSING PIECES dist/my-app.js /* ... */ define('my-app/components/loading-spinner', [], function() { /* ... */ }); define('my-app/components/date-picker', [ '@ember/component', 'ember-concurrency', 'moment', 'my-app/config/environment' ],function(Component, task, moment, ENV) { class DatePicker extends Component { /* ... */ } return DatePicker; }); define('my-app/config/environment', [], function () { return { environment: 'development', modulePrefix: 'my-app', /* ... */ }; }); dist/vendor.js define('ember-concurrency', [ '@ember/application', '@ember/object', '@ember/object/computed', /* ... */ ], function () { /* ... */ }); define('moment', [], function () { /* ... */ }); define('@ember/application', [], function () { /* ... */ }); define('@ember/component', [], function () { /* ... */ }); define('@ember/object', [], function () { /* ... */ ember-concurrency ember-moment ember-source

Slide 23

Slide 23 text

EMBER BUILD PIPELINE OUR ANSWER TO THE MISSING PIECES dist/my-app.js /* ... */ define('my-app/components/loading-spinner', [], function() { /* ... */ }); define('my-app/components/date-picker', [ '@ember/component', 'ember-concurrency', 'moment', 'my-app/config/environment' ],function(Component, task, moment, ENV) { class DatePicker extends Component { /* ... */ } return DatePicker; }); define('my-app/config/environment', [], function () { return { environment: 'development', modulePrefix: 'my-app', /* ... */ }; }); dist/vendor.js define('ember-concurrency', [ '@ember/application', '@ember/object', '@ember/object/computed', /* ... */ ], function () { /* ... */ }); define('moment', [], function () { /* ... */ }); define('@ember/application', [], function () { /* ... */ }); define('@ember/component', [], function () { /* ... */ }); define('@ember/object', [], function () { /* ... */ ember-concurrency ember-moment ember-source

Slide 24

Slide 24 text

EMBER BUILD PIPELINE OUR ANSWER TO THE MISSING PIECES dist/my-app.js /* ... */ define('my-app/components/loading-spinner', [], function() { /* ... */ }); define('my-app/components/date-picker', [ '@ember/component', 'ember-concurrency', 'moment', 'my-app/config/environment' ],function(Component, task, moment, ENV) { class DatePicker extends Component { /* ... */ } return DatePicker; }); define('my-app/config/environment', [], function () { return { environment: 'development', modulePrefix: 'my-app', /* ... */ }; }); dist/vendor.js define('ember-concurrency', [ '@ember/application', '@ember/object', '@ember/object/computed', /* ... */ ], function () { /* ... */ }); define('moment', [], function () { /* ... */ }); define('@ember/application', [], function () { /* ... */ }); define('@ember/component', [], function () { /* ... */ }); define('@ember/object', [], function () { /* ... */ ember-concurrency ember-moment ember-source

Slide 25

Slide 25 text

EMBER BUILD PIPELINE OUR ANSWER TO THE MISSING PIECES dist/my-app.js /* ... */ define('my-app/components/loading-spinner', [], function() { /* ... */ }); define('my-app/components/date-picker', [ '@ember/component', 'ember-concurrency', 'moment', 'my-app/config/environment' ],function(Component, task, moment, ENV) { class DatePicker extends Component { /* ... */ } return DatePicker; }); define('my-app/config/environment', [], function () { return { environment: 'development', modulePrefix: 'my-app', /* ... */ }; }); dist/vendor.js define('ember-concurrency', [ '@ember/application', '@ember/object', '@ember/object/computed', /* ... */ ], function () { /* ... */ }); define('moment', [], function () { /* ... */ }); define('@ember/application', [], function () { /* ... */ }); define('@ember/component', [], function () { /* ... */ }); define('@ember/object', [], function () { /* ... */ ember-concurrency ember-moment ember-source

Slide 26

Slide 26 text

EMBER BUILD PIPELINE OUR ANSWER TO THE MISSING PIECES dist/my-app.js /* ... */ define('my-app/components/loading-spinner', [], function() { /* ... */ }); define('my-app/components/date-picker', [ '@ember/component', 'ember-concurrency', 'moment', 'my-app/config/environment' ],function(Component, task, moment, ENV) { class DatePicker extends Component { /* ... */ } return DatePicker; }); define('my-app/config/environment', [], function () { return { environment: 'development', modulePrefix: 'my-app', /* ... */ }; }); dist/vendor.js define('ember-concurrency', [ '@ember/application', '@ember/object', '@ember/object/computed', /* ... */ ], function () { /* ... */ }); define('moment', [], function () { /* ... */ }); define('@ember/application', [], function () { /* ... */ }); define('@ember/component', [], function () { /* ... */ }); define('@ember/object', [], function () { /* ... */ ember-concurrency ember-moment ember-source

Slide 27

Slide 27 text

EMBER BUILD PIPELINE OUR ANSWER TO THE MISSING PIECES dist/my-app.js /* ... */ define('my-app/components/loading-spinner', [], function() { /* ... */ }); define('my-app/components/date-picker', [ '@ember/component', 'ember-concurrency', 'moment', 'my-app/config/environment' ],function(Component, task, moment, ENV) { class DatePicker extends Component { /* ... */ } return DatePicker; }); define('my-app/config/environment', [], function () { return { environment: 'development', modulePrefix: 'my-app', /* ... */ }; }); dist/vendor.js define('ember-concurrency', [ '@ember/application', '@ember/object', '@ember/object/computed', /* ... */ ], function () { /* ... */ }); define('moment', [], function () { /* ... */ }); define('@ember/application', [], function () { /* ... */ }); define('@ember/component', [], function () { /* ... */ }); define('@ember/object', [], function () { /* ... */ ember-concurrency moment ember-source

Slide 28

Slide 28 text

PACKAGES HOW DO THEY WORK? import moment from 'moment'; window.require('moment'); dist/vendor.js define('ember-concurrency', [ '@ember/application', '@ember/object', '@ember/object/computed', /* ... */ ], function () { /* ... */ }); define('moment', [], function () { /* ... */ }); define('@ember/application', [], function () { /* ... */ }); define('@ember/component', [], function () { /* ... */ });

Slide 29

Slide 29 text

PACKAGES HOW DO THEY WORK? import moment from 'moment'; node_modules moment moment.js

Slide 30

Slide 30 text

NPM Registry package.json JavaScript Modules (ESM) Modern JavaScript Loose Modules Node Resolution Exports Maps TypeScript Types Dynamic import() Top-level Await import.meta Import Assertions Import Maps import.meta.resolve JSON Modules CSS Modules Constructable Stylesheets Web Bundles pnpm yarn npm webpack Rollup Parcel Vite Snowpack JSPM unpkg.com skypack.dev Workspaces Editors TypeScript GitHub Storybook Universal Package

Slide 31

Slide 31 text

NPM Registry package.json JavaScript Modules (ESM) Modern JavaScript Loose Modules Node Resolution Exports Maps TypeScript Types Dynamic import() Top-level Await import.meta Import Assertions Import Maps import.meta.resolve JSON Modules CSS Modules Constructable Stylesheets Web Bundles pnpm yarn npm webpack Rollup Parcel Vite Snowpack JSPM unpkg.com skypack.dev Workspaces Editors TypeScript GitHub Storybook Universal Package

Slide 32

Slide 32 text

POLARIS ALIGNING WITH MODERN PACKAGES

Slide 33

Slide 33 text

GUIDING PRINCIPLES ALIGNING WITH MODERN PACKAGES 1. Addons are universal packages 2. Imports are standard imports 3. Express dependencies as imports

Slide 34

Slide 34 text

ADDONS TODAY PUBLISHED AS DYNAMIC BUILD INSTRUCTIONS > _ ember build ember-concurrency ember-moment ember-source dist/vendor.js define('ember-concurrency', [ '@ember/application', '@ember/object', '@ember/object/computed', /* ... */ ], function () { /* ... */ }); define('moment', [], function () { /* ... */ }); define('@ember/application', [], function /* ... */ }); define('@ember/component', [], function ( /* ... */ }); define('@ember/object', [], function () { /* ... */ });

Slide 35

Slide 35 text

ADDONS TODAY PUBLISHED AS DYNAMIC BUILD INSTRUCTIONS > _ ember build ember-concurrency ember-moment ember-source dist/vendor.js define('ember-concurrency', [ '@ember/application', '@ember/object', '@ember/object/computed', /* ... */ ], function () { /* ... */ }); define('moment', [], function () { /* ... */ }); define('@ember/application', [], function /* ... */ }); define('@ember/component', [], function ( /* ... */ }); define('@ember/object', [], function () { /* ... */ });

Slide 36

Slide 36 text

ADDONS TODAY PUBLISHED AS DYNAMIC BUILD INSTRUCTIONS > _ ember build ember-concurrency ember-moment ember-source dist/vendor.js define('ember-concurrency', [ '@ember/application', '@ember/object', '@ember/object/computed', /* ... */ ], function () { /* ... */ }); define('moment', [], function () { /* ... */ }); define('@ember/application', [], function /* ... */ }); define('@ember/component', [], function ( /* ... */ }); define('@ember/object', [], function () { /* ... */ });

Slide 37

Slide 37 text

ADDONS TODAY PUBLISHED AS DYNAMIC BUILD INSTRUCTIONS > _ ember build ember-concurrency ember-moment ember-source dist/vendor.js define('ember-concurrency', [ '@ember/application', '@ember/object', '@ember/object/computed', /* ... */ ], function () { /* ... */ }); define('moment', [], function () { /* ... */ }); define('@ember/application', [], function /* ... */ }); define('@ember/component', [], function ( /* ... */ }); define('@ember/object', [], function () { /* ... */ });

Slide 38

Slide 38 text

ADDONS IN POLARIS PUBLISHED AS UNIVERSAL PACKAGES https://emberjs.github.io/rfcs/0507-embroider-v2-package-format.html Universal Packages NPM Registry package.json JavaScript Modules (ESM) “Modern” JavaScript Features Node Resolution Exports Maps TypeScript Types

Slide 39

Slide 39 text

ADDONS IN POLARIS PUBLISHED AS UNIVERSAL PACKAGES > _ npm publish ember-concurrency .npmignore package.json tsconfig.json index.ts

Slide 40

Slide 40 text

ADDONS IN POLARIS PUBLISHED AS UNIVERSAL PACKAGES > _ npm publish tsc ember-concurrency .npmignore package.json tsconfig.json index.ts

Slide 41

Slide 41 text

ADDONS IN POLARIS PUBLISHED AS UNIVERSAL PACKAGES ember-concurrency package.json index.js index.d.ts ember-concurrency .npmignore package.json tsconfig.json index.ts > _ npm publish

Slide 42

Slide 42 text

GUIDING PRINCIPLES ALIGNING WITH MODERN PACKAGES 1. Addons are universal packages 2. Imports are standard imports 3. Express dependencies as imports

Slide 43

Slide 43 text

STANDARD IMPORTS NODE PACKAGE RESOLUTION import uniq from 'lodash/uniq';

Slide 44

Slide 44 text

STANDARD IMPORTS NODE PACKAGE RESOLUTION import uniq from 'lodash/uniq'; package.json { "name": "my-app", /* ... */ "devDependencies": { "lodash": "^4.0.0" /* ... */ } }

Slide 45

Slide 45 text

STANDARD IMPORTS NODE PACKAGE RESOLUTION import uniq from 'lodash/uniq'; node_modules lodash uniq.js

Slide 46

Slide 46 text

STANDARD IMPORTS NODE PACKAGE RESOLUTION import uniq from 'lodash/uniq'; import task from 'ember-concurrency'; package.json { "name": "my-app", /* ... */ "devDependencies": { "ember-concurrency": "^2.2.1" /* ... */ } }

Slide 47

Slide 47 text

STANDARD IMPORTS NODE PACKAGE RESOLUTION import uniq from 'lodash/uniq'; import task from 'ember-concurrency'; node_modules ember-concurrency index.js

Slide 48

Slide 48 text

STANDARD IMPORTS NODE PACKAGE RESOLUTION import uniq from 'lodash/uniq'; import task from 'ember-concurrency'; import { timeout } from 'ember-concurrency/utils'; // ERROR! import nope from 'ember-concurrency/private'; package.json { "name": "ember-concurrency", /* ... */ "exports": { ".": "./src/index.js", "./utils": "./src/concurrency-utils.js" } } Using exports Map https://nodejs.org/api/packages.html#subpath-exports

Slide 49

Slide 49 text

No content

Slide 50

Slide 50 text

EMBROIDER A NEW BUILD PIPELINE? Powered By > _ ember build my-app Bundles

Slide 51

Slide 51 text

EMBROIDER A NEW BUILD ARCHITECTURE Powered By > _ ember build ember-concurrency ember-moment ember-source my-app Bundles

Slide 52

Slide 52 text

EMBROIDER A NEW BUILD ARCHITECTURE Powered By > _ ember build ember-concurrency ember-moment ember-source my-app Bundles

Slide 53

Slide 53 text

TREE SHAKING LAZY DEPENDENCY INCLUSION node_modules ember-concurrency index.js lodash unescape.js union.js unionBy.js unionWith.js uniq.js unionBy.js unionWith.js

Slide 54

Slide 54 text

TREE SHAKING LAZY DEPENDENCY INCLUSION node_modules ember-concurrency index.js lodash unescape.js union.js unionBy.js unionWith.js uniq.js unionBy.js unionWith.js app.js

Slide 55

Slide 55 text

TREE SHAKING LAZY DEPENDENCY INCLUSION node_modules ember-concurrency index.js lodash unescape.js union.js unionBy.js unionWith.js uniq.js unionBy.js unionWith.js app.js import task from 'ember-concurrency';

Slide 56

Slide 56 text

TREE SHAKING LAZY DEPENDENCY INCLUSION node_modules ember-concurrency index.js lodash unescape.js union.js unionBy.js unionWith.js uniq.js unionBy.js unionWith.js app.js import task from 'ember-concurrency'; import uniq from 'lodash/uniq';

Slide 57

Slide 57 text

TREE SHAKING LAZY DEPENDENCY INCLUSION node_modules ember-concurrency index.js lodash unescape.js union.js unionBy.js unionWith.js uniq.js unionBy.js unionWith.js app.js import task from 'ember-concurrency'; import uniq from 'lodash/uniq'; import Tracker from './utils/tracker';

Slide 58

Slide 58 text

TREE SHAKING LAZY DEPENDENCY INCLUSION node_modules ember-concurrency index.js lodash unescape.js union.js unionBy.js unionWith.js uniq.js unionBy.js unionWith.js app.js import task from 'ember-concurrency'; import uniq from 'lodash/uniq'; import Tracker from './utils/tracker'; utils/tracker.js

Slide 59

Slide 59 text

TREE SHAKING LAZY DEPENDENCY INCLUSION node_modules ember-concurrency index.js lodash unescape.js union.js unionBy.js unionWith.js uniq.js unionBy.js unionWith.js app.js import task from 'ember-concurrency'; import uniq from 'lodash/uniq'; import Tracker from './utils/tracker'; utils/tracker.js import union from 'lodash/union';

Slide 60

Slide 60 text

EMBROIDER A NEW BUILD ARCHITECTURE Outsourced To Powered By > _ ember build my-app Bundles

Slide 61

Slide 61 text

EMBROIDER A PLUGGABLE BUILD ARCHITECTURE Outsourced To Powered By > _ ember build my-app Bundles

Slide 62

Slide 62 text

GUIDING PRINCIPLES ALIGNING WITH MODERN PACKAGES 1. Addons are universal packages 2. Imports are standard imports 3. Express dependencies as imports

Slide 63

Slide 63 text

TREE SHAKING TODAY COULD IT BE DONE? dist/vendor.js define('ember-concurrency', [ '@ember/application', '@ember/object', '@ember/object/computed', /* ... */ ], function () { /* ... */ }); define('moment', [], function () { /* ... */ }); define('@ember/application', [], function () { /* ... */ }); define('@ember/component', [], function () { /* ... */ }); define('@ember/object', [], function () { /* ... */ }); dist/my-app.js /* ... */ define('my-app/components/loading-spinner', [], function() { /* ... */ }); define('my-app/components/date-picker', [ '@ember/component', 'ember-concurrency', 'moment', 'my-app/config/environment' ],function(Component, task, moment, ENV) { class DatePicker extends Component { /* ... */ } return DatePicker; }); define('my-app/config/environment', [], function () { return { environment: 'development', modulePrefix: 'my-app', /* ... */ }; });

Slide 64

Slide 64 text

TREE SHAKING TODAY COULD IT BE DONE? dist/vendor.js define('ember-concurrency', [ '@ember/application', '@ember/object', '@ember/object/computed', /* ... */ ], function () { /* ... */ }); define('moment', [], function () { /* ... */ }); define('@ember/application', [], function () { /* ... */ }); define('@ember/component', [], function () { /* ... */ }); define('@ember/object', [], function () { /* ... */ }); dist/my-app.js /* ... */ define('my-app/components/loading-spinner', [], function() { /* ... */ }); define('my-app/components/date-picker', [ '@ember/component', 'ember-concurrency', 'moment', 'my-app/config/environment' ],function(Component, task, moment, ENV) { class DatePicker extends Component { /* ... */ } return DatePicker; }); define('my-app/config/environment', [], function () { return { environment: 'development', modulePrefix: 'my-app', /* ... */ }; });

Slide 65

Slide 65 text

TREE SHAKING TODAY COULD IT BE DONE? app/router.js import EmberRouter from '@ember/routing/router'; export default class Router extends EmberRouter {} Router.map(function () { this.route('post'); });

Slide 66

Slide 66 text

TREE SHAKING TODAY COULD IT BE DONE? app/router.js import EmberRouter from '@ember/routing/router'; export default class Router extends EmberRouter {} Router.map(function () { this.route('post'); }); app/controllers/post.js import Controller from '@ember/controller'; export default class PostController extends Controller { /* ... */ } app/routes/post.js import Route from '@ember/routing/route'; import { service } from '@ember/service'; export default class PostRoute extends Route { @service store; async model(params) { this.store.find('post', params.post_id); } }

Slide 67

Slide 67 text

TREE SHAKING TODAY COULD IT BE DONE? app/router.js import EmberRouter from '@ember/routing/router'; export default class Router extends EmberRouter {} Router.map(function () { this.route('post'); }); app/controllers/post.js import Controller from '@ember/controller'; export default class PostController extends Controller { /* ... */ } app/routes/post.js import Route from '@ember/routing/route'; import { service } from '@ember/service'; export default class PostRoute extends Route { @service store; async model(params) { this.store.find('post', params.post_id); } }

Slide 68

Slide 68 text

EMBROIDER ENCODING EMBER CONVENTIONS Outsourced To Powered By my-app Bundles my-app

Slide 69

Slide 69 text

BAD IDEA

Slide 70

Slide 70 text

TEMPLATES TODAY NAME BASED RESOLUTIONS app/components/welcome.hbs Hello there, welcome back!

Slide 71

Slide 71 text

TEMPLATES TODAY NAME BASED RESOLUTIONS app/components/welcome.hbs Hi there, welcome back! Rendering a component named "hello" RFC #311

Slide 72

Slide 72 text

TEMPLATES TODAY NAME BASED RESOLUTIONS app/components/welcome.hbs Hi there, welcome back! Rendering a component named "hello" Step 1. Find the component RFC #311

Slide 73

Slide 73 text

TEMPLATES TODAY NAME BASED RESOLUTIONS app/components/welcome.hbs Hi there, welcome back! Rendering a component named "hello" Step 1. Find the component owner.factoryFor("component:hello"); RFC #311

Slide 74

Slide 74 text

TEMPLATES TODAY NAME BASED RESOLUTIONS app/components/welcome.hbs Hi there, welcome back! Rendering a component named "hello" Step 1. Find the component owner.factoryFor("component:hello"); require("my-app/components/hello"); RFC #311 ember-resolver

Slide 75

Slide 75 text

TEMPLATES TODAY NAME BASED RESOLUTIONS app/components/welcome.hbs Hi there, welcome back! Rendering a component named "hello" Step 1. Find the component owner.factoryFor("component:hello"); require("my-app/components/hello"); (load the AMD module from app bundle) RFC #311 ember-resolver loader.js

Slide 76

Slide 76 text

TEMPLATES TODAY NAME BASED RESOLUTIONS app/components/welcome.hbs Hi there, welcome back! Rendering a component named "hello" Step 1. Find the component owner.factoryFor("component:hello"); require("my-app/components/hello"); (load the AMD module from app bundle) Step 2. Setup the component Manager = getComponentManager(Hello); Template = getComponentTemplate(Hello); C = Manager.createComponent(Hello, Args); This = Manager.getContext(C); Step 3. Render render(Template, This, Args); document.createElement(!!"), etc RFC #311 ember-resolver loader.js RFC #213 Component Manager RFC #481 Co-location glimmer-vm

Slide 77

Slide 77 text

TEMPLATES TODAY NAME BASED RESOLUTIONS app/components/welcome.hbs Hi there, welcome back! Rendering a component named "hello" Step 1. Find the component owner.factoryFor("component:hello"); require("my-app/components/hello"); (load the AMD module from app bundle) Step 2. Setup the component Manager = getComponentManager(Hello); Template = getComponentTemplate(Hello); C = Manager.createComponent(Hello, Args); This = Manager.getContext(C); Step 3. Render render(Template, This, Args); document.createElement(!!"), etc RFC #311 ember-resolver loader.js RFC #213 Component Manager RFC #481 Co-location glimmer-vm

Slide 78

Slide 78 text

TEMPLATES TODAY NAME BASED RESOLUTIONS app/components/welcome.hbs Hi there, welcome back! Rendering a component named "hello" Step 1. Find the component owner.factoryFor("component:hello"); require("my-app/components/hello"); (load the AMD module from app bundle) Step 2. Setup the component Manager = getComponentManager(Hello); Template = getComponentTemplate(Hello); C = Manager.createComponent(Hello, Args); This = Manager.getContext(C); Step 3. Render render(Template, This, Args); document.createElement(!!"), etc RFC #311 ember-resolver loader.js RFC #213 Component Manager RFC #481 Co-location glimmer-vm

Slide 79

Slide 79 text

TEMPLATES TODAY NAME BASED RESOLUTIONS app/components/welcome.hbs Hi there, welcome back! {{log Hello}} ~~~~~ Error. Hello is not a value! Rendering a component named "hello" Step 1. Find the component owner.factoryFor("component:hello"); require("my-app/components/hello"); (load the AMD module from app bundle) Step 2. Setup the component Manager = getComponentManager(Hello); Template = getComponentTemplate(Hello); C = Manager.createComponent(Hello, Args); This = Manager.getContext(C); Step 3. Render render(Template, This, Args); document.createElement(!!"), etc RFC #311 ember-resolver loader.js RFC #213 Component Manager RFC #481 Co-location glimmer-vm

Slide 80

Slide 80 text

TEMPLATES TODAY NAME BASED RESOLUTIONS app/components/welcome.hbs Hi there, welcome back! {{!-- Works. Hello is a value! --}} {{log Hello}} Rendering the value Hello as a component Step 1. Find the component owner.factoryFor("component:hello"); require("my-app/components/hello"); (load the AMD module from app bundle) Step 2. Setup the component Manager = getComponentManager(Hello); Template = getComponentTemplate(Hello); C = Manager.createComponent(Hello, Args); This = Manager.getContext(C); Step 3. Render render(Template, This, Args); document.createElement(!!"), etc RFC #64 Contextual Components ember-resolver loader.js RFC #213 Component Manager RFC #481 Co-location glimmer-vm Skipped!

Slide 81

Slide 81 text

TEMPLATES IN POLARIS VALUES EVERYWHERE app/components/welcome.gjs import Hello from 'my-app/components/hello'; Hi there, welcome back! {{!-- Works. Hello is a value! --}} {{log Hello}} RFC #373 Modifier Manager RFC #432 Contextual Helpers/Modifiers RFC #496 Strict Mode Templates Refactor Handlebars parser and glimmer-vm RFC #625 Helper Manager RFC #756 Default Helper Manager RFC #779

Slide 82

Slide 82 text

TEMPLATES IN POLARIS VALUES EVERYWHERE app/components/welcome.gjs import Hello from 'my-app/components/hello'; Hi there, welcome back! {{!-- Works. Hello is a value! --}} {{log Hello}} RFC #373 Modifier Manager RFC #432 Contextual Helpers/Modifiers RFC #496 Strict Mode Templates Refactor Handlebars parser and glimmer-vm RFC #625 Helper Manager RFC #756 Default Helper Manager RFC #779

Slide 83

Slide 83 text

TEMPLATES IN POLARIS VALUES EVERYWHERE app/components/welcome.gjs import Hello from 'my-app/components/hello'; // Same value inside and outside the template console.log(Hello); Hi there, welcome back! {{!-- Works. Hello is a value! --}} {{log Hello}} RFC #373 Modifier Manager RFC #432 Contextual Helpers/Modifiers RFC #496 Strict Mode Templates Refactor Handlebars parser and glimmer-vm RFC #625 Helper Manager RFC #756 Default Helper Manager RFC #779

Slide 84

Slide 84 text

TEMPLATES IN POLARIS VALUES EVERYWHERE app/components/welcome.gjs import Hello from 'my-app/components/hello'; const GREETING = 'Hi there'; {{GREETING}}, welcome back! RFC #373 Modifier Manager RFC #432 Contextual Helpers/Modifiers RFC #496 Strict Mode Templates Refactor Handlebars parser and glimmer-vm RFC #625 Helper Manager RFC #756 Default Helper Manager RFC #779

Slide 85

Slide 85 text

TEMPLATES IN POLARIS VALUES EVERYWHERE app/components/welcome.gjs import Hello from 'my-app/components/hello'; /** * Randomly chosen a value for the given choices. */ function sample(...choices) { let i = Math.floor(Math.random() * choices.length); return choices[i]; } Hi there, welcome back! {{sample 'You won a prize!' 'Better luck next time!'}} RFC #373 Modifier Manager RFC #432 Contextual Helpers/Modifiers RFC #496 Strict Mode Templates Refactor Handlebars parser and glimmer-vm RFC #625 Helper Manager RFC #756 Default Helper Manager RFC #779

Slide 86

Slide 86 text

TEMPLATES IN POLARIS VALUES EVERYWHERE app/components/welcome.gjs import Hello from 'my-app/components/hello'; import sample from 'my-app/helpers/sample'; Hi there, welcome back! {{sample 'You won a prize!' 'Better luck next time!'}} RFC #373 Modifier Manager RFC #432 Contextual Helpers/Modifiers RFC #496 Strict Mode Templates Refactor Handlebars parser and glimmer-vm RFC #625 Helper Manager RFC #756 Default Helper Manager RFC #779

Slide 87

Slide 87 text

TEMPLATES IN POLARIS VALUES EVERYWHERE app/components/welcome.gjs import Hello from 'my-app/components/hello'; import sample from 'lodash/sample'; import { array } from '@ember/helper'; Hi there, welcome back! {{sample (array 'You won a prize!' 'Better luck next time!' )}} RFC #373 Modifier Manager RFC #432 Contextual Helpers/Modifiers RFC #496 Strict Mode Templates Refactor Handlebars parser and glimmer-vm RFC #625 Helper Manager RFC #756 Default Helper Manager RFC #779

Slide 88

Slide 88 text

TEMPLATES IN POLARIS VALUES EVERYWHERE app/components/welcome.gjs import Component from '@glimmer/component'; import { tracked } from '@glimmer/tracking'; import { action } from '@ember/object'; import Hello from 'my-app/components/hello'; import sample from 'lodash/sample'; export default class Welcome extends Component { @tracked result = this.lottery(); @action retry() { this.result = this.lottery(); } lottery() { return sample(['You won a prize!', 'Better luck next time!']); } Hi there, welcome back! {{this.result}} } RFC #373 Modifier Manager RFC #432 Contextual Helpers/Modifiers RFC #496 Strict Mode Templates Refactor Handlebars parser and glimmer-vm RFC #625 Helper Manager RFC #756 Default Helper Manager RFC #779

Slide 89

Slide 89 text

TANGENT Is this!!" JSX?!

Slide 90

Slide 90 text

TANGENT

Slide 91

Slide 91 text

GUIDING PRINCIPLES ALIGNING WITH MODERN PACKAGES 1. Addons are universal packages 2. Imports are standard imports 3. Express dependencies as imports

Slide 92

Slide 92 text

POLARIS HOW DO WE GET THERE?

Slide 93

Slide 93 text

No content

Slide 94

Slide 94 text

No content

Slide 95

Slide 95 text

No content

Slide 96

Slide 96 text

No content

Slide 97

Slide 97 text

Blueprints POLARIS Deprecations Migration Guides Codemods Guides Tutorial Blog Posts Outreach Best Practices Bug Reports Examples Primitives High-level Features Lint Rules Paradigms Patterns Cookbooks Discussions Talks Experience Reports Abstractions Tools Libraries Integrations Ember Inspector RFCs