Skip to content

Commit

Permalink
Merge pull request #11338 from emberjs/glimmer-optimizations
Browse files Browse the repository at this point in the history
Glimmer optimizations
  • Loading branch information
rwjblue committed Jun 4, 2015
2 parents e89dc6d + d1d993d commit 308ca40
Show file tree
Hide file tree
Showing 12 changed files with 116 additions and 35 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"express": "^4.5.0",
"github": "^0.2.3",
"glob": "~4.3.2",
"htmlbars": "0.13.22",
"htmlbars": "0.13.25",
"qunit-extras": "^1.3.0",
"qunitjs": "^1.16.0",
"route-recognizer": "0.1.5",
Expand Down
3 changes: 1 addition & 2 deletions packages/ember-htmlbars/lib/hooks/component.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ export default function componentHook(renderNode, env, scope, _tagName, params,
isAngleBracket = true;
}

var read = env.hooks.getValue;
var parentView = read(scope.view);
var parentView = env.view;

var manager = ComponentNodeManager.create(renderNode, env, {
tagName,
Expand Down
4 changes: 2 additions & 2 deletions packages/ember-htmlbars/lib/keywords/real_outlet.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ export default {
return { outletState: selectedOutletState, hasParentOutlet: env.hasParentOutlet };
},

childEnv(state) {
return { outletState: state.outletState && state.outletState.outlets, hasParentOutlet: true };
childEnv(state, env) {
return env.childWithOutletState(state.outletState && state.outletState.outlets, true);
},

isStable(lastState, nextState) {
Expand Down
2 changes: 2 additions & 0 deletions packages/ember-htmlbars/lib/morphs/attr-morph.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ export var styleWarning = '' +

function EmberAttrMorph(element, attrName, domHelper, namespace) {
HTMLBarsAttrMorph.call(this, element, attrName, domHelper, namespace);

this.streamUnsubscribers = null;
}

var proto = EmberAttrMorph.prototype = o_create(HTMLBarsAttrMorph.prototype);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,7 @@ ComponentNodeManager.prototype.render = function(_env, visitor) {
var { component, attrs } = this;

return instrument(component, function() {
let env = _env;

env = assign({ view: component }, env);
let env = _env.childWithView(component);

var snapshot = takeSnapshot(attrs);
env.renderer.componentInitAttrs(this.component, snapshot);
Expand Down Expand Up @@ -210,7 +208,7 @@ ComponentNodeManager.prototype.rerender = function(_env, attrs, visitor) {
var snapshot = takeSnapshot(attrs);

if (component._renderNode.shouldReceiveAttrs) {
env.renderer.componentUpdateAttrs(component, component.attrs, snapshot);
env.renderer.componentUpdateAttrs(component, snapshot);

if (!component._isAngleBracket) {
setProperties(component, mergeBindings({}, shadowedAttrs(component, snapshot)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,7 @@ ViewNodeManager.prototype.render = function(env, attrs, visitor) {

var newEnv = env;
if (component) {
newEnv = merge({}, env);
newEnv.view = component;
newEnv = env.childWithView(component);
}

if (component) {
Expand Down Expand Up @@ -124,8 +123,7 @@ ViewNodeManager.prototype.rerender = function(env, attrs, visitor) {
return instrument(component, function() {
var newEnv = env;
if (component) {
newEnv = merge({}, env);
newEnv.view = component;
newEnv = env.childWithView(component);

var snapshot = takeSnapshot(attrs);

Expand Down
56 changes: 56 additions & 0 deletions packages/ember-htmlbars/lib/system/render-env.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import defaultEnv from "ember-htmlbars/env";

export default function RenderEnv(options) {
this.lifecycleHooks = options.lifecycleHooks || [];
this.renderedViews = options.renderedViews || [];
this.renderedNodes = options.renderedNodes || {};
this.hasParentOutlet = options.hasParentOutlet || false;

this.view = options.view;
this.outletState = options.outletState;
this.container = options.container;
this.renderer = options.renderer;
this.dom = options.dom;

this.hooks = defaultEnv.hooks;
this.helpers = defaultEnv.helpers;
this.useFragmentCache = defaultEnv.useFragmentCache;
}

RenderEnv.build = function(view) {
return new RenderEnv({
view: view,
outletState: view.outletState,
container: view.container,
renderer: view.renderer,
dom: view.renderer._dom
});
};

RenderEnv.prototype.childWithView = function(view) {
return new RenderEnv({
view: view,
outletState: this.outletState,
container: this.container,
renderer: this.renderer,
dom: this.dom,
lifecycleHooks: this.lifecycleHooks,
renderedViews: this.renderedViews,
renderedNodes: this.renderedNodes,
hasParentOutlet: this.hasParentOutlet
});
};

RenderEnv.prototype.childWithOutletState = function(outletState, hasParentOutlet=this.hasParentOutlet) {
return new RenderEnv({
view: this.view,
outletState: outletState,
container: this.container,
renderer: this.renderer,
dom: this.dom,
lifecycleHooks: this.lifecycleHooks,
renderedViews: this.renderedViews,
renderedNodes: this.renderedNodes,
hasParentOutlet: hasParentOutlet
});
};
16 changes: 2 additions & 14 deletions packages/ember-htmlbars/lib/system/render-view.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,10 @@
import defaultEnv from "ember-htmlbars/env";
import ViewNodeManager, { createOrUpdateComponent } from "ember-htmlbars/node-managers/view-node-manager";
import RenderEnv from "ember-htmlbars/system/render-env";

// This function only gets called once per render of a "root view" (`appendTo`). Otherwise,
// HTMLBars propagates the existing env and renders templates for a given render node.
export function renderHTMLBarsBlock(view, block, renderNode) {
var env = {
lifecycleHooks: [],
renderedViews: [],
renderedNodes: {},
view: view,
outletState: view.outletState,
container: view.container,
renderer: view.renderer,
dom: view.renderer._dom,
hooks: defaultEnv.hooks,
helpers: defaultEnv.helpers,
useFragmentCache: defaultEnv.useFragmentCache
};
var env = RenderEnv.build(view);

view.env = env;
createOrUpdateComponent(view, {}, null, renderNode, env);
Expand Down
13 changes: 11 additions & 2 deletions packages/ember-metal-views/lib/renderer.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import run from "ember-metal/run_loop";
import { get } from "ember-metal/property_get";
import { set } from "ember-metal/property_set";
import { assign } from "ember-metal/merge";
import setProperties from "ember-metal/set_properties";
import buildComponentTemplate from "ember-views/system/build-component-template";
import { indexOf } from "ember-metal/enumerable_utils";
//import { deprecation } from "ember-views/compat/attrs-proxy";
Expand Down Expand Up @@ -161,8 +163,15 @@ Renderer.prototype.updateAttrs = function (view, attrs) {
this.setAttrs(view, attrs);
}; // setting new attrs

Renderer.prototype.componentUpdateAttrs = function (component, oldAttrs, newAttrs) {
set(component, 'attrs', newAttrs);
Renderer.prototype.componentUpdateAttrs = function (component, newAttrs) {
let oldAttrs = null;

if (component.attrs) {
oldAttrs = assign({}, component.attrs);
setProperties(component.attrs, newAttrs);
} else {
set(component, 'attrs', newAttrs);
}

component.trigger('didUpdateAttrs', { oldAttrs, newAttrs });
component.trigger('didReceiveAttrs', { oldAttrs, newAttrs });
Expand Down
7 changes: 5 additions & 2 deletions packages/ember-metal/lib/merge.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,11 @@ export function assign(original, ...args) {
let arg = args[i];
if (!arg) { continue; }

for (let prop in arg) {
if (arg.hasOwnProperty(prop)) { original[prop] = arg[prop]; }
let updates = keys(arg);

for (let i=0, l=updates.length; i<l; i++) {
let prop = updates[i];
original[prop] = arg[prop];
}
}

Expand Down
4 changes: 2 additions & 2 deletions packages/ember-routing-htmlbars/lib/keywords/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ export default {
};
},

childEnv(state) {
return { outletState: state.childOutletState };
childEnv(state, env) {
return env.childWithOutletState(state.childOutletState);
},

isStable(lastState, nextState) {
Expand Down
32 changes: 30 additions & 2 deletions packages/ember/tests/component_registration_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import "ember";

import compile from "ember-template-compiler/system/compile";
import helpers from "ember-htmlbars/helpers";
import { OutletView } from "ember-routing-views/views/outlet";

var App, registry, container;
var originalHelpers;
Expand Down Expand Up @@ -40,7 +41,7 @@ QUnit.module("Application Lifecycle - Component Registration", {
teardown: cleanup
});

function boot(callback) {
function boot(callback, startURL="/") {
Ember.run(function() {
App = Ember.Application.create({
name: 'App',
Expand All @@ -63,7 +64,7 @@ function boot(callback) {

Ember.run(App, 'advanceReadiness');
Ember.run(function() {
router.handleURL('/');
router.handleURL(startURL);
});
}

Expand Down Expand Up @@ -348,3 +349,30 @@ QUnit.test("Components trigger actions in the components context when called fro

Ember.$('#fizzbuzz', "#wrapper").click();
});

QUnit.test("Components receive the top-level view as their ownerView", function(assert) {
Ember.TEMPLATES.application = compile("{{outlet}}");
Ember.TEMPLATES.index = compile("{{my-component}}");
Ember.TEMPLATES['components/my-component'] = compile('<div></div>');

let component;

boot(function() {
registry.register('component:my-component', Ember.Component.extend({
init() {
this._super();
component = this;
}
}));
});

// Theses tests are intended to catch a regression where the owner view was
// not configured properly. Future refactors may break these tests, which
// should not be considered a breaking change to public APIs.
let ownerView = component.ownerView;
assert.ok(ownerView, "owner view was set");
assert.ok(ownerView instanceof OutletView, "owner view has no parent view");
assert.notStrictEqual(component, ownerView, "owner view is not itself");

assert.ok(ownerView._outlets, "owner view has an internal array of outlets");
});

0 comments on commit 308ca40

Please sign in to comment.