Skip to content
This repository has been archived by the owner on Jan 22, 2020. It is now read-only.

Commit

Permalink
added performance profiling support
Browse files Browse the repository at this point in the history
  • Loading branch information
samsel committed May 1, 2015
1 parent 28530e1 commit e91ebc2
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 3 deletions.
2 changes: 1 addition & 1 deletion .jshintrc
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"maxlen": 120,

// Require capitalized names for constructor functions.
"newcap": true,
"newcap": false,

// Enforce use of single quotation marks for strings.
"quotmark": "single",
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 1.3.0 (April 30, 2015)

* added Performance profiling

## 1.2.0 (April 25, 2015)

* Generate semantic html by injecting script tag before end of html tag
Expand Down
30 changes: 29 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
// create the view engine with `react-engine`
var engine = require('react-engine').server.create({
reactRoutes: <string> /* pass in the path to react-router routes optionally */
performanceCollector: <function> /* optional function to collect perf stats */
});

// set the engine
Expand Down Expand Up @@ -50,7 +51,8 @@
"renderer": {
"method": "create",
"arguments": [{
"reactRoutes": "path:<PATH_TO_REACT-ROUTER_ROUTES>"
"reactRoutes": "path:<PATH_TO_REACT-ROUTER_ROUTES>",
"performanceCollector": "require:<PATH_TO_PERF_COLLECTOR_FUNCTION>"
}]
}
}
Expand Down Expand Up @@ -100,6 +102,32 @@ document.addEventListener('DOMContentLoaded', function onLoad() {
};
```
### Performance Profiling
Pass in a function to the `performanceCollector` property to collect the `stats`
object for every render.
##### `stats`
The object that contains the stats info for each render by react-engine.
It has the below properties.
- `name` - Name of the template or the url in case of react router rendering.
- `startTime` - The start time of render.
- `endTime` - The completion time of render.
- `duration` - The duration taken to render (in milliseconds).
```js
// example
function collector(stats) {
console.log(stats);
}

var engine = require('react-engine').server.create({
reactRoutes: './routes.jsx'
performanceCollector: collector
});
```
### Notes
* On the client side, the state is exposed on the window object's property `__REACT_ENGINE__`
* In development mode, views are automatically reloaded before render. So there is no need to restart the server for seeing the changes.
Expand Down
37 changes: 37 additions & 0 deletions lib/performance.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*-------------------------------------------------------------------------------------------------------------------*\
| Copyright (C) 2015 PayPal |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance |
| with the License. |
| |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software distributed under the License is distributed |
| on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for |
| the specific language governing permissions and limitations under the License. |
\*-------------------------------------------------------------------------------------------------------------------*/

'use strict';

module.exports = function Performance(name) {

var startTime = Date.now();
var time = process.hrtime();

return function end() {

var diff = process.hrtime(time);

// duration in milliseconds
var duration = diff[0] + (diff[1] / 1000000);

return {
name: name,
startTime: startTime,
endTime: Date.now(),
duration: duration
};
};
};
17 changes: 17 additions & 0 deletions lib/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
'use strict';

var util = require('./util');
var assert = require('assert');
var Config = require('./config');
var format = require('util').format;
var Performance = require('./performance');
var omit = require('lodash-node/compat/object/omit');
var merge = require('lodash-node/compat/object/merge');

Expand All @@ -36,10 +38,21 @@ exports.create = function create(createOptions) {

createOptions = createOptions || {};

if (createOptions.performanceCollector) {
assert.equal(typeof createOptions.performanceCollector,
'function',
'`performanceCollector` - should be a function');
}

// the render implementation
return function render(thing, options, callback) {

var routes;
var perfInstance;

if (createOptions.performanceCollector) {
perfInstance = Performance(thing);
}

function done(err, html) {
if (options.settings.env === 'development') {
Expand All @@ -49,6 +62,10 @@ exports.create = function create(createOptions) {
util.clearRequireCacheInDir(options.settings.views, options.settings['view engine']);
}

if (createOptions.performanceCollector) {
createOptions.performanceCollector(perfInstance());
}

callback(err, html);
}

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-engine",
"version": "1.2.0",
"version": "1.3.0",
"description": "a composite render engine for express apps to render both plain react views and react-router views",
"main": "index.js",
"scripts": {
Expand Down
49 changes: 49 additions & 0 deletions test/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,55 @@ test('rendering a react view', function(t) {
setup(options);
});

test('performance collector to be asserted to be a function', function(t) {

function underTest1() {
renderer.create({
performanceCollector: 'SOME_STRING_AND_NOT_FUNCTION'
});
}

function underTest2() {
renderer.create({
performanceCollector: console.dir
});
}

t.throws(underTest1);
t.doesNotThrow(underTest2);
t.end();
});

test('performance collector', function(t) {

var recorder = [];

function collector(stats) {
recorder.push(stats);
}

var options = {
engine: renderer.create({
performanceCollector: collector
}),
onSetup: function(done) {
inject('/profile', function(err, data) {
t.error(err);
t.strictEqual(typeof data, 'string');
t.strictEqual(recorder.length, 1);
t.strictEqual(Object.keys(recorder[0]).length, 4);
t.strictEqual(recorder[0].name, path.resolve(__dirname, 'fixtures/views', 'profile.js'));
t.strictEqual(typeof recorder[0].startTime, 'number');
t.strictEqual(typeof recorder[0].endTime, 'number');
t.strictEqual(typeof recorder[0].duration, 'number');
t.ok(recorder[0].endTime > recorder[0].startTime);
done(t);
});
}
};
setup(options);
});

test('all views get cleared from require cache in dev mode', function(t) {
var options = {
engine: renderer.create(),
Expand Down

0 comments on commit e91ebc2

Please sign in to comment.