react-stdio
Advanced tools
| #!/usr/bin/env node | ||
| const EventStream = require("event-stream"); | ||
| const JSONStream = require("JSONStream"); | ||
| const createRequestHandler = require("./index").createRequestHandler; | ||
| // Redirect stdout to stderr, but save a reference so we can | ||
| // still write to stdout. | ||
| const stdout = process.stdout; | ||
| Object.defineProperty(process, "stdout", { | ||
| configurable: true, | ||
| enumerable: true, | ||
| value: process.stderr | ||
| }); | ||
| // Ensure console.log knows about the new stdout. | ||
| const Console = require("console").Console; | ||
| Object.defineProperty(global, "console", { | ||
| configurable: true, | ||
| enumerable: true, | ||
| value: new Console(process.stdout, process.stderr) | ||
| }); | ||
| // Read JSON blobs from stdin, pipe output to stdout. | ||
| process.stdin | ||
| .pipe(JSONStream.parse()) | ||
| .pipe(EventStream.map(createRequestHandler(process.cwd()))) | ||
| .pipe(stdout); |
| const path = require("path"); | ||
| const invariant = require("invariant"); | ||
| const ReactDOMServer = require("react-dom/server"); | ||
| const React = require("react"); | ||
| function loadModule(moduleId) { | ||
| // Clear the require cache, in case the file was | ||
| // changed since the server was started. | ||
| const cacheKey = require.resolve(moduleId); | ||
| delete require.cache[cacheKey]; | ||
| const moduleExports = require(moduleId); | ||
| // Return exports.default if using ES modules. | ||
| if (moduleExports && moduleExports.default) { | ||
| return moduleExports.default; | ||
| } | ||
| return moduleExports; | ||
| } | ||
| function renderToStaticMarkup(element, callback) { | ||
| callback(null, ReactDOMServer.renderToStaticMarkup(element)); | ||
| } | ||
| function renderToString(element, callback) { | ||
| callback(null, ReactDOMServer.renderToString(element)); | ||
| } | ||
| function handleRequest(workingDir, request, callback) { | ||
| const componentPath = request.component; | ||
| const renderMethod = request.render; | ||
| const props = request.props; | ||
| invariant(componentPath != null, "Missing { component } in request"); | ||
| let render; | ||
| if (renderMethod == null || renderMethod === "renderToString") { | ||
| render = renderToString; | ||
| } else if (renderMethod === "renderToStaticMarkup") { | ||
| render = renderToStaticMarkup; | ||
| } else { | ||
| const methodFile = path.resolve(workingDir, renderMethod); | ||
| try { | ||
| render = loadModule(methodFile); | ||
| } catch (error) { | ||
| if (error.code !== "MODULE_NOT_FOUND") { | ||
| process.stderr.write(error.stack + "\n"); | ||
| } | ||
| } | ||
| } | ||
| invariant( | ||
| typeof render === "function", | ||
| "Cannot load render method: %s", | ||
| renderMethod | ||
| ); | ||
| const componentFile = path.resolve(workingDir, componentPath); | ||
| let component; | ||
| try { | ||
| component = loadModule(componentFile); | ||
| } catch (error) { | ||
| if (error.code !== "MODULE_NOT_FOUND") { | ||
| process.stderr.write(error.stack + "\n"); | ||
| } | ||
| } | ||
| invariant(component != null, "Cannot load component: %s", componentPath); | ||
| render(React.createElement(component, props), function(err, html) { | ||
| callback(err, html, component.context); | ||
| }); | ||
| } | ||
| function createRequestHandler(workingDir) { | ||
| return function(request, callback) { | ||
| try { | ||
| handleRequest(workingDir, request, function(error, html, context) { | ||
| if (error) { | ||
| callback(error); | ||
| } else if (typeof html !== "string") { | ||
| // Crash the server process. | ||
| callback(new Error("Render method must return a string")); | ||
| } else { | ||
| callback(null, JSON.stringify({ html: html, context: context })); | ||
| } | ||
| }); | ||
| } catch (error) { | ||
| callback(null, JSON.stringify({ error: error.message })); | ||
| } | ||
| }; | ||
| } | ||
| module.exports = { | ||
| createRequestHandler | ||
| }; |
+8
-6
| { | ||
| "name": "react-stdio", | ||
| "version": "3.4.5", | ||
| "version": "3.4.6", | ||
| "description": "Render React.js components on any backend", | ||
| "author": "Michael Jackson", | ||
| "license": "MIT", | ||
| "bin": "./bin/react-stdio", | ||
| "bin": { | ||
| "react-stdio": "./modules/cli.js" | ||
| }, | ||
| "files": [ | ||
| "modules/cli.js", | ||
| "modules/index.js" | ||
| ], | ||
| "preferGlobal": true, | ||
| "repository": "ReactTraining/react-stdio", | ||
| "files": [ | ||
| "bin", | ||
| "server.js" | ||
| ], | ||
| "scripts": { | ||
@@ -15,0 +17,0 @@ "build": "./scripts/build.sh", |
+17
-7
@@ -1,7 +0,9 @@ | ||
| # react-stdio [![npm package][npm-badge]][npm] | ||
| # react-stdio [![Travis][build-badge]][build] [![npm package][npm-badge]][npm] | ||
| [build-badge]: https://img.shields.io/travis/ReactTraining/react-stdio/master.svg?style=flat-square | ||
| [build]: https://travis-ci.org/ReactTraining/react-stdio | ||
| [npm-badge]: https://img.shields.io/npm/v/react-stdio.svg?style=flat-square | ||
| [npm]: https://www.npmjs.org/package/react-stdio | ||
| [react-stdio](https://github.com/mjackson/react-stdio) lets you render [React](https://facebook.github.io/react/) components on the server, regardless of the backend technology you're using. | ||
| [react-stdio](https://npmjs.org/package/react-stdio) lets you render [React](https://reactjs.org/) components on the server, regardless of the backend technology you're using. | ||
@@ -12,9 +14,13 @@ As its name suggests, other processes communicate with react-stdio using standard streams. The protocol is JSON, so any environment that can spawn a child process and write JSON to its stdin can use the server. Requests are handled serially, so responses are issued in the same order requests are received. | ||
| Using [npm](https://npmjs.com): | ||
| If you have node installed, you can install using npm: | ||
| $ npm install -g react-stdio | ||
| This will put the `react-stdio` executable in your [`npm bin`](https://docs.npmjs.com/cli/bin). | ||
| If you don't have node installed, you can download the executable for your architecture from [the releases page](https://github.com/ReactTraining/react-stdio/releases). | ||
| ## Usage | ||
| Once you've installed the server, you will have a `react-stdio` binary available (assuming `node_modules/.bin` is in your `$PATH`). Execute it to start the server. | ||
| After installation, execute `react-stdio` to start the server. | ||
@@ -27,3 +33,3 @@ To render a React component, write a JSON blob to stdin with any of the following properties: | ||
| If the request is successful, the server will put a JSON blob with `{"html":"..."}` on stdout. If the request fails for some reason, the JSON will have an `error` property instead of `html`. | ||
| If the request is successful, the server will put a JSON blob with `{"html":"...","context":...}` on stdout. If the request fails for some reason, the JSON will have an `error` property instead of `html`. | ||
@@ -52,5 +58,9 @@ Example: | ||
| - [Elixir/Phoenix](http://blog.overstuffedgorilla.com/render-react-with-phoenix/) | ||
| - [Ruby on Rails](https://github.com/aaronvb/rails_react_stdio) | ||
| * [Elixir/Phoenix](http://blog.overstuffedgorilla.com/render-react-with-phoenix/) | ||
| * [Ruby on Rails](https://github.com/aaronvb/rails_react_stdio) | ||
| If you'd like to add an integration here, please submit a PR. | ||
| ## About | ||
| react-stdio is developed and maintained by [React Training](https://reacttraining.com). If you're interested in learning more about what React can do for your company, please [get in touch](mailto:hello@reacttraining.com)! |
Sorry, the diff of this file is not supported yet
-120
| const path = require("path"); | ||
| const invariant = require("invariant"); | ||
| const EventStream = require("event-stream"); | ||
| const JSONStream = require("JSONStream"); | ||
| const ReactDOMServer = require("react-dom/server"); | ||
| const React = require("react"); | ||
| function loadModule(moduleId) { | ||
| // Clear the require cache, in case the file was | ||
| // changed since the server was started. | ||
| const cacheKey = require.resolve(moduleId); | ||
| delete require.cache[cacheKey]; | ||
| const moduleExports = require(moduleId); | ||
| // Return exports.default if using ES modules. | ||
| if (moduleExports && moduleExports.default) { | ||
| return moduleExports.default; | ||
| } | ||
| return moduleExports; | ||
| } | ||
| function renderToStaticMarkup(element, callback) { | ||
| callback(null, ReactDOMServer.renderToStaticMarkup(element)); | ||
| } | ||
| function renderToString(element, callback) { | ||
| callback(null, ReactDOMServer.renderToString(element)); | ||
| } | ||
| function handleRequest(workingDir, request, callback) { | ||
| const componentPath = request.component; | ||
| const renderMethod = request.render; | ||
| const props = request.props; | ||
| invariant(componentPath != null, "Missing { component } in request"); | ||
| let render; | ||
| if (renderMethod == null || renderMethod === "renderToString") { | ||
| render = renderToString; | ||
| } else if (renderMethod === "renderToStaticMarkup") { | ||
| render = renderToStaticMarkup; | ||
| } else { | ||
| const methodFile = path.resolve(workingDir, renderMethod); | ||
| try { | ||
| render = loadModule(methodFile); | ||
| } catch (error) { | ||
| if (error.code !== "MODULE_NOT_FOUND") { | ||
| process.stderr.write(error.stack + "\n"); | ||
| } | ||
| } | ||
| } | ||
| invariant( | ||
| typeof render === "function", | ||
| "Cannot load render method: %s", | ||
| renderMethod | ||
| ); | ||
| const componentFile = path.resolve(workingDir, componentPath); | ||
| let component; | ||
| try { | ||
| component = loadModule(componentFile); | ||
| } catch (error) { | ||
| if (error.code !== "MODULE_NOT_FOUND") { | ||
| process.stderr.write(error.stack + "\n"); | ||
| } | ||
| } | ||
| invariant(component != null, "Cannot load component: %s", componentPath); | ||
| render(React.createElement(component, props), function(err, html) { | ||
| callback(err, html, component.context); | ||
| }); | ||
| } | ||
| function createRequestHandler(workingDir) { | ||
| return function(request, callback) { | ||
| try { | ||
| handleRequest(workingDir, request, function(error, html, context) { | ||
| if (error) { | ||
| callback(error); | ||
| } else if (typeof html !== "string") { | ||
| // Crash the server process. | ||
| callback(new Error("Render method must return a string")); | ||
| } else { | ||
| callback(null, JSON.stringify({ html: html, context: context })); | ||
| } | ||
| }); | ||
| } catch (error) { | ||
| callback(null, JSON.stringify({ error: error.message })); | ||
| } | ||
| }; | ||
| } | ||
| // Redirect stdout to stderr, but save a reference so we can | ||
| // still write to stdout. | ||
| const stdout = process.stdout; | ||
| Object.defineProperty(process, "stdout", { | ||
| configurable: true, | ||
| enumerable: true, | ||
| value: process.stderr | ||
| }); | ||
| // Ensure console.log knows about the new stdout. | ||
| const Console = require("console").Console; | ||
| Object.defineProperty(global, "console", { | ||
| configurable: true, | ||
| enumerable: true, | ||
| value: new Console(process.stdout, process.stderr) | ||
| }); | ||
| // Read JSON blobs from stdin, pipe output to stdout. | ||
| process.stdin | ||
| .pipe(JSONStream.parse()) | ||
| .pipe(EventStream.map(createRequestHandler(process.cwd()))) | ||
| .pipe(stdout); |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
7939
10.4%106
4.95%64
18.52%1
Infinity%