Repository: ReactTraining/react-stdio
Branch: master
Commit: 69489252dc34
Files: 12
Total size: 13.1 KB
Directory structure:
gitextract_6n57gqjw/
├── .gitignore
├── .prettierignore
├── .travis.yml
├── README.md
├── jest.config.js
├── modules/
│ ├── __mocks__/
│ │ ├── ContextComponent.js
│ │ └── TestComponent.js
│ ├── __tests__/
│ │ └── server-test.js
│ ├── cli.js
│ └── index.js
├── package.json
└── scripts/
└── build.sh
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
/build/
/node_modules/
================================================
FILE: .prettierignore
================================================
package.json
================================================
FILE: .travis.yml
================================================
language: node_js
node_js: 8
cache:
directories:
- "$HOME/.npm"
- "$HOME/.pkg-cache"
env:
- NPM_TAG=$([[ "$TRAVIS_TAG" == *-* ]] && echo "next" || echo "latest")
script:
- npm test
- npm run build
deploy:
- provider: npm
skip_cleanup: true
email: npm@mjackson.me
tag: "$NPM_TAG"
api_key:
secure: Ouhk1VI9D8JUihTJl16S2yVYHu1ngFEbmrrq6KJzTCD69N4NiyvXzMYhN97K/R0twQqnxS10aAufPvXnFtTvQz48/USGp34gSzLySSqWCXsCpOothsew4SUDqHZPdLIUJqwhpYyJsyCtDbwf8cOTgxlbXW+DE8Y1s0LTJjbbJrg2RlwNjIdYeAjfDQuO2nL3zHPAGJQ/mYJEyicZ6T2H46O4kLuzWvocvUYnEV/j/gtBtBCukg9UG//YxHJVlNfeRXYCiQ/mf5ReCY7zgghK+eJXiaKJZ+l/hV2sp7C893YwKs1IQJ5kn/liwtJfqLGSKrsw7jwu1AESx1jhQsdhCJx5pj61BUTtAGF1acetiD7/MmIHcuDUYqiVsK38UYUxW3XUIOOWH8FpcAJ3+tOpO34kDd4LCBxe09BMbDaGruuSh7+JmbBKNgvX+kJu8b4I80vRs0SrrF9lqdjQ9q/BqwnxbBWXhCZo6dDZEEwwNtLyz6hiuafnZKZgZGb9gcNQ/kwccSnZuifhnNU5nHJL9eJJrAL+XY0l8OWVOMbmuX+iSW7b0yVWqgf3bTiAez2fUUhx1bWFQlOPo/Z5I8y2zZjzCKdFOk59J4hFAhtMGkw3LJmoCyqkVGxR2x1TnH0z8R8ScBZafV8RK4/GDQnOxNIPHIPtdRn8XIXtGkev/YE=
on:
tags: true
condition: '"$TRAVIS_TAG" =~ ^v[0-9]'
- provider: releases
skip_cleanup: true
file: build/*.zip
file_glob: true
prerelease: true
api_key:
secure: RFzhM7HoiSqoOt79Y1Obx7RkgO4UujKLTyqgci6vln0x5A/DchUh7rErpvDLNzvrDeIIp5S41MeQ+CJuVnL5BSWvhsf50/qmSfY2iky3Gl8r5qDG0uKffwPv5Pw+TmtiS3hy9n7PY4Py6u+2fIUChK7OKbPfvvjGLNWAqUi+B9U1c9qOBkHg2LkH+XdtO4dwsjHB/mZ4s10PntLfI6mA0RXIW8/mhYD4gYTWg/DtuenNMcZKDAP+z+GWZr8cen7haMOtoYqY9SA103VgeudXpSzZr5JKSMGnx6YrHicsGaRIal69sC6RspelJsW2+6yaQtIWH8zvb9IvFPv9QP3xYEftVkqxJXr9fsDBVFZIkrF3fCBf7at8UT1CVz3kEH07oc+RZahnVBNqvTbelO32whY2wSV7QBVg6xf0UEeP+un9eBIn1M9AUXiH90KskNVu+Gcs0kNqurpo/cEXXcAuGxK/2KGyfJkg9MKx1B6FmyW1QOIS8ZGOwiUha77fudDq+PUTrjByY2NEyk1GhUmildyoGx5Ds+vwqgBHHkGu7VVitltX7SnnMh48E3AeylYHE2iMSfDRujRefOgL3sEAnHjhU3yBnfRdPsD7jdi/Rux1qzbpVdK5u7gPxrr9SHYc49zVd6e7075UC7twiV99NQoYUpI+7f2q1KffRRt+q24=
on:
tags: true
condition: '"$TRAVIS_TAG" =~ ^v[0-9] && "$NPM_TAG" = "next"'
- provider: releases
skip_cleanup: true
file: build/*.zip
file_glob: true
prerelease: false
api_key:
secure: RFzhM7HoiSqoOt79Y1Obx7RkgO4UujKLTyqgci6vln0x5A/DchUh7rErpvDLNzvrDeIIp5S41MeQ+CJuVnL5BSWvhsf50/qmSfY2iky3Gl8r5qDG0uKffwPv5Pw+TmtiS3hy9n7PY4Py6u+2fIUChK7OKbPfvvjGLNWAqUi+B9U1c9qOBkHg2LkH+XdtO4dwsjHB/mZ4s10PntLfI6mA0RXIW8/mhYD4gYTWg/DtuenNMcZKDAP+z+GWZr8cen7haMOtoYqY9SA103VgeudXpSzZr5JKSMGnx6YrHicsGaRIal69sC6RspelJsW2+6yaQtIWH8zvb9IvFPv9QP3xYEftVkqxJXr9fsDBVFZIkrF3fCBf7at8UT1CVz3kEH07oc+RZahnVBNqvTbelO32whY2wSV7QBVg6xf0UEeP+un9eBIn1M9AUXiH90KskNVu+Gcs0kNqurpo/cEXXcAuGxK/2KGyfJkg9MKx1B6FmyW1QOIS8ZGOwiUha77fudDq+PUTrjByY2NEyk1GhUmildyoGx5Ds+vwqgBHHkGu7VVitltX7SnnMh48E3AeylYHE2iMSfDRujRefOgL3sEAnHjhU3yBnfRdPsD7jdi/Rux1qzbpVdK5u7gPxrr9SHYc49zVd6e7075UC7twiV99NQoYUpI+7f2q1KffRRt+q24=
on:
tags: true
condition: '"$TRAVIS_TAG" =~ ^v[0-9] && "$NPM_TAG" = "latest"'
================================================
FILE: README.md
================================================
# 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://npmjs.org/package/react-stdio) lets you render [React](https://reactjs.org/) components on the server, regardless of the backend technology you're using.
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.
## Installation
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
After installation, execute `react-stdio` to start the server.
To render a React component, write a JSON blob to stdin with any of the following properties:
component The path to a file that exports a React component (required)
props Any props you want to pass to the component (optional, default is {})
render The type of rendering (optional, default is renderToString)
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`.
Example:
$ echo '{"component":"./MyComponent","props":{"message":"hello"}}' | react-stdio
If you'd like to use a render method other than [`renderToString`](https://facebook.github.io/react/docs/top-level-api.html#reactdomserver.rendertostring) or [`renderToStaticMarkup`](https://facebook.github.io/react/docs/top-level-api.html#reactdomserver.rendertostaticmarkup) you can pass a path to a file that exports your rendering function. The signature of your `render` function should be:
```js
function render(element, callback) {
// ...
}
```
This function is asynchronous so you have time to do data fetching before you render if you wish. Call `callback(error, html)` when you're finished.
## Environment
Your component file is loaded in a vanilla node.js environment. If you need additional code transforms to run (e.g. using webpack or Browserify) you should create your bundle first and tell react-stdio to load your bundle instead of the plain component file. If you're using webpack to build your bundle, you'll want to use `"libraryTarget": "commonjs2"` in your config so the bundle exports the component using `module.exports = MyComponent`.
Also, since react-stdio uses the `stdout` stream for all program output, all writes your code makes to `process.stdout` (including `console.log` statements) are redirected to `process.stderr`.
## Integrations
* [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)!
================================================
FILE: jest.config.js
================================================
module.exports = {
testURL: 'http://localhost/'
};
================================================
FILE: modules/__mocks__/ContextComponent.js
================================================
const React = require("react");
let context = {};
function ContextComponent() {
context.test = true;
return React.createElement("div", null, "I am a context component");
}
ContextComponent.context = context;
module.exports = ContextComponent;
================================================
FILE: modules/__mocks__/TestComponent.js
================================================
const React = require("react");
function TestComponent() {
return React.createElement("div", null, "I am a test component");
}
module.exports = TestComponent;
================================================
FILE: modules/__tests__/server-test.js
================================================
const path = require('path');
const childProcess = require('child_process');
function mock(name) {
return path.join(__dirname, '..', '__mocks__', name);
}
describe('server', () => {
let proc;
beforeEach(() => {
proc = childProcess.spawn(path.join(__dirname, '..', 'cli.js'), {
stdio: 'pipe'
});
});
afterEach(() => {
proc.kill();
});
it('throws an error when component is missing', done => {
proc.stdin.write(JSON.stringify({}));
proc.stdout.once('data', out => {
expect(JSON.parse(out).error).toEqual('Missing { component } in request');
done();
});
});
it('throws an error when component cannot be found', done => {
proc.stdin.write(JSON.stringify({ component: 'component.js' }));
proc.stdout.once('data', out => {
expect(JSON.parse(out).error).toEqual(
'Cannot load component: component.js'
);
done();
});
});
it('renders the component', done => {
proc.stdin.write(
JSON.stringify({
component: mock('TestComponent.js')
})
);
proc.stdout.once('data', out => {
expect(JSON.parse(out).html).toMatch('I am a test component');
done();
});
});
it('renders a component and exposes additional context', done => {
proc.stdin.write(
JSON.stringify({
component: mock('ContextComponent.js')
})
);
proc.stdout.once('data', out => {
const result = JSON.parse(out);
expect(result.html).toMatch('I am a context component');
expect(result.context).toEqual({ test: true });
done();
});
});
});
================================================
FILE: modules/cli.js
================================================
#!/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);
================================================
FILE: modules/index.js
================================================
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
};
================================================
FILE: package.json
================================================
{
"name": "react-stdio",
"version": "3.4.8",
"description": "Render React.js components on any backend",
"author": "Michael Jackson",
"license": "MIT",
"bin": {
"react-stdio": "./modules/cli.js"
},
"files": [
"modules/cli.js",
"modules/index.js"
],
"preferGlobal": true,
"repository": "ReactTraining/react-stdio",
"scripts": {
"build": "./scripts/build.sh",
"clean": "git clean -fdX .",
"test": "jest"
},
"dependencies": {
"JSONStream": "^1.0.7",
"event-stream": "3.3.4",
"invariant": "^2.2.0",
"react": "^16.2.0",
"react-dom": "^16.2.0"
},
"devDependencies": {
"jest": "^22.1.4",
"pkg": "^4.3.4"
},
"jest": {
"testPathIgnorePatterns": [
"/node_modules/",
"__tests__/mocks"
]
}
}
================================================
FILE: scripts/build.sh
================================================
#!/bin/bash
mkdir -p build
tag=${TRAVIS_TAG:-"v$npm_package_version"}
# TODO: Enable x86 builds when https://github.com/zeit/pkg/issues/310 is fixed
platforms=( win-x64 linux-x64 macos )
for platform in "${platforms[@]}"
do
archive=react-stdio-$tag-$platform
echo "Creating $archive build..."
pkg modules/cli.js -t $platform -o build/$archive/react-stdio
echo "$tag" > build/$archive/version
cd build
zip -q -r $archive.zip $archive
cd - > /dev/null
done
gitextract_6n57gqjw/
├── .gitignore
├── .prettierignore
├── .travis.yml
├── README.md
├── jest.config.js
├── modules/
│ ├── __mocks__/
│ │ ├── ContextComponent.js
│ │ └── TestComponent.js
│ ├── __tests__/
│ │ └── server-test.js
│ ├── cli.js
│ └── index.js
├── package.json
└── scripts/
└── build.sh
SYMBOL INDEX (8 symbols across 4 files)
FILE: modules/__mocks__/ContextComponent.js
function ContextComponent (line 5) | function ContextComponent() {
FILE: modules/__mocks__/TestComponent.js
function TestComponent (line 3) | function TestComponent() {
FILE: modules/__tests__/server-test.js
function mock (line 4) | function mock(name) {
FILE: modules/index.js
function loadModule (line 6) | function loadModule(moduleId) {
function renderToStaticMarkup (line 22) | function renderToStaticMarkup(element, callback) {
function renderToString (line 26) | function renderToString(element, callback) {
function handleRequest (line 30) | function handleRequest(workingDir, request, callback) {
function createRequestHandler (line 78) | function createRequestHandler(workingDir) {
Condensed preview — 12 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (15K chars).
[
{
"path": ".gitignore",
"chars": 23,
"preview": "/build/\n/node_modules/\n"
},
{
"path": ".prettierignore",
"chars": 13,
"preview": "package.json\n"
},
{
"path": ".travis.yml",
"chars": 2851,
"preview": "language: node_js\nnode_js: 8\ncache:\n directories:\n - \"$HOME/.npm\"\n - \"$HOME/.pkg-cache\"\nenv:\n- NPM_TAG=$([[ \"$TRAVIS_"
},
{
"path": "README.md",
"chars": 3666,
"preview": "# react-stdio [![Travis][build-badge]][build] [![npm package][npm-badge]][npm]\n\n[build-badge]: https://img.shields.io/tr"
},
{
"path": "jest.config.js",
"chars": 53,
"preview": "module.exports = {\n testURL: 'http://localhost/'\n};\n"
},
{
"path": "modules/__mocks__/ContextComponent.js",
"chars": 251,
"preview": "const React = require(\"react\");\n\nlet context = {};\n\nfunction ContextComponent() {\n context.test = true;\n return React."
},
{
"path": "modules/__mocks__/TestComponent.js",
"chars": 163,
"preview": "const React = require(\"react\");\n\nfunction TestComponent() {\n return React.createElement(\"div\", null, \"I am a test compo"
},
{
"path": "modules/__tests__/server-test.js",
"chars": 1607,
"preview": "const path = require('path');\nconst childProcess = require('child_process');\n\nfunction mock(name) {\n return path.join(_"
},
{
"path": "modules/cli.js",
"chars": 823,
"preview": "#!/usr/bin/env node\n\nconst EventStream = require(\"event-stream\");\nconst JSONStream = require(\"JSONStream\");\nconst create"
},
{
"path": "modules/index.js",
"chars": 2692,
"preview": "const path = require(\"path\");\nconst invariant = require(\"invariant\");\nconst ReactDOMServer = require(\"react-dom/server\")"
},
{
"path": "package.json",
"chars": 790,
"preview": "{\n \"name\": \"react-stdio\",\n \"version\": \"3.4.8\",\n \"description\": \"Render React.js components on any backend\",\n \"author"
},
{
"path": "scripts/build.sh",
"chars": 476,
"preview": "#!/bin/bash\n\nmkdir -p build\n\ntag=${TRAVIS_TAG:-\"v$npm_package_version\"}\n\n# TODO: Enable x86 builds when https://github.c"
}
]
About this extraction
This page contains the full source code of the ReactTraining/react-stdio GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 12 files (13.1 KB), approximately 4.5k tokens, and a symbol index with 8 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.