diff --git a/lib/api/getRibbitStore.js b/lib/api/getRibbitStore.js new file mode 100644 index 0000000..bfd3a69 --- /dev/null +++ b/lib/api/getRibbitStore.js @@ -0,0 +1,20 @@ +import { createStore, applyMiddleware } from 'redux'; + +const getRibbitStore = (combinedReducers, ...middleware) => { + let store; + // check if rendering is happening on the client or the server. + + if (typeof window !== 'undefined') { + // get state from window + const preloadedState = window.RIBBIT_PRELOADED_STATE; + delete window.RIBBIT_PRELOADED_STATE; + + // pass state into redux store + store = createStore(combinedReducers, preloadedState, applyMiddleware(...middleware)); + } else { + store = createStore(combinedReducers, applyMiddleware(...middleware)); + } + return store; +}; + +export default getRibbitStore; diff --git a/lib/api/preloadActions.js b/lib/api/preloadActions.js new file mode 100644 index 0000000..24a749a --- /dev/null +++ b/lib/api/preloadActions.js @@ -0,0 +1,13 @@ +function preloadPush() { + fetch('http://localhost:5000/preload-push') + .then(() => console.log('preload push')) + .catch(err => console.log(err)); +} + +function preloadPop() { + fetch('http://localhost:5000/preload-pop') + .then(() => console.log('preload pop')) + .catch(err => console.log(err)); +} + +module.exports = { preloadPush, preloadPop }; diff --git a/lib/api/ribbitPreload.js b/lib/api/ribbitPreload.js new file mode 100644 index 0000000..d043190 --- /dev/null +++ b/lib/api/ribbitPreload.js @@ -0,0 +1,23 @@ +const { preloadPush } = require('./preloadActions'); + +const ribbitRequestFactory = () => { + const fetched = {}; + + function ribbitPreload(cb, component) { + // only perform fetch if running on the server + if (typeof window === 'undefined') { + // dont let component continue to send requests after initial preload + if (!fetched[component]) { + fetched[component] = true; + cb(); + preloadPush(); + } + } + } + + return ribbitPreload; +}; + +const ribbitPreload = ribbitRequestFactory(); + +export default ribbitPreload; diff --git a/lib/api/ribbitStore.js b/lib/api/ribbitStore.js new file mode 100644 index 0000000..fabbb2b --- /dev/null +++ b/lib/api/ribbitStore.js @@ -0,0 +1,15 @@ +const { preloadPop } = require('./preloadActions'); +// re-render page with updated state on the server +const ribbitStore = routes => { + routes.forEach(route => { + fetch(`http://localhost:5000${route}`) + .then(response => response.json()) + .then(() => { + console.log('Re-render success!'); + preloadPop(); + }) + .catch(err => console.log(err)); + }); +}; + +export default ribbitStore; diff --git a/lib/commands/build.js b/lib/commands/build.js index a1d54a7..11f6092 100644 --- a/lib/commands/build.js +++ b/lib/commands/build.js @@ -7,7 +7,13 @@ function build() { { cwd: __dirname }, - () => {} + () => { + const TEMP_STATIC_FILE_FOLDER = `${__dirname}/../../dist`; + rimraf(TEMP_STATIC_FILE_FOLDER, error => { + if (error) process.stdout(error); + process.kill(process.pid, 'SIGINT'); + }); + } ); child.stdout.on('data', data => { @@ -18,14 +24,6 @@ function build() { process.stdout.write(data); }); - child.stdout.on('finish', () => { - const TEMP_STATIC_FILE_FOLDER = `${__dirname}/../../dist`; - rimraf(TEMP_STATIC_FILE_FOLDER, error => { - if (error) process.stdout(error); - process.kill(process.pid, 'SIGINT'); - }); - }); - child.stderr.on('exit', data => { console.log('Error starting server: ', data); }); diff --git a/package.json b/package.json index 2ab5627..e51ca29 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "@babel/preset-env": "^7.2.3", "@babel/preset-react": "^7.0.0", "babel-plugin-import-inspector": "^2.0.0", + "body-parser": "^1.18.3", "chalk": "^2.4.2", "commander": "^2.19.0", "css-loader": "^2.1.0", @@ -44,7 +45,9 @@ "isomorphic-fetch": "^2.2.1", "react": "^16.7.0", "react-dom": "^16.7.0", + "react-redux": "^6.0.0", "react-router-dom": "^4.3.1", + "redux": "^4.0.1", "rimraf": "^2.6.3", "webpack": "^4.28.4", "webpack-cli": "^3.2.1" diff --git a/server/controllers/htmlTemplate.js b/server/controllers/htmlTemplate.js index 3d69320..9e0921e 100644 --- a/server/controllers/htmlTemplate.js +++ b/server/controllers/htmlTemplate.js @@ -5,7 +5,7 @@ const { StringDecoder } = require('string_decoder'); const decoder = new StringDecoder('utf8'); function htmlTemplate(req, res, next) { - const { appParentDirectory, componentRoute, jsx } = res.locals; + const { appParentDirectory, componentRoute, jsx, preLoadedState } = res.locals; const ribbitConfig = require(path.join(appParentDirectory, '/ribbit.config.js')); const reactStream = renderToNodeStream(jsx); @@ -14,6 +14,8 @@ function htmlTemplate(req, res, next) { reactStream.on('data', data => { reactDom += decoder.write(data); }); + + // inject state into HTML template reactStream.on('end', () => { const html = ` @@ -24,8 +26,13 @@ function htmlTemplate(req, res, next) {
-