diff --git a/client.js b/client.js new file mode 100644 index 0000000..4fba4f1 --- /dev/null +++ b/client.js @@ -0,0 +1 @@ +module.exports = require('./lib/client.js'); diff --git a/server.js b/server.js new file mode 100644 index 0000000..429f220 --- /dev/null +++ b/server.js @@ -0,0 +1 @@ +module.exports = require('./lib/server.js'); diff --git a/src/client.js b/src/client.js new file mode 100644 index 0000000..d8c24a5 --- /dev/null +++ b/src/client.js @@ -0,0 +1,43 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import hypernova, { load } from 'hypernova'; + +const renderReactClient = (name, component) => { + const payloads = load(name); + + if (payloads) { + payloads.forEach((payload) => { + const { node, data } = payload; + const element = React.createElement(component, data); + + if (ReactDOM.hydrate) { + ReactDOM.hydrate(element, node); + } else { + ReactDOM.render(element, node); + } + }); + } + + return component; +}; + +const renderReact = (name, component) => hypernova({ + server() {}, + + client() { + return renderReactClient(name, component); + }, +}); + +/* istanbul ignore next */ +const renderReactStatic = () => hypernova({ + server() {}, + + client() {}, +}); + +export { + renderReactClient, + renderReact, + renderReactStatic, +}; diff --git a/src/index.js b/src/index.js index ae8f72a..461c2a4 100644 --- a/src/index.js +++ b/src/index.js @@ -1,39 +1,20 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import ReactDOMServer from 'react-dom/server'; -import hypernova, { serialize, load } from 'hypernova'; +import hypernova from 'hypernova'; +import { renderReactClient } from './client'; +import { renderReactServer, renderReactStaticServer } from './server'; export const renderReact = (name, component) => hypernova({ server() { - return (props) => { - const contents = ReactDOMServer.renderToString(React.createElement(component, props)); - return serialize(name, contents, props); - }; + return renderReactServer(name, component); }, client() { - const payloads = load(name); - - if (payloads) { - payloads.forEach((payload) => { - const { node, data } = payload; - const element = React.createElement(component, data); - - if (ReactDOM.hydrate) { - ReactDOM.hydrate(element, node); - } else { - ReactDOM.render(element, node); - } - }); - } - - return component; + return renderReactClient(name, component); }, }); export const renderReactStatic = (name, component) => hypernova({ server() { - return props => ReactDOMServer.renderToStaticMarkup(React.createElement(component, props)); + return renderReactStaticServer(name, component); }, client() {}, diff --git a/src/server.js b/src/server.js new file mode 100644 index 0000000..ff6e823 --- /dev/null +++ b/src/server.js @@ -0,0 +1,37 @@ +import React from 'react'; +import ReactDOMServer from 'react-dom/server'; +import hypernova, { serialize } from 'hypernova'; + +const renderReactServer = (name, component) => (props) => { + const contents = ReactDOMServer.renderToString( + React.createElement(component, props), + ); + return serialize(name, contents, props); +}; + +const renderReactStaticServer = (name, component) => props => + // eslint-disable-next-line implicit-arrow-linebreak + ReactDOMServer.renderToStaticMarkup(React.createElement(component, props)); + +const renderReact = (name, component) => hypernova({ + server() { + return renderReactServer(name, component); + }, + + client() {}, +}); + +const renderReactStatic = (name, component) => hypernova({ + server() { + return renderReactStaticServer(name, component); + }, + + client() {}, +}); + +export { + renderReactServer, + renderReactStaticServer, + renderReact, + renderReactStatic, +}; diff --git a/test/renderReact-test.js b/test/renderReact-test.js index e6a97f5..982984d 100644 --- a/test/renderReact-test.js +++ b/test/renderReact-test.js @@ -1,67 +1,38 @@ import jsdom from 'jsdom'; import { assert } from 'chai'; import sinon from 'sinon'; -import ReactDOM from 'react-dom'; -import ifReact from 'enzyme-adapter-react-helper/build/ifReact'; import ExampleReactComponent from './components/ExampleReactComponent'; import { renderReact } from '..'; +import * as renderReactClientModule from '../lib/client'; +import * as renderReactServerModule from '../lib/server'; describe('renderReact', () => { - let result; - beforeEach(() => { - result = renderReact('ExampleReactComponent', ExampleReactComponent)({ name: 'Desmond' }); - }); - it('exists', () => { assert.isFunction(renderReact); assert.equal(renderReact.length, 2); }); - it('has correct markup on server', () => { - assert.isString(result); - assert.match(result, /Hello Desmond/); - }); - - ifReact('>= 16', it, it.skip)('calls hypernova.client (hydrate method)', (done) => { - jsdom.env(result, (err, window) => { - if (err) { - done(err); - return; - } - - global.window = window; - global.document = window.document; - - const hydrateMethod = sinon.spy(ReactDOM, 'hydrate'); - - // Calling it again for the client. - renderReact('ExampleReactComponent', ExampleReactComponent); - - assert(hydrateMethod.calledOnce); + it('calls renderReactServer', () => { + const renderReactServerSpy = sinon.spy(renderReactServerModule, 'renderReactServer'); - delete global.window; - delete global.document; + renderReact('ExampleReactComponent', ExampleReactComponent)({ name: 'Desmond' }); - hydrateMethod.restore(); + assert(renderReactServerSpy.calledOnce, `renderReactServer was not called once but ${renderReactServerSpy.callCount} times`); - done(); - }); + renderReactServerSpy.restore(); }); - it('calls hypernova.client (render method)', (done) => { + it('calls renderReactClient', (done) => { + const result = renderReact('ExampleReactComponent', ExampleReactComponent)({ name: 'Desmond' }); + jsdom.env(result, (err, window) => { if (err) { done(err); return; } - const sandbox = sinon.createSandbox(); - if (ReactDOM.hydrate) { - sandbox.stub(ReactDOM, 'hydrate').value(undefined); - } - - const renderMethod = sinon.spy(ReactDOM, 'render'); + const renderReactClientSpy = sinon.spy(renderReactClientModule, 'renderReactClient'); global.window = window; global.document = window.document; @@ -69,9 +40,9 @@ describe('renderReact', () => { // Calling it again for the client. renderReact('ExampleReactComponent', ExampleReactComponent); - assert(renderMethod.calledOnce); + assert(renderReactClientSpy.calledOnce, `renderReactClient was not called once but ${renderReactClientSpy.callCount} times`); - sandbox.restore(); + renderReactClientSpy.restore(); delete global.window; delete global.document; diff --git a/test/renderReactClient-test.js b/test/renderReactClient-test.js new file mode 100644 index 0000000..17f0735 --- /dev/null +++ b/test/renderReactClient-test.js @@ -0,0 +1,87 @@ +import jsdom from 'jsdom'; +import { assert } from 'chai'; +import sinon from 'sinon'; +import ReactDOM from 'react-dom'; +import ifReact from 'enzyme-adapter-react-helper/build/ifReact'; + +import ExampleReactComponent from './components/ExampleReactComponent'; +import { renderReactServer } from '../lib/server'; +import { renderReact, renderReactClient } from '../lib/client'; + +describe('client', () => { + let result; + beforeEach(() => { + result = renderReactServer('ExampleReactComponent', ExampleReactComponent)({ name: 'Desmond' }); + + assert.isString(result); + assert.match(result, /Hello Desmond/); + }); + + it('renderReact exists', () => { + assert.isFunction(renderReact); + assert.equal(renderReact.length, 2); + }); + + it('renderReactClient exists', () => { + assert.isFunction(renderReactClient); + assert.equal(renderReactClient.length, 2); + }); + + ifReact('>= 16', it, it.skip)('calls hypernova.client (hydrate method)', (done) => { + jsdom.env(result, (err, window) => { + if (err) { + done(err); + return; + } + + global.window = window; + global.document = window.document; + + const hydrateMethod = sinon.spy(ReactDOM, 'hydrate'); + + // Calling it again for the client. + renderReact('ExampleReactComponent', ExampleReactComponent); + + assert(hydrateMethod.calledOnce); + + hydrateMethod.restore(); + + delete global.window; + delete global.document; + + done(); + }); + }); + + it('calls hypernova.client (render method)', (done) => { + jsdom.env(result, (err, window) => { + if (err) { + done(err); + return; + } + + const sandbox = sinon.createSandbox(); + if (ReactDOM.hydrate) { + sandbox.stub(ReactDOM, 'hydrate').value(undefined); + } + + const renderMethod = sinon.spy(ReactDOM, 'render'); + + global.window = window; + global.document = window.document; + + // Calling it again for the client. + renderReact('ExampleReactComponent', ExampleReactComponent); + + assert(renderMethod.calledOnce); + + sandbox.restore(); + renderMethod.restore(); + + delete global.window; + delete global.document; + + done(); + }); + }); +}); diff --git a/test/renderReactServer-test.js b/test/renderReactServer-test.js new file mode 100644 index 0000000..8b0b77e --- /dev/null +++ b/test/renderReactServer-test.js @@ -0,0 +1,26 @@ +import { assert } from 'chai'; + +import ExampleReactComponent from './components/ExampleReactComponent'; +import { renderReact, renderReactServer } from '../lib/server'; + +describe('server renderReact', () => { + let result; + beforeEach(() => { + result = renderReact('ExampleReactComponent', ExampleReactComponent)({ name: 'Desmond' }); + }); + + it('exists', () => { + assert.isFunction(renderReact); + assert.equal(renderReact.length, 2); + }); + + it('exists', () => { + assert.isFunction(renderReactServer); + assert.equal(renderReactServer.length, 2); + }); + + it('has correct markup', () => { + assert.isString(result); + assert.match(result, /Hello Desmond/); + }); +}); diff --git a/test/renderReactStatic-test.js b/test/renderReactStatic-test.js index cdded8c..d7dd4d9 100644 --- a/test/renderReactStatic-test.js +++ b/test/renderReactStatic-test.js @@ -1,21 +1,23 @@ import { assert } from 'chai'; +import sinon from 'sinon'; import ExampleReactComponent from './components/ExampleReactComponent'; import { renderReactStatic } from '..'; +import * as renderReactServerModule from '../lib/server'; describe('renderReactStatic', () => { - let result; - beforeEach(() => { - result = renderReactStatic('ExampleReactComponent', ExampleReactComponent)({ name: 'Zack' }); - }); - it('exists', () => { assert.isFunction(renderReactStatic); assert.equal(renderReactStatic.length, 2); }); - it('has correct markup on server', () => { - assert.isString(result); - assert.match(result, /Hello Zack/); + it('calls renderReactStaticServer', () => { + const renderReactStaticServerSpy = sinon.spy(renderReactServerModule, 'renderReactStaticServer'); + + renderReactStatic('ExampleReactComponent', ExampleReactComponent)({ name: 'Desmond' }); + + assert(renderReactStaticServerSpy.calledOnce, `renderReactServer was not called once but ${renderReactStaticServerSpy.callCount} times`); + + renderReactStaticServerSpy.restore(); }); }); diff --git a/test/renderReactStaticServer-test.js b/test/renderReactStaticServer-test.js new file mode 100644 index 0000000..8937727 --- /dev/null +++ b/test/renderReactStaticServer-test.js @@ -0,0 +1,18 @@ +import { assert } from 'chai'; + +import ExampleReactComponent from './components/ExampleReactComponent'; +import { renderReactStatic } from '../lib/server'; + +describe('server renderReactStatic', () => { + it('exists', () => { + assert.isFunction(renderReactStatic); + assert.equal(renderReactStatic.length, 2); + }); + + it('has correct markup', () => { + const result = renderReactStatic('ExampleReactComponent', ExampleReactComponent)({ name: 'Zack' }); + + assert.isString(result); + assert.match(result, /Hello Zack/); + }); +});