-
Notifications
You must be signed in to change notification settings - Fork 5
Server Side Rendering
JP DeVries edited this page Mar 18, 2017
·
4 revisions
To demonstrate server side rendering via Node this example assumes you are using Express, Formidable, and some promises we will elaborate on that handle getting the media source data to be served.
Your REST API needs to supply the media browser with JSON data for all available media source objects. Modify the promise returned by the getMediaSources
function to do just that as needed.
Your REST API needs to supply the media browser with JSON data for the current directory contents. Modify the promise returned by the getMediaSources
function to do just that as needed.
import React from 'react';
import ReactDOM from 'react-dom';
import EurekaMediaBrowser from 'EurekaMediaBrowser';
function getMediaSources() {
return new Promise((resolve, reject) => {
/* this is where you get your media source information (data base query, whatever) and then return it with resolve() */
})
}
function getDirectoryListing() {
return new Promise((resolve, reject) => {
/* this is where you get your directory listing information (data base query, whatever) and then return it with resolve() */
})
}
function getEurekaPageMarkup(eurekaMarkup = '') {
return (
`<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title data-site-name="Eureka Media Browser">Eureka Media Browser</title>
<link rel="stylesheet" href="assets/css/components/eureka/eureka.2.0.0.min.css">
</head>
<body>
<div id="root">${eurekaMarkup}</div>
</body>
</html>`
);
}
function handleEurekaPostChosen(req, res, fields) {
res.end(`<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title data-site-name="Eureka Media Browser">Eureka!</title>
</head>
<body>
<h1>Eureka!</h1>
<p>You chose ${path.join(fields['eureka__upload-dir'], fields.eureka__chosen_item)} of the ${name} (${cs}) media source.</p>
<img src="/sources/filesystem/${path.join(fields['eureka__upload-dir'], fields.eureka__chosen_item)}" alt="/sources/filesystem/${path.join(fields['eureka__upload-dir'], fields.eureka__chosen_item)}" />
</body>
</html>`);
}
/*___ __ ___
/\ __`\/\ \ /\_ \
\ \ \/\ \ \ \/'\ ___ ___ ___\//\ \
\ \ \ \ \ \ , < /'___\ / __`\ / __`\\ \ \
\ \ \_\ \ \ \\`\ __ /\ \__//\ \L\ \/\ \L\ \\_\ \_
\ \_____\ \_\ \_\/\ \ \ \____\ \____/\ \____//\____\
\/_____/\/_/\/_/\ \/ \/____/\/___/ \/___/ \/____/
\/ You probably don't need to change the rest very much */
app.get('/eureka', (req, res) => {
serveEurekaPage(req, res);
});
const allowMultipleUploads = true;
app.post('/eureka', (req, res) => {
// using formidable because it rocks
const form = new formidable.IncomingForm();
form.multiples = allowMultipleUploads;
form.parse(req, function(err, fields, files) { // parse the form
const uploadFiles = files.eureka__uploadFiles, // Array of File Objects or a single File Object
[cs, cd] = utility.parseMediaSourceOutOfCombinedPath(fields[`eureka__media-browser_${fields.eureka__mediaSourceId}__browsing`], '||'), // option values need to send both the media source id and the current directory so they are combined into a single string and parsed out on the server side
uploadDir = path.join(__dirname, path.join('/sources/filesystem/', fields['eureka__upload-dir'])); // where we are going to be uploading files too
function moveFile(file) {
fs.renameSync(file.path, path.join(uploadDir, file.name))
}
// move the uploaded files into place
try {
uploadFiles.map(moveFile)
} catch (e) { // its a single file not an Array
if(uploadFiles.name) moveFile(uploadFiles)
}
if(fields.eureka__chosen_item) { // if they chose an item
getMediaSources().then((mediaSources) => { // get the media source data
const name = mediaSources.filter((mediaSource) => ( // try and get the name of the current media source
mediaSource.id == cs
))[0].name || undefined;
// this is where you redirect or do whatever you'd like once they have chosen an item
return handleEurekaPostChosen(req, res, fields);
});
} else { // if they didn't chose something, they browsed or uploaded so time to serve them the media browser again
return serveEurekaPage(req, res, cd);
}
});
});
/**
* Serves the Eureka media browser component based off the current directory
* @param req The Express req Object
* @param res The Express res Object
* @param cd The current directory
*/
function serveEurekaPage(req, res, cd = "/") {
getEurekaMarkup(cd).then((eurekaMarkup) => {
res.end(getEurekaPageMarkup(eurekaMarkup));
});
}
/**
* Returns static markup of EurekaMediaBrowser
*
* Returns a promise that fetches media source data, then gets listings for the current directory of the current media source, then dispatch related Redux actions and resolves the promise with the static markup of EurekaMediaBrowser
* @param dir The current directory
* @return static markup of EurekaMediaBrowser component
*/
function getEurekaMarkup(dir = "/") {
return new Promise((resolve, reject) => {
getMediaSources().then((mediaSources) => ( // get the media source data
store.dispatch(actions.fetchMediaSourcesSuccess(( // set the media source data on the Redux store
mediaSources
)))
)).then(() => {
return new Promise((resolve, reject) => { // get the media source tree listing
const path = `${__dirname}/sources/filesystem/`;
// crawl the filesystem (media source) to get the directory structure
recursivelyGetSourceDirectories(path).then((results) => (
resolve(results)
)).catch((err) => (
res.json(err)
));
})
}).then((results) => ( // set the directory tree data on the Redux store
store.dispatch(actions.updateSourceTreeSuccess(
results
))
)).then(() => { // get the current directory listing
return new Promise((resolve, reject) => {
getDirectoryListing(`${__dirname}/sources/filesystem/`, dir || 'assets/img/hawaii', true, true, `${__dirname}/sources/filesystem/`).then((results) => (
resolve(results)
)).catch((err) => (
res.json(err)
));
})
}).then((results) => (
// set the current directory content data on the Redux store
store.dispatch(actions.fetchDirectoryContentsSuccess(
results
))
)).then(() => ( // Resolve the promise with Redux state and React components flattened to a static string to be delivered in the initial HTML layer for world wide performance and accessibility
resolve(
ReactDOM.renderToStaticMarkup(
<EurekaMediaBrowser
uid="0"
currentDirectory={dir} />
)
)
));
});
}