{"id":13764851,"url":"https://github.com/jaredLunde/react-broker","last_synced_at":"2025-05-10T20:31:16.731Z","repository":{"id":32937013,"uuid":"146973294","full_name":"jaredLunde/react-broker","owner":"jaredLunde","description":"💸 SSR-capable async components \u0026 code splitting with Webpack 4+ and Babel 7+","archived":false,"fork":false,"pushed_at":"2023-01-03T17:12:07.000Z","size":2162,"stargazers_count":25,"open_issues_count":61,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-13T21:06:54.630Z","etag":null,"topics":["async","code-splitting","lazy","lazyload","react","reactjs","server-side-rendering","ssr","webpack","webpack4"],"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/jaredLunde.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-09-01T06:16:49.000Z","updated_at":"2022-12-29T17:53:48.000Z","dependencies_parsed_at":"2023-01-14T22:45:24.133Z","dependency_job_id":null,"html_url":"https://github.com/jaredLunde/react-broker","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaredLunde%2Freact-broker","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaredLunde%2Freact-broker/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaredLunde%2Freact-broker/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaredLunde%2Freact-broker/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jaredLunde","download_url":"https://codeload.github.com/jaredLunde/react-broker/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253480422,"owners_count":21915246,"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":["async","code-splitting","lazy","lazyload","react","reactjs","server-side-rendering","ssr","webpack","webpack4"],"created_at":"2024-08-03T16:00:30.449Z","updated_at":"2025-05-10T20:31:12.041Z","avatar_url":"https://github.com/jaredLunde.png","language":"JavaScript","funding_links":[],"categories":["Macros"],"sub_categories":["React"],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003ch1 align=\"center\"\u003e\n    react-broker\n  \u003c/h1\u003e\n  \u003cimg alt=\"Wolf of Wall Street Gif\" src=\"https://media.giphy.com/media/8Q31McooUHTNu/giphy.gif\"\u003e\n\u003c/div\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://bundlephobia.com/result?p=react-broker\"\u003e\n    \u003cimg alt=\"Bundlephobia\" src=\"https://img.shields.io/bundlephobia/minzip/react-broker?style=for-the-badge\u0026labelColor=24292e\"\u003e\n  \u003c/a\u003e\n  \u003c!--\u003ca aria-label=\"Code coverage report\" href=\"https://codecov.io/gh/jaredLunde/react-broker\"\u003e\n    \u003cimg alt=\"Code coverage\" src=\"https://img.shields.io/codecov/c/gh/jaredLunde/react-broker?style=for-the-badge\u0026labelColor=24292e\"\u003e\n  \u003c/a\u003e\n  \u003ca aria-label=\"Build status\" href=\"https://travis-ci.org/jaredLunde/react-broker\"\u003e\n    \u003cimg alt=\"Build status\" src=\"https://img.shields.io/travis/jaredLunde/react-broker?style=for-the-badge\u0026labelColor=24292e\"\u003e\n  \u003c/a\u003e--\u003e\n  \u003ca aria-label=\"NPM version\" href=\"https://www.npmjs.com/package/react-broker\"\u003e\n    \u003cimg alt=\"NPM Version\" src=\"https://img.shields.io/npm/v/react-broker?style=for-the-badge\u0026labelColor=24292e\"\u003e\n  \u003c/a\u003e\n  \u003ca aria-label=\"License\" href=\"https://jaredlunde.mit-license.org/\"\u003e\n    \u003cimg alt=\"MIT License\" src=\"https://img.shields.io/npm/l/react-broker?style=for-the-badge\u0026labelColor=24292e\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cpre align=\"center\"\u003e\nnpm i react-broker\n\u003c/pre\u003e\n\u003chr\u003e\n\nA  [lightweight](https://bundlephobia.com/result?p=react-broker) library for lazy components using React 16.8+. It's perfect for \ncode splitting and has the simplest SSR story you've ever seen out-of-the-box.\n\nCritically, this package is only intended to work with Webpack, specifically\nWebpack 4 and future versions. There are no plans to implement a design\naccommodating Parcel or other bundlers. There is also a hard requirement\nfor `babel-plugin-macros` (which is shipped with CRA) if you opt to use the macro.\n\n## Quick Start\n\n```js\nimport {BrokerProvider} from 'react-broker'\nimport lazy from 'react-broker/macro'\n\n// Automatically generates dynamic imports for webpack with babel-plugin-macros. \n// Just give it the path.\nconst LazyPage = lazy('../pages/Page', {loading: props =\u003e 'Loading...'})\n\n////////////////////////////////////////////////////////////////////////////////\n//                               ⬇ BECOMES ⬇                                //\n///////////////////////////////////////////////////////////////////////////////\n\nconst LazyPage =\n  require('react-broker').lazy(\n    'src/pages/Page',\n    () =\u003e import(/* webpackChunkName: \"src/pages/Page\" */ '../pages/Page'),\n    {loading: props =\u003e 'Loading...'}\n  )\n  \nfunction App () {\n  // Look at me! I'm used like a normal component.\n  return (\n    \u003cBrokerProvider\u003e\n      \u003cLazyPage id='1'/\u003e\n    \u003c/BrokerProvider/\u003e\n   )\n}\n```\n\n### Requirements\n- Webpack 4+ (because `chunks`)\n- React 16.8+ (because `hooks`)\n- Babel (because `babel-plugin-macros`)\n\n### Examples\n**[Hello world](examples/hello-world)**\u003cbr/\u003e\n**[Hello world w/ Router](examples/hello-world-router)**\n\n--------------------------------------------------------------------------------\n\n## API\n\n### `react-broker/macro`\nThe function that transforms your imports and delegates your async components.\n\n```js\nimport lazy from 'react-broker/macro'\n```\n\n#### `lazy(component \u003cString\u003e, options \u003cObject\u003e)`\n**component** `{String}`\u003cbr/\u003e\nA path to a React component you want to lazy load. The component must be in the `default` \nexport of the file. \n\nPaths cannot be passed via an identifier, it has to be a plain string. It is used just like a \nregular component. \n\nYou may also lazy load external library components, but just know that the component in question must be the \n`default` export.\n```js\n// Used like a regular component\nconst LazyPage = lazy('./pages/Home', {loading: props =\u003e 'Loading ${props.id}...'})\n\n\u003cLazyPage id={1}\u003e\n  // ...\n\u003c/LazyPage\u003e\n```\n\n**options** `{Object}`\u003cbr/\u003e\n- `loading (props, context{retry, error})`\n  - **props** props passed the component\n  - **context**\n    - `retry` is a function which will force a reload of the component\n    - `error` is any error returned by `Promise.reject`, this is only relevant\n      if an `error` component isn't also defined in options\n- `error (props, context{retry, error})`\n  - See `loading`\n--------------------------------------------------------------------------------\n\n### `Broker.Provider`\nManages code-splitting and the resolution of your async components by\nkeeping track of which chunk names have been loaded and also determining\nwhich `\u003cscripts\u003e` need to be included from the server-side. `Broker.Provider`\nmust be defined at the top-level of your lazy loaded components.\n\n#### Props\n##### chunkCache `{Broker.createChunkCache}`\nYou only provide a `chunkCache` on the server side. In the client it is not\nallowed. The chunk cache is used for tracking which chunks were loaded during\nthe latest render phase of the app.\n`Broker.createChunkCache`\n\n```js\nimport * as Broker from 'react-broker'\n\nconst chunkCache = Broker.createChunkCache()\n\nfunction App (props) {\n  return (\n    \u003cBroker.Provider chunkCache={chunkCache}\u003e\n      \u003cLazyPage id={props.id}/\u003e\n    \u003c/Broker.Provider\u003e\n  )\n}\n```\n--------------------------------------------------------------------------------\n\n### `Broker.createChunkCache`\nCreates a context for `Broker.Provider` to track chunks in and provides\nhelper methods to provide access to those chunks.\n\n##### `createChunkCache.getChunkNames()`\nReturns an `array` of all the Webpack chunk names loaded into the current app.\n\n##### `createChunkCache.getChunks(webpackStats)`\nReturns a `Set` of all the Webpack chunks loaded into the current app.\n- `webpackStats` `\u003cObject\u003e`\n  - The [stats](https://webpack.js.org/configuration/stats/) object created by \n    Webpack.\n    \n##### `createChunkCache.getChunkScripts(webpackStats, options)`\nReturns a `string` representation of all the `\u003cscript\u003e` tags to include in the\noutput of your app when using with SSR.\n- `webpackStats` `{Object}`\n  - The [stats](https://webpack.js.org/configuration/stats/) object created by \n    Webpack.\n- `options` `{Object}`\n  - `preload` `{Bool|Object}`\n     - If `true`, this will generate `\u003clink rel='preload'\u003e` tags with your scripts.\n     - If an `object`, the key/value pairs will be added to the `\u003clink rel='preload'\u003e` \n       tags as attributes. e.g. `{preload: {crossorigin: 'anonymous'}}` generates\n       `\u003clink rel='preload' as='script' crossorigin='anonymous' href='...'\u003e`\n  - `async` `{Bool}`\n     - If `true`, an `async` flag will be added to your `\u003cscript\u003e` tags\n     - **default** `true`\n  - `defer` `{Bool}`\n     - If `true`, a `defer` flag will be added to your `\u003cscript\u003e` tags and `async`\n       will be omitted\n     - **default** `false`\n\n#### See the [SSR section](#serverrenderjs) for an example\n\n--------------------------------------------------------------------------------\n\n### `Broker.lazy`\nThis is the function created by `react-broker/macro`.\n\nTo skip the macro you could do something like this with the Webpack code-splitting\nAPI:\n```js\nimport {lazy} from 'react-broker'\nconst Component = lazy(\n  'uniqueChunkName', \n  () =\u003e import(/* webpackChunkName: \"uniqueChunkName\" */'./path/to/component'), \n  {loading: props =\u003e 'Loading...'}\n)\n```\n\n#### `Lazy.load()`\nPreloads the component.\n```js\nconst LazyPage = lazy('./pages/Home')\n// ...\n\u003cLink onMouseEnter={LazyPage.load}\u003e\n  Home\n\u003c/Link\u003e\n```\n\n--------------------------------------------------------------------------------\n\n### `Broker.load(...components \u003cString\u003e)`\nPreloads one or several `Lazy` components.\n\n```js\nimport * as Broker from 'react-broker'\nimport lazy from 'react-broker/macro'\n\nconst LazyA = lazy('./A')\nconst LazyB = lazy('./B')\n\nBroker.load(LazyA, LazyB).then(/*...*/)\n```\n\n--------------------------------------------------------------------------------\n\n### `Broker.loadAll(`\n#### `  App: React.Element,`\n#### `  renderer: ReactDOM.renderToStaticMarkup|renderToString`\n### `)`\nTracks all of the chunks used in your app during the server side render and\noptionally renders your app to a string\n\n- `App` `{React.Element}`\n  - Your React application\n- `renderer` `{ReactDOM.renderToStaticMarkup|ReactDOM.renderToString}`\n  - **default** `ReactDOM.renderToStaticMarkup`\n  - The renderer used for determining the chunks used in your app. To avoid,\n    extra renders, you could change this to `ReactDOM.renderToString.\n  \n#### See the [SSR section](#serverrenderjs) for an example\n\n--------------------------------------------------------------------------------\n\n### `Broker.loadInitial(chunkCache: Broker.createChunkCache)`\nPopulates your chunk cache with the async components present in your application.\nThis requires that `Broker.getChunkScripts` was used on the server side. The primary\nuse case for this function is elimination loading components and flashes when \ninitially rendering your app in the browser.\n\n#### See the [SSR section](#clientrenderjs) for an example\n\n-------------------------------------------------------------------------------\n\n## Server-side Rendering\n\n#### client/render.js\n```js\nimport React from 'react'\nimport ReactDOM from 'react-dom'\nimport * as Broker from 'react-broker'\nimport App from '../App'\n\n\nconst app = (\n  \u003cBroker.Provider\u003e\n    \u003cApp/\u003e\n  \u003c/Broker.Provider\u003e\n)\n\nBroker.loadInitial().then(\n  () =\u003e ReactDOM.hydrate(app, document.getElementById('⚛️'))\n)\n```\n\n#### server/render.js\n```js\nimport React from 'react'\nimport ReactDOMServer from 'react-dom/server'\nimport express from 'express'\nimport * as Broker from 'react-broker'\nimport App from '../App'\n\n\nexport default function createRenderer({\n  // These are the Webpack compilation stats returned by Webpack post-run.\n  // https://webpack.js.org/api/stats/\n  clientStats\n}) {\n  app = express()\n\n  app.get('*', /* Note 'async' here */ async (req, res, next) =\u003e {\n    res.set('Content-Type', 'text/html')\n    // keeps track of lazy chunks used by the current page\n    const chunkCache = Broker.createChunkCache()\n    // chunkCache is passed to Broker.Provider as a prop\n    const app = (\n      \u003cBroker.Provider chunkCache={chunkCache}\u003e\n        \u003cApp/\u003e\n      \u003c/Broker.Provider\u003e\n    )\n    // Preloads the async components and renders the app to a string\n    const page = await Broker.loadAll(app, ReactDOMServer.renderToString)\n    // You could also do this if you have other requirements in addition to preloading with\n    // react-broker\n    // await Broker.loadAll(app, ReactDOMServer.renderToStaticMarkup)\n    // const page = await ReactDOMServer.renderToString(app)\n    \n    // Generates \u003cscript\u003e and \u003cpreload\u003e tags for this page\n    const chunks = chunkCache.getChunkScripts(clientStats, {preload: true})\n\n    res.send(`\n      \u003chtml\u003e\n        \u003chead\u003e\n          ${chunks.preload}\n        \u003c/head\u003e\n        \u003cbody\u003e\n          \u003cdiv id='⚛️'\u003e\n            ${app}\n          \u003c/div\u003e\n          ${chunks.scripts}\n        \u003c/body\u003e\n      \u003c/html\u003e\n    `)\n  })\n\n  return app\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FjaredLunde%2Freact-broker","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FjaredLunde%2Freact-broker","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FjaredLunde%2Freact-broker/lists"}