Node + Ember
Dean Sofer
Follow Along: slides.com/ProLoser/node-plus-ember/live
whois dean sofer?
- Github.com/ProLoser
- Señor Engineer at Sony
- Founder of AngularUI
- Started on CakePHP/jQuery
- Playstation Vue Architect
- Glorious mustache proprietor
Wise Man Says
- API design === User Experience Design
- Refactor-friendly FTW
- Composition over Convention
- Obfuscation for its own sake is evil
- Pretend everything is public
- Expect the unexpected
Node First
- The library is node first, everything else second
- Node packages and standards increase compatibility
- Ember has a very specific and opinionated API
- Core library is written without knowledge of Ember
ES6 in Node.js
- Native ES6 support with 'use strict'
- Easier development / debugging
- See node.green for details
- Compiled source tree for most
- BUT DON'T BUNDLE NODE CODE!
Bundling Antipattern
Redundant bundling breaks tree-shaking
- Redundant libraries
- Bigger filesize
- Debugging is much harder
- Complicated dependency upgrades
App
- Dependency B
- Library(A+B)
App(B+Library(A+B))
Library
- Dependency A
- Dependency B
Library(A+B)
bundle
library
bundle
app
Compiled Tree
/*** core-library/package.json ***/
{
...
"main": "compiled/index.js",
"dependencies": {
"babel-preset-es2015": "^6.6.0",
"babel": "^6.5.2"
}
}
/*** core-library/.babelrc ***/
{
"presets": [
"es2015"
]
}
Save the trees!
- Files are local, unlike websites
- Files are smaller
- Building is faster (and incremental)
Node in Ember
- Ember recommended solution
- Bower is dying. Long live Browserify!
- Namespaced imports "npm:core-library"
- Browserify can compile too
?
Compiling Antipattern
DON'T double compile your code
es6
compile
compile
watchers
sourcemaps
es5
bundled
waiting
watchers
waiting
sourcemaps
build tool A
build tool B
Targetting Clients
/*** core-library/package.json ***/
{
...
"browser": "src/index.js",
"browserify": {
"transform": [
"babelify"
]
},
"dependencies": {
...
"babel-preset-es2015": "^6.6.0",
"babelify": "^7.2.0"
}
}
/*** core-library/.babelrc ***/
{
"presets": [
"es2015"
]
}
es6
es5 bundled
browserify
Separating Concerns
- What can I do without Ember?
- Classes
- Queries
- Reads
- Utilities
- What must I do with Ember?
- Rendering
- Ember.set()
- Function.property()
Show me
the Code
/*** core-library/Base.js ***/
class Base {
constructor(data) {
Object.assign(this, data);
}
}
module.exports = Base;
/*** core-library/Project.js ***/
const Base = require('./Base');
const Task = require('./Task');
class Project extends Base {
static get(id) {
return query(`/projects/${id}`).then( project =>
new Project( project );
);
}
constructor(data) {
super(data);
this.tasks = this.tasks.map( task =>
new Task( task )
);
}
isComplete() {
return this.tasks.every( task =>
task.completed
);
}
}
module.exports = Project;
But Ember-Data!
- Ember-Data doesn't work for everything
- Want to use business logic outside of Ember
- We have a terrible server API
- Easy to roll our own with ES6
- Code is transparent and refactor friendly
ember Wrapper
/*** my-addon ***/
import CoreLibrary from 'npm:core-library';
import Ember from 'ember';
const Base = CoreLibrary.Base;
// Monkey-patch CoreLibrary with Ember utils
Base.prototype.set = function(property, value) {
return Ember.set(this, property, value);
};
Base.prototype.get = function(property) {
return Ember.get(this, property);
};
// Configure environment for Ember statically
CoreLibrary.setPromiseLibrary(Ember.RSVP.Promise);
CoreLibrary.configure({ ... });
// Or create Ember configured instance
export default new CoreLibrary({ ... });
- Ember addon for core library
- Handles installation
- Handles dependencies
- Handles library configuration
- Adds Ember-specific logic
- NOT an alias for core library
Ember Wrapper Setup
/*** my-addon/package.json ***/
{
...
"peerDependencies": {
"ember-browserify": "^1.1.8",
"my-node-library": "^1.0.0"
}
}
/*** my-addon/blueprints/my-addon/index.js ***/
module.exports = {
...
afterInstall: function(options) {
return this.addPackagesToProject([
{ name: 'ember-browserify' },
{ name: 'my-node-library' }
]);
}
};
my-app/
node_modules/
ember-browserify/
my-addon/
addon/
index.js
app/
dependencies.js
blueprints/
my-addon/
index.js
core-library/
library.js
package.json
node_modules/
babelify/
babel-preset-es2015/
/*** my-addon/addon/index.js ***/
import CoreLibrary from 'npm:core-library';
...
/*** my-addon/app/dependencies.js ***/
import coreLibrary from 'npm:core-library';
// Informs ember-cli of npm:core-library
// This file never gets executed
Ready to Use
/*** my-app ***/
import CoreLibrary from 'npm:core-library';
import coreLibrary from 'my-addon';
CoreLibrary.Project.get(123).then( project =>
project.set('name', 'Presentation');
);
coreLibrary.Project.get(123).then( ... )
ember install my-addon
mind = blown
FEEN
Node + Ember
By Dean Sofer
Node + Ember
Presentation video: https://youtu.be/kmRsjnTZXpE Additional notes: https://github.com/ProLoser/node-to-embe
- 2,526