{"id":13469658,"url":"https://github.com/transitive-bullshit/react-static-tweets","last_synced_at":"2025-03-26T07:30:56.780Z","repository":{"id":38109890,"uuid":"338955601","full_name":"transitive-bullshit/react-static-tweets","owner":"transitive-bullshit","description":"Extremely fast static renderer for tweets.","archived":true,"fork":false,"pushed_at":"2024-04-24T05:33:03.000Z","size":912,"stargazers_count":565,"open_issues_count":18,"forks_count":46,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-10-29T23:55:46.555Z","etag":null,"topics":["nextjs","react","ssr","tweet","tweets","twitter"],"latest_commit_sha":null,"homepage":"https://react-tweet.vercel.app","language":"TypeScript","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/transitive-bullshit.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":".github/funding.yml","license":"license","code_of_conduct":null,"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},"funding":{"github":["transitive-bullshit"]}},"created_at":"2021-02-15T03:15:18.000Z","updated_at":"2024-09-18T21:06:33.000Z","dependencies_parsed_at":"2024-06-18T18:35:01.967Z","dependency_job_id":"5630ad16-bbed-4a99-b62d-8276d5c4cc94","html_url":"https://github.com/transitive-bullshit/react-static-tweets","commit_stats":{"total_commits":150,"total_committers":10,"mean_commits":15.0,"dds":"0.16000000000000003","last_synced_commit":"bdfc1e4c1bcedbc2aa89b7f7cc1957a370705f1e"},"previous_names":[],"tags_count":34,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/transitive-bullshit%2Freact-static-tweets","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/transitive-bullshit%2Freact-static-tweets/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/transitive-bullshit%2Freact-static-tweets/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/transitive-bullshit%2Freact-static-tweets/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/transitive-bullshit","download_url":"https://codeload.github.com/transitive-bullshit/react-static-tweets/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245401372,"owners_count":20609163,"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","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":["nextjs","react","ssr","tweet","tweets","twitter"],"created_at":"2024-07-31T15:01:49.205Z","updated_at":"2025-03-26T07:30:56.162Z","avatar_url":"https://github.com/transitive-bullshit.png","language":"TypeScript","funding_links":["https://github.com/sponsors/transitive-bullshit"],"categories":["TypeScript"],"sub_categories":[],"readme":"# Deprecation Notice\n\nVercel released [react-tweet](https://github.com/vercel/react-tweet) which is a better maintained version of this library. Please use that instead.\n\n---\n\n# React Static Tweets\n\n\u003e Extremely fast static renderer for tweets.\n\n[![NPM](https://img.shields.io/npm/v/react-static-tweets.svg)](https://www.npmjs.com/package/react-static-tweets) [![Build Status](https://github.com/transitive-bullshit/react-static-tweets/actions/workflows/test.yml/badge.svg)](https://github.com/transitive-bullshit/react-static-tweets/actions/workflows/test.yml) [![Prettier Code Formatting](https://img.shields.io/badge/code_style-prettier-brightgreen.svg)](https://prettier.io)\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://react-static-tweets.vercel.app/1352687755621351425\"\u003e\n    \u003cimg alt=\"React Static Tweets\" src=\"https://raw.githubusercontent.com/transitive-bullshit/react-static-tweets/master/example/demo.jpg\" width=\"550\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n## Demo\n\nVisit [react-static-tweets.vercel.app](https://react-static-tweets.vercel.app/1352687755621351425) and append your tweet ID. You can also append `/dynamic/\u003ctweetId\u003e` if you want to test the non-SSR version.\n\n## Why?\n\nTwitter's embedding SDK is horribly slow and inefficient. For embedding tweets on your site (including SSR), this solution is significantly more performant. 🔥\n\nThis project takes Vercel's work on [static tweet rendering](https://static-tweet.vercel.app) and packages it up into two easy-to-use NPM packages.\n\n## Features\n\n- ⚡ **Fast** - 10-100x faster than using Twitter's iframe embedding.\n- 🔥 **Solid** - Used in production by [super.so](https://s.super.so/x), [react-notion-x](https://transitivebullsh.it/nextjs-notion-starter-kit), and others.\n- 🚀 **Simple** - TypeScript + React.\n\n## Install\n\n```bash\nnpm install react-static-tweets static-tweets date-fns\n# or\nyarn add react-static-tweets static-tweets date-fns\n```\n\nNote: this project currently only works with **Next.js** (see [#2](https://github.com/transitive-bullshit/react-static-tweets/issues/2) for more info).\n\n## Usage\n\nYou'll need to pre-fetch tweet data server-side using `fetchTweetAst` and then render it using the `Tweet` component.\n\n```tsx\nimport React from 'react'\nimport { fetchTweetAst } from 'static-tweets'\nimport { Tweet } from 'react-static-tweets'\n\nconst tweetId = '1358199505280262150'\n\nexport const getStaticProps = async () =\u003e {\n  try {\n    const tweetAst = await fetchTweetAst(tweetId)\n\n    return {\n      props: {\n        tweetAst\n      },\n      revalidate: 10\n    }\n  } catch (err) {\n    console.error('error fetching tweet', err)\n\n    throw err\n  }\n}\n\nexport default function Example({ tweetAst }) {\n  return \u003cTweet ast={tweetAst} /\u003e\n}\n```\n\nNote that `Tweet` is a React server component, and has been tested with Next.js 13 `appDir`.\n\n## Advanced Usage\n\nIf you have multiple tweets and are okay with using client components, then we recommend using the built-in `TwitterContextProvider` to store a map from tweet ID to tweet AST.\n\nIn this example, we're using the client component imports from `react-static/tweets/client` which use React Context under the hood:\n\n```tsx\nimport React from 'react'\nimport pMap from 'p-map'\nimport { fetchTweetAst } from 'static-tweets'\nimport { TweetClient, TwitterContextProvider } from 'react-static-tweets/client'\n\n// NOTE: You'll likely infer your list of tweets by introspecting your page's\n// content from a CMS.\nconst tweetIds = [\n  '1358199505280262150',\n  '1374492662061953034',\n  '1358199505280262150'\n  // ...\n]\n\nexport const getStaticProps = async () =\u003e {\n  try {\n    // Fetch all tweet ASTs statically\n    const tweetAsts = await pMap(tweetIds, fetchTweetAst, {\n      concurrency: 4\n    })\n\n    // Create a map from tweet ID to tweet AST\n    const tweetAstMap = tweetIds.reduce((tweetId, map, index) =\u003e ({\n      ...map,\n      [tweetId]: tweetAsts[index]\n    }))\n\n    return {\n      props: {\n        tweetAstMap\n      },\n      revalidate: 60\n    }\n  } catch (err) {\n    console.error('error fetching tweets', err)\n\n    throw err\n  }\n}\n\nexport default function Example({ tweetAstMap }) {\n  return (\n    \u003cTwitterContextProvider value={{ tweetAstMap }}\u003e\n      {tweetIds.map((tweetId) =\u003e (\n        \u003cdiv key={tweetId}\u003e\n          {/* \n          There's no need to pass the tweet AST directly if it is provided via TwitterContextProvider. This is nice in situations where you're \n          rendering tweets in deeply nested component trees.\n          */}\n          \u003cTweetClient id={tweetId} /\u003e\n        \u003c/div\u003e\n      ))}\n    \u003c/TwitterContextProvider\u003e\n  )\n}\n```\n\n## Styles\n\nYou'll need to import some CSS styles as well. For Next.js, we recommend you put these in `pages/_app`:\n\n```ts\nimport 'react-static-tweets/styles.css'\n```\n\n## Next.js Config\n\nAdd `pbs.twimg.com` to your `next.config.js` since we use `next/image` to load images.\n\n```js\nmodule.exports = {\n  images: {\n    domains: ['pbs.twimg.com']\n  }\n}\n```\n\n## Next.js Example\n\nHere is an [example Next.js project](./example), with the most important code in [`pages/[tweetId].tsx`](./example/pages/%5BtweetId%5D.tsx). You can view this example [live on Vercel](https://react-static-tweets.vercel.app).\n\n## Packages\n\n| Package                                               | NPM                                                                                                               | Environment   | Description                             |\n| ----------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | ------------- | --------------------------------------- |\n| [static-tweets](./packages/static-tweets)             | [![NPM](https://img.shields.io/npm/v/static-tweets.svg)](https://www.npmjs.com/package/static-tweets)             | Node.js       | Fetches tweet ASTs.                     |\n| [react-static-tweets](./packages/react-static-tweets) | [![NPM](https://img.shields.io/npm/v/react-static-tweets.svg)](https://www.npmjs.com/package/react-static-tweets) | Browser + SSR | React renderer for tweets given an AST. |\n\n## Dynamic Client-Side Rendering\n\n`react-static-tweets` is meant for rendering tweets as efficiently as possible. The `Tweet` component assumes that you've already pre-fetched tweet AST data ahead of time, most likely during SSR.\n\nRendering dynamic tweets on the client-side is supported; however, you'll need to wrap `fetchTweetAst` in an API route since it can't be used from the browser.\n\nYou can view an example of this in action via [`example/pages/dynamic/[tweetId].tsx`](./example/pages/dynamic/%5BtweetId%5D.tsx).\n\n## Credit\n\nMy main contribution is packaging the Vercel team's excellent work into two isolated packages: `static-tweets` for server-side fetching of tweet ASTs and `react-static-tweets` for client-side rendering as well as SSR.\n\n- Inspired by this [demo](https://static-tweet.vercel.app/) from the Vercel team\n- And the underlying [repo](https://github.com/lfades/static-tweet) by [Luis Alvarez](https://github.com/lfades)\n- Most of the core code is adapted from [Guillermo Rauch's blog](https://github.com/rauchg/blog/blob/master/pages/2020/2019-in-review.js)\n- Converted the JS codebase to TypeScript\n- Removed `styled-jsx` because using a flat CSS file (with a `.static-tweet` class prefix) makes bundling for NPM easier\n- Fixed some minor formatting bugs\n\n## License\n\nMIT © [Travis Fischer](https://transitivebullsh.it)\n\nSupport my OSS work by \u003ca href=\"https://twitter.com/transitive_bs\"\u003efollowing me on twitter \u003cimg src=\"https://storage.googleapis.com/saasify-assets/twitter-logo.svg\" alt=\"twitter\" height=\"24px\" align=\"center\"\u003e\u003c/a\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftransitive-bullshit%2Freact-static-tweets","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftransitive-bullshit%2Freact-static-tweets","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftransitive-bullshit%2Freact-static-tweets/lists"}