{"id":31392840,"url":"https://github.com/formidablelabs/react-ssr-prepass","last_synced_at":"2025-09-29T04:47:51.999Z","repository":{"id":37663862,"uuid":"175187015","full_name":"FormidableLabs/react-ssr-prepass","owner":"FormidableLabs","description":"A custom partial React SSR renderer for prefetching and suspense","archived":false,"fork":false,"pushed_at":"2024-11-05T21:23:06.000Z","size":647,"stargazers_count":606,"open_issues_count":9,"forks_count":27,"subscribers_count":46,"default_branch":"master","last_synced_at":"2025-09-13T21:41:15.656Z","etag":null,"topics":["react","react-dom","server-side-rendering"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/FormidableLabs.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-03-12T10:25:13.000Z","updated_at":"2025-08-25T19:32:08.000Z","dependencies_parsed_at":"2024-06-18T12:27:16.443Z","dependency_job_id":"dd63f0a6-47ae-4fcc-9bfb-b6295a4ee861","html_url":"https://github.com/FormidableLabs/react-ssr-prepass","commit_stats":{"total_commits":121,"total_committers":8,"mean_commits":15.125,"dds":0.09917355371900827,"last_synced_commit":"099119761074dc35d2bc0d884297e6c84c77f684"},"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"purl":"pkg:github/FormidableLabs/react-ssr-prepass","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FormidableLabs%2Freact-ssr-prepass","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FormidableLabs%2Freact-ssr-prepass/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FormidableLabs%2Freact-ssr-prepass/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FormidableLabs%2Freact-ssr-prepass/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/FormidableLabs","download_url":"https://codeload.github.com/FormidableLabs/react-ssr-prepass/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FormidableLabs%2Freact-ssr-prepass/sbom","scorecard":{"id":51783,"data":{"date":"2025-08-11","repo":{"name":"github.com/FormidableLabs/react-ssr-prepass","commit":"e48a7788e3386719a82b507f3aa0ba5f28efbdd1"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.8,"checks":[{"name":"Code-Review","score":3,"reason":"Found 11/30 approved changesets -- score normalized to 3","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/FormidableLabs/react-ssr-prepass/ci.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/FormidableLabs/react-ssr-prepass/ci.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/FormidableLabs/react-ssr-prepass/release.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:23: update your workflow using https://app.stepsecurity.io/secureworkflow/FormidableLabs/react-ssr-prepass/release.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/release.yml:39: update your workflow using https://app.stepsecurity.io/secureworkflow/FormidableLabs/react-ssr-prepass/release.yml/master?enable=pin","Info:   0 out of   4 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: jobLevel 'packages' permission set to 'write': .github/workflows/release.yml:16","Warn: jobLevel 'contents' permission set to 'write': .github/workflows/release.yml:11","Warn: jobLevel 'deployments' permission set to 'write': .github/workflows/release.yml:15","Warn: no topLevel permission defined: .github/workflows/ci.yml:1","Warn: no topLevel permission defined: .github/workflows/release.yml:1"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 12 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"19 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-r683-j2x4-v87g","Warn: Project is vulnerable to: GHSA-gcx4-mw62-g8wm","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-4x5v-gmq8-25ch","Warn: Project is vulnerable to: GHSA-4wf5-vphf-c2xc","Warn: Project is vulnerable to: GHSA-52f5-9888-hmc6","Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3","Warn: Project is vulnerable to: GHSA-j8xg-fqg3-53r7","Warn: Project is vulnerable to: GHSA-3h5v-q93c-6h6q"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-14T23:52:45.125Z","repository_id":37663862,"created_at":"2025-08-14T23:52:45.125Z","updated_at":"2025-08-14T23:52:45.125Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":277467480,"owners_count":25822917,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-29T02:00:09.175Z","response_time":84,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["react","react-dom","server-side-rendering"],"created_at":"2025-09-29T04:47:50.897Z","updated_at":"2025-09-29T04:47:51.994Z","avatar_url":"https://github.com/FormidableLabs.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# react-ssr-prepass\n\n\u003cp\u003e\n  \u003ca href=\"https://travis-ci.com/FormidableLabs/react-ssr-prepass\"\u003e\n    \u003cimg alt=\"Build Status\" src=\"https://travis-ci.com/FormidableLabs/react-ssr-prepass.svg?branch=master\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://codecov.io/gh/FormidableLabs/react-ssr-prepass\"\u003e\n    \u003cimg alt=\"Test Coverage\" src=\"https://codecov.io/gh/FormidableLabs/react-ssr-prepass/branch/master/graph/badge.svg\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://npmjs.com/package/react-ssr-prepass\"\u003e\n    \u003cimg alt=\"NPM Version\" src=\"https://img.shields.io/npm/v/react-ssr-prepass.svg\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/FormidableLabs/react-ssr-prepass#maintenance-status\"\u003e\n    \u003cimg alt=\"Maintenance Status\" src=\"https://img.shields.io/badge/maintenance-experimental-blueviolet.svg\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp\u003e\n  \u003ccode\u003ereact-dom/server\u003c/code\u003e does not have support for suspense yet.\u003cbr /\u003e\n  \u003ccode\u003ereact-ssr-prepass\u003c/code\u003e offers suspense on the server-side today, until it does. ✨\n\u003c/p\u003e\n\n`react-ssr-prepass` is a **partial server-side React renderer** that does a prepass\non a React element tree and suspends when it finds thrown promises. It also\naccepts a visitor function that can be used to suspend on anything.\n\nYou can use it to fetch data before your SSR code calls `renderToString` or\n`renderToNodeStream`.\n\n\u003e ⚠️ **Note:** Suspense is unstable and experimental. This library purely\n\u003e exists since `react-dom/server` does not support data fetching or suspense\n\u003e yet. This two-pass approach should just be used until server-side suspense\n\u003e support lands in React.\n\n## The Why \u0026 How\n\nIt's quite common to have some data that needs to be fetched before\nserver-side rendering and often it's inconvenient to specifically call\nout to random fetch calls to get some data. Instead **Suspense**\noffers a practical way to automatically fetch some required data,\nbut is currently only supported in client-side React.\n\n`react-ssr-prepass` offers a solution by being a \"prepass\" function\nthat walks a React element tree and executing suspense. It finds all\nthrown promises (a custom visitor can also be provided) and waits for\nthose promises to resolve before continuing to walk that particular\nsuspended subtree. Hence, it attempts to offer a practical way to\nuse suspense and complex data fetching logic today.\n\nA two-pass React render is already quite common for in other libraries\nthat do implement data fetching. This has however become quite impractical.\nWhile it was trivial to previously implement a primitive React renderer,\nthese days a lot more moving parts are involved to make such a renderer\ncorrect and stable. This is why some implementations now simply rely\non calling `renderToStaticMarkup` repeatedly.\n\n`react-ssr-prepass` on the other hand is a custom implementation\nof a React renderer. It attempts to stay true and correct to the\nReact implementation by:\n\n- Mirroring some of the implementation of `ReactPartialRenderer`\n- Leaning on React elements' symbols from `react-is`\n- Providing only the simplest support for suspense\n\n## Quick Start Guide\n\nFirst install `react-ssr-prepass` alongside `react` and `react-dom`:\n\n```sh\nyarn add react-ssr-prepass\n# or\nnpm install --save react-ssr-prepass\n```\n\nIn your SSR code you may now add it in front of your usual `renderToString`\nor `renderToNodeStream` code:\n\n```js\nimport { createElement } from 'react'\nimport { renderToString } from 'react-dom/server'\n\nimport ssrPrepass from 'react-ssr-prepass'\n\nconst renderApp = async (App) =\u003e {\n  const element = createElement(App)\n  await ssrPrepass(element)\n\n  return renderToString(element)\n}\n```\n\nAdditionally you can also pass a \"visitor function\" as your second argument.\nThis function is called for every React class or function element that is\nencountered.\n\n```js\nssrPrepass(\u003cApp /\u003e, (element, instance) =\u003e {\n  if (element.type === SomeData) {\n    return fetchData()\n  } else if (instance \u0026\u0026 instance.fetchData) {\n    return instance.fetchData()\n  }\n})\n```\n\nThe first argument of the visitor is the React element. The second is\nthe instance of a class component or undefined. When you return\na promise from this function `react-ssr-prepass` will suspend before\nrendering this element.\n\nYou should be aware that `react-ssr-prepass` does not handle any\ndata rehydration. In most cases it's fine to collect data from your cache\nor store after running `ssrPrepass`, turn it into JSON, and send it\ndown in your HTML result.\n\n## Prior Art\n\nThis library is (luckily) not a reimplementation from scratch of\nReact's server-side rendering. Instead it's mostly based on\nReact's own server-side rendering logic that resides in its\n[`ReactPartialRenderer`](https://github.com/facebook/react/blob/13645d2/packages/react-dom/src/server/ReactPartialRenderer.js).\n\nThe approach of doing an initial \"data fetching pass\" is inspired by:\n\n- [`react-apollo`'s `getDataFromTree`](https://github.com/apollographql/react-apollo/blob/master/src/getDataFromTree.ts)\n- [`react-tree-walker`](https://github.com/ctrlplusb/react-tree-walker)\n\n## Maintenance Status\n\n**Experimental:** This project is quite new. We're not sure what our ongoing maintenance plan for this project will be. Bug reports, feature requests and pull requests are welcome. If you like this project, let us know!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fformidablelabs%2Freact-ssr-prepass","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fformidablelabs%2Freact-ssr-prepass","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fformidablelabs%2Freact-ssr-prepass/lists"}