Skip to content

Commit

Permalink
React is now resolved from the component's path.
Browse files Browse the repository at this point in the history
Re #1
  • Loading branch information
markfinger committed Apr 13, 2015
1 parent f981899 commit 3c3afe0
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 62 deletions.
6 changes: 0 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,9 @@ Usage
var reactRender = require('react-render');

reactRender({
// Required
// --------

// An absolute path to a module exporting your component
path: '/abs/path/to/component.js',

// Or, you can provide an instance of your component
component: YourComponent,

// Optional
// --------

Expand Down
69 changes: 49 additions & 20 deletions lib/Component.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
var _ = require('lodash');
var React = require('react');
var path = require('path');
var resolve = require('resolve');

var Component = function Component(opts) {
this.opts = opts;
this.path = null;
this.component = null;
this.factory = null;
this.React = null;
};

Component.prototype.getPath = function getPath(cb) {
Expand Down Expand Up @@ -46,6 +47,28 @@ Component.prototype.getComponent = function getComponent(cb) {
}.bind(this));
};

Component.prototype.getReact = function getReact(cb) {
if (this.React) return cb(null, this.React);

this.getPath(function(err, _path) {
if (err) return cb(err);

resolve('react', {
basedir: path.dirname(_path)
}, function(err, res) {
if (err) return cb(err);

try {
this.React = require(res);
} catch(err) {
return cb(err);
}

cb(null, this.React);
}.bind(this));
}.bind(this));
};

Component.prototype.getFactory = function getFactory(cb) {
if (this.factory) {
return cb(null, this.factory);
Expand All @@ -54,34 +77,40 @@ Component.prototype.getFactory = function getFactory(cb) {
this.getComponent(function(err, component) {
if (err) return cb(err);

try {
this.factory = React.createFactory(component);
} catch(err) {
cb(err);
}
this.getReact(function(err, React) {
if (err) return cb(err);

try {
this.factory = React.createFactory(component);
} catch(err) {
cb(err);
}

cb(null, this.factory);
cb(null, this.factory);
});
}.bind(this));
};

Component.prototype._render = function _render(props, toStaticMarkup, cb) {
this.getFactory(function(err, factory) {
if (err) return cb(err);

var render = (
toStaticMarkup ?
React.renderToStaticMarkup :
React.renderToString
).bind(React);
this.getReact(function(err, React) {
if (err) return cb(err);

try {
var markup = render(factory(props));
} catch(err) {
return cb(err);
}
var render = (
toStaticMarkup ? React.renderToStaticMarkup : React.renderToString
).bind(React);

cb(null, markup);
});
try {
var markup = render(factory(props));
} catch (err) {
return cb(err);
}

cb(null, markup);
});
}.bind(this));
};

Component.prototype.renderToString = function renderToString(props, cb) {
Expand Down
6 changes: 2 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,8 @@
"url": "https://github.com/markfinger/react-render.git"
},
"dependencies": {
"lodash": "^3.6.0"
},
"peerDependencies": {
"react": "*"
"lodash": "^3.6.0",
"resolve": "^1.1.6"
},
"devDependencies": {
"chai": "^2.1.1",
Expand Down
60 changes: 37 additions & 23 deletions test/Component.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,29 @@ var path = require('path');
var assert = require('chai').assert;
var _ = require('lodash');
var Component = require('../lib/Component');
var Hello = require('./test_components/Hello');
var ErrorThrowingComponent = require('./test_components/ErrorThrowingComponent');

var Hello = path.join(__dirname, 'test_components', 'Hello.js');
var ErrorThrowingComponent = path.join(__dirname, 'test_components', 'ErrorThrowingComponent.js');
var SyntaxErrorComponent = path.join(__dirname, 'test_components', 'SyntaxErrorComponent.js');

describe('Component', function() {
it('is a function', function() {
assert.isFunction(Component);
});
it('can accept a component in its options', function(done) {
var component = new Component({
component: Hello
});

component.getComponent(function(err, component) {
assert.isNull(err);
assert.strictEqual(component, Hello);
done();
});
});
it('can require a component specified by a path', function(done) {
var component = new Component({
path: path.join(__dirname, 'test_components', 'Hello')
path: Hello
});

component.getComponent(function(err, component) {
assert.isNull(err);
assert.strictEqual(component, Hello);
assert.strictEqual(component, require(Hello));
done();
});
});
it('can render a component to static markup', function(done) {
var component = new Component({
component: Hello
path: Hello
});

component.renderToStaticMarkup(null, function(err, markup) {
Expand All @@ -44,7 +35,7 @@ describe('Component', function() {
});
it('can render a component to a string', function(done) {
var component = new Component({
component: Hello
path: Hello
});

component.renderToString(null, function(err, markup) {
Expand All @@ -57,7 +48,7 @@ describe('Component', function() {
});
it('can render a component to static markup with props', function(done) {
var component = new Component({
component: Hello
path: Hello
});

component.renderToStaticMarkup({
Expand All @@ -70,7 +61,7 @@ describe('Component', function() {
});
it('can render a component to a string with props', function(done) {
var component = new Component({
component: Hello
path: Hello
});

component.renderToString({
Expand All @@ -97,30 +88,53 @@ describe('Component', function() {
});
it('passes up errors thrown during a component\'s rendering', function(done) {
var component = new Component({
component: ErrorThrowingComponent
path: ErrorThrowingComponent
});

component.renderToString(null, function(err, output) {
assert.instanceOf(err, Error);
assert.include(err.stack, 'Error from inside ErrorThrowingComponent');
assert.include(err.stack, path.join(__dirname, 'test_components', 'ErrorThrowingComponent.js'));
assert.include(err.stack, ErrorThrowingComponent);
assert.isUndefined(output);
done();
});
});
it('provides a SyntaxError if a component contains syntax errors', function(done) {
var component = new Component({
path: path.join(__dirname, 'test_components', 'SyntaxErrorComponent.js')
path: SyntaxErrorComponent
});

component.getComponent(function(err, component) {
assert.instanceOf(err, SyntaxError);
// Node 0.10.x stack traces don't provide so much detail
if (!_.startsWith(process.version, 'v0.10')) {
assert.include(err.stack, path.join(__dirname, 'test_components', 'SyntaxErrorComponent.js'));
assert.include(err.stack, SyntaxErrorComponent);
}
assert.isUndefined(component);
done();
});
});
it('can resolve React from a component\'s path', function(done) {
var component = new Component({
path: Hello
});

component.getReact(function(err, React) {
assert.isNull(err);
assert.strictEqual(React, require('react'));
done();
});
});
it('can provide an error if React is unresolvable from a component\'s path', function(done) {
var component = new Component({
path: path.join(__dirname, '..', '..', 'test.js')
});

component.getReact(function(err, React) {
assert.isNotNull(err);
assert.instanceOf(err, Error);
assert.isUndefined(React);
done();
});
});
});
19 changes: 10 additions & 9 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ var assert = require('chai').assert;
var reactRender = require('..');
var cache = require('../lib/cache');
var Component = require('../lib/Component');
var Hello = require('./test_components/Hello');
var ErrorThrowingComponent = require('./test_components/ErrorThrowingComponent');

var Hello = path.join(__dirname, 'test_components', 'Hello.js');
var ErrorThrowingComponent = path.join(__dirname, 'test_components', 'ErrorThrowingComponent.js');

describe('reactRender', function() {
beforeEach(function() {
Expand All @@ -15,7 +16,7 @@ describe('reactRender', function() {
});
it('can render a component to static markup', function(done) {
reactRender({
component: Hello,
path: Hello,
toStaticMarkup: true,
props: {
name: 'World'
Expand All @@ -28,7 +29,7 @@ describe('reactRender', function() {
});
it('can render a component to a string', function(done) {
reactRender({
component: Hello,
path: Hello,
props: {
name: 'World'
}
Expand All @@ -44,7 +45,7 @@ describe('reactRender', function() {
});
it('can render a component without props', function(done) {
reactRender({
component: Hello,
path: Hello,
toStaticMarkup: true
}, function(err, output) {
assert.isNull(err);
Expand All @@ -54,7 +55,7 @@ describe('reactRender', function() {
});
it('can parse props which are provided in a JSON serialized form', function(done) {
reactRender({
component: Hello,
path: Hello,
toStaticMarkup: true,
serializedProps: '{"name": "World"}'
}, function(err, output) {
Expand Down Expand Up @@ -94,11 +95,11 @@ describe('reactRender', function() {
assert.equal(cache._cache.length, 0);

reactRender({
component: Hello
path: Hello
}, function() {
assert.equal(cache._cache.length, 1);
assert.instanceOf(cache._cache[0], Component);
assert.equal(cache._cache[0].component, Hello);
assert.equal(cache._cache[0].component, require(Hello));
done();
});
});
Expand Down Expand Up @@ -144,7 +145,7 @@ describe('reactRender', function() {
});
it('passes up errors thrown during a component\'s rendering', function(done) {
reactRender({
component: ErrorThrowingComponent
path: ErrorThrowingComponent
}, function(err, output) {
assert.instanceOf(err, Error);
assert.include(err.stack, 'Error from inside ErrorThrowingComponent');
Expand Down

0 comments on commit 3c3afe0

Please sign in to comment.