{"id":13607190,"url":"https://github.com/Daydreamer-riri/vite-react-ssg","last_synced_at":"2025-04-12T11:31:40.305Z","repository":{"id":182512696,"uuid":"664961657","full_name":"Daydreamer-riri/vite-react-ssg","owner":"Daydreamer-riri","description":"Static-site generation for React on Vite.","archived":false,"fork":false,"pushed_at":"2025-02-26T08:37:59.000Z","size":1193,"stargazers_count":160,"open_issues_count":4,"forks_count":8,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-09T10:01:37.115Z","etag":null,"topics":["build","react","react-ssg","ssg","vite","vite-ssg"],"latest_commit_sha":null,"homepage":"https://vite-react-ssg.netlify.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/Daydreamer-riri.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"github":["Daydreamer-riri"]}},"created_at":"2023-07-11T06:18:57.000Z","updated_at":"2025-04-04T03:28:10.000Z","dependencies_parsed_at":"2023-07-20T09:53:38.360Z","dependency_job_id":"fe53338d-7de8-4ae1-8e37-411962d7ba70","html_url":"https://github.com/Daydreamer-riri/vite-react-ssg","commit_stats":null,"previous_names":["daydreamer-riri/vite-react-ssg"],"tags_count":38,"template":false,"template_full_name":"Daydreamer-riri/starter-lib","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Daydreamer-riri%2Fvite-react-ssg","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Daydreamer-riri%2Fvite-react-ssg/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Daydreamer-riri%2Fvite-react-ssg/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Daydreamer-riri%2Fvite-react-ssg/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Daydreamer-riri","download_url":"https://codeload.github.com/Daydreamer-riri/vite-react-ssg/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248560152,"owners_count":21124601,"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":["build","react","react-ssg","ssg","vite","vite-ssg"],"created_at":"2024-08-01T19:01:16.361Z","updated_at":"2025-04-12T11:31:40.292Z","avatar_url":"https://github.com/Daydreamer-riri.png","language":"TypeScript","funding_links":["https://github.com/sponsors/Daydreamer-riri"],"categories":["Plugins"],"sub_categories":["React"],"readme":"# Vite React SSG\n\nStatic-site generation for React on Vite.\n\nSee demo(also document): [docs](https://vite-react-ssg.netlify.app/)\n\n**🎈 Support for [`@tanstack/router`](https://tanstack.com/router/latest/docs/framework/react/overview)\nand [`wouter`](https://github.com/molefrog/wouter) is in progress!**\n\nSupport for the [`@tanstack/router`](https://tanstack.com/router/latest/docs/framework/react/overview) router is still experimental, and `pathname.lazy.tsx routes` are not yet supported.\nFor usage examples, see: [`main`/examples/tanstack/src/main.tsx](https://github.com/Daydreamer-riri/vite-react-ssg/blob/main/examples/tanstack/src/main.tsx)\n\n[![NPM version](https://img.shields.io/npm/v/vite-react-ssg?color=a1b858\u0026label=)](https://www.npmjs.com/package/vite-react-ssg)\n\n## Table of contents\n\n- [Usage](#usage)\n- [Use CSR during development](#use-csr-during-development)\n- [Extra route options](#extra-route-options)\n  - [`entry`](#entry)\n  - [`getStaticPaths`](#getstaticpaths)\n- [Data fetch](#data-fetch)\n- [lazy](#lazy)\n- [`\u003cClientOnly/\u003e`](#clientonly)\n- [Document head](#document-head)\n  - [Reactive head](#reactive-head)\n- [Redirect](#redirect)\n- [Public Base Path](#public-base-path)\n- [Future config](#future-config)\n- [CSS in JS](#css-in-js)\n- [Critical CSS](#critical-css)\n- [Configuration](#configuration)\n  - [Custom Routes to Render](#custom-routes-to-render)\n- [Roadmap](#roadmap)\n- [Credits](#credits)\n\n## Usage\n\n\u003cpre\u003e\n\u003cb\u003enpm i -D vite-react-ssg\u003c/b\u003e \u003cem\u003ereact-router-dom\u003c/em\u003e\n\u003c/pre\u003e\n\n```diff\n// package.json\n{\n  \"scripts\": {\n-   \"build\": \"vite build\"\n+   \"build\": \"vite-react-ssg build\"\n    // If you need ssr when dev\n-   \"dev\": \"vite\",\n+   \"dev\": \"vite-react-ssg dev\",\n\n    // OR if you want to use another vite config file\n+   \"build\": \"vite-react-ssg build -c another-vite.config.ts\"\n  }\n}\n```\n\n```ts\n// src/main.ts\nimport { ViteReactSSG } from 'vite-react-ssg'\nimport routes from './App.tsx'\n\nexport const createRoot = ViteReactSSG(\n  // react-router-dom data routes\n  { routes },\n  // function to have custom setups\n  ({ router, routes, isClient, initialState }) =\u003e {\n    // do something.\n  },\n)\n```\n\n```tsx\n// src/App.tsx\nimport type { RouteRecord } from 'vite-react-ssg'\nimport React from 'react'\nimport Layout from './Layout'\nimport './App.css'\n\nexport const routes: RouteRecord[] = [\n  {\n    path: '/',\n    element: \u003cLayout /\u003e,\n    entry: 'src/Layout.tsx',\n    children: [\n      {\n        path: 'a',\n        lazy: () =\u003e import('./pages/a'),\n      },\n      {\n        index: true,\n        Component: React.lazy(() =\u003e import('./pages/index')),\n      },\n      {\n        path: 'nest/:b',\n        lazy: () =\u003e {\n          const Component = await import('./pages/nest/[b]')\n          return { Component }\n        },\n        // To determine which paths will be pre-rendered\n        getStaticPaths: () =\u003e ['nest/b1', 'nest/b2'],\n      },\n    ],\n  },\n]\n```\n\n### Use CSR during development\n\nVite React SSG provide SSR (Server-Side Rendering) during development to ensure consistency\nbetween development and production as much as possible.\n\nBut if you want to use CSR during development, just:\n\n```diff\n// package.json\n{\n  \"scripts\": {\n-   \"dev\": \"vite-react-ssg dev\",\n+   \"dev\": \"vite\",\n    \"build\": \"vite-react-ssg build\"\n  }\n}\n```\n\n### Single Page SSG\n\nFor SSG of an index page only (i.e. without `react-router-dom`);\nimport `vite-react-ssg/single-page` instead.\n\n```tsx\n// src/main.tsx\nimport { ViteReactSSG } from 'vite-react-ssg/single-page'\nimport App from './App.tsx'\n\nexport const createRoot = ViteReactSSG(\u003cApp /\u003e)\n```\n\n## Extra route options\n\nThe RouteObject of vite-react-ssg is based on react-router, and vite-react-ssg receives some additional properties.\n\n#### `getStaticPaths`\n\nThe `getStaticPaths()` function should return an array of path\nto determine which paths will be pre-rendered by vite-react-ssg.\n\nThis function is only valid for dynamic route.\n\n```tsx\nconst route = {\n  path: 'nest/:b',\n  lazy: () =\u003e import('./pages/nest/[b]'),\n  entry: 'src/pages/nest/[b].tsx',\n  // To determine which paths will be pre-rendered\n  getStaticPaths: () =\u003e ['nest/b1', 'nest/b2'],\n}\n```\n\n#### `entry`\n\n**You are not required to use this field. It is only necessary when \"prehydration style loss\" occurs.**\nIt should be the path from root to the target file.\n\neg: `src/pages/page1.tsx`\n\n## lazy\n\nThese options work well with the `lazy` field.\n\n```tsx\n// src/pages/[page].tsx\nexport function Component() {\n  return (\n    \u003cdiv\u003e{/* your component */}\u003c/div\u003e\n  )\n}\n\nexport function getStaticPaths() {\n  return ['page1', 'page2']\n}\n```\n\n```ts\n// src/routes.ts\nconst routes = [\n  {\n    path: '/:page',\n    lazy: () =\u003e import('./pages/[page]'),\n  }\n]\n```\n\n**Note that** during the build process, `vite-react-ssg` will [automatically detect](https://github.com/Daydreamer-riri/vite-react-ssg/blob/main/src/node/assets.ts#L5) the files directly dynamically imported in the function you pass to the `lazy` field. This helps `vite-react-ssg` to get the route's style files or other static resources during the build, preventing [flash of unstyled content](https://en.wikipedia.org/wiki/Flash_of_unstyled_content).\n\nIf you still encounter FOUC (flash of unstyled content), please open an issue.\n\nIf your component isn't loading, make sure you have wrapped it or its parent in `Suspense` tags as described in the [React documentation](https://react.dev/reference/react/lazy#usage).\n\nSee [example](./examples/lazy-pages/src/App.tsx).\n\n## Data fetch\n\nYou can use react-router-dom's `loader` to fetch data at build time and use `useLoaderData` to get the data in the component.\n\nIn production, the `loader` will only be executed at build time, and the data will be fetched by the manifest generated at build time during the browser navigations .\n\nIn the development environment, the `loader` also runs only on the server.It provides data to the HTML during initial server rendering, and during browser route navigations , it makes calls to the server by initiating a fetch on the service.\n\n```tsx\nimport { useLoaderData } from 'react-router-dom'\n\nexport default function Docs() {\n  const data = useLoaderData() as Awaited\u003cReturnType\u003ctypeof loader\u003e\u003e\n\n  return (\n    \u003c\u003e\n      \u003cdiv\u003e{data.key}\u003c/div\u003e\n      {/* eslint-disable-next-line react-dom/no-dangerously-set-innerhtml */}\n      \u003cdiv dangerouslySetInnerHTML={{ __html: data.packageCodeHtml }} style={{ textAlign: 'start' }}\u003e\u003c/div\u003e\n    \u003c/\u003e\n  )\n}\n\nexport const Component = Docs\n\nexport const entry = 'src/pages/json.tsx'\n\nexport async function loader() {\n  // The code here will not be executed on the client side, and the modules imported will not be sent to the client.\n  const fs = (await import('node:fs'))\n  const cwd = process.cwd()\n  const json = (await import('../docs/test.json')).default\n\n  const packageJson = await fs.promises.readFile(`${cwd}/package.json`, 'utf-8')\n  const { codeToHtml } = await import('shiki')\n  const packageJsonHtml = await codeToHtml(packageJson, { lang: 'json', theme: 'vitesse-light' })\n\n  return {\n    ...json,\n    packageCodeHtml: packageJsonHtml,\n  }\n}\n```\n\nSee [example | with-loader](./examples/with-loader/src/pages/[docs].tsx).\n\n## `\u003cClientOnly/\u003e`\n\nIf you need to render some component in browser only, you can wrap your component with `\u003cClientOnly\u003e`.\n\n```tsx\nimport { ClientOnly } from 'vite-react-ssg'\n\nfunction MyComponent() {\n  return (\n    \u003cClientOnly\u003e\n      {() =\u003e {\n        return \u003cdiv\u003e{window.location.href}\u003c/div\u003e\n      }}\n    \u003c/ClientOnly\u003e\n  )\n}\n```\n\n\u003e It's important that the children of `\u003cClientOnly\u003e` is not a JSX element, but a function that returns an element.\n\u003e Because React will try to render children, and may use the client's API on the server.\n\n## Document head\n\nYou can use `\u003cHead/\u003e` to manage all of your changes to the document head. It takes plain HTML tags and outputs plain HTML tags. It is a wrapper around [React Helmet](https://github.com/nfl/react-helmet).\n\n```tsx\nimport { Head } from 'vite-react-ssg'\n\nfunction MyHead() {\n  return (\n    \u003cHead\u003e\n      \u003cmeta property=\"og:description\" content=\"My custom description\" /\u003e\n      \u003cmeta charSet=\"utf-8\" /\u003e\n      \u003ctitle\u003eMy Title\u003c/title\u003e\n      \u003clink rel=\"canonical\" href=\"http://mysite.com/example\" /\u003e\n    \u003c/Head\u003e\n  )\n}\n```\n\nNested or latter components will override duplicate usages:\n\n```tsx\nimport { Head } from 'vite-react-ssg'\n\nfunction MyHead() {\n  return (\n    \u003cparent\u003e\n      \u003cHead\u003e\n        \u003ctitle\u003eMy Title\u003c/title\u003e\n        \u003cmeta name=\"description\" content=\"Helmet application\" /\u003e\n      \u003c/Head\u003e\n      \u003cchild\u003e\n        \u003cHead\u003e\n          \u003ctitle\u003eNested Title\u003c/title\u003e\n          \u003cmeta name=\"description\" content=\"Nested component\" /\u003e\n        \u003c/Head\u003e\n      \u003c/child\u003e\n    \u003c/parent\u003e\n  )\n}\n```\n\nOutputs:\n\n```html\n\u003chead\u003e\n  \u003ctitle\u003eNested Title\u003c/title\u003e\n  \u003cmeta name=\"description\" content=\"Nested component\" /\u003e\n\u003c/head\u003e\n```\n\n### Reactive head\n\n```tsx\nimport { useState } from 'react'\nimport { Head } from 'vite-react-ssg'\n\nexport default function MyHead() {\n  const [state, setState] = useState(false)\n\n  return (\n    \u003cHead\u003e\n      \u003cmeta charSet=\"UTF-8\" /\u003e\n      \u003clink rel=\"icon\" type=\"image/svg+xml\" href=\"/vite.svg\" /\u003e\n      \u003ctitle\u003ehead test {state ? 'A' : 'B'}\u003c/title\u003e\n      {/* You can also set the 'body' attributes here */}\n      \u003cbody className={`body-class-in-head-${state ? 'a' : 'b'}`} /\u003e\n    \u003c/Head\u003e\n  )\n}\n```\n\n## Redirect\n\nYou should not use redirect in the loader.\nIn vite-react-ssg, the loader only executes during the build process for data fetching.\nIf you need to perform a redirect in certain situations, you can use the following method to redirect on the client side:\n\n```tsx\nexport const routes: RouteRecord[] = [\n  {\n    path: '/:lng',\n    Component: Layout,\n    getStaticPaths: () =\u003e Object.keys(resources),\n    children: [\n      // ... some routes\n    ],\n  },\n  {\n    path: '/',\n    Component: () =\u003e {\n      const navigate = useNavigate()\n      useEffect(() =\u003e {\n        navigate('/en', { replace: true })\n      }, [navigate])\n\n      return null\n    },\n  },\n]\n```\n\n## Public Base Path\n\nJust set `base` in vite.config.ts like:\n\n```ts\nimport react from '@vitejs/plugin-react-swc'\n// vite.config.ts\nimport { defineConfig } from 'vite'\n\n// https://vitejs.dev/config/\nexport default defineConfig({\n  plugins: [react()],\n  base: '/base-path',\n})\n```\n\n```ts\n// main.ts\nimport { ViteReactSSG } from 'vite-react-ssg'\nimport { routes } from './App'\nimport './index.css'\n\nexport const createRoot = ViteReactSSG(\n  {\n    routes,\n    // pass your BASE_URL\n    basename: import.meta.env.BASE_URL,\n  },\n)\n```\n\nVite React SSG will give it to the react-router's `basename`.\n\nSee: [react-router's create-browser-router](https://reactrouter.com/en/main/routers/create-browser-router#basename)\n\n[Example](./examples/lazy-pages/vite.config.ts)\n\n## Future config\n\n```tsx\nexport const createRoot = ViteReactSSG(\n  {\n    routes,\n    basename: import.meta.env.BASE_URL,\n    future: {\n      v7_normalizeFormMethod: true,\n      v7_startTransition: true,\n      v7_fetcherPersist: true,\n      v7_relativeSplatPath: true,\n      v7_skipActionErrorRevalidation: true,\n      v7_partialHydration: true,\n    },\n  },\n)\n```\n\nSee: [react-router's optsfuture](https://reactrouter.com/6.28.0/routers/create-browser-router#optsfuture)\n\n[Example](./examples/lazy-pages/src/main.tsx)\n\n## CSS in JS\n\nUse the `getStyleCollector` option to specify an SSR/SSG style collector. Currently only supports `styled-components`.\n\n```tsx\nimport { ViteReactSSG } from 'vite-react-ssg'\nimport getStyledComponentsCollector from 'vite-react-ssg/style-collectors/styled-components'\nimport { routes } from './App.js'\nimport './index.css'\n\nexport const createRoot = ViteReactSSG(\n  { routes },\n  () =\u003e { },\n  { getStyleCollector: getStyledComponentsCollector }\n)\n```\n\nYou can provide your own by looking at the [implementation](./src/style-collectors/) of any of the existing collectors.\n\n## Critical CSS\n\nVite React SSG has built-in support for generating [Critical CSS](https://web.dev/extract-critical-css/) inlined in the HTML via the [`beasties`](https://github.com/danielroe/beasties) package.\nInstall it with:\n\n```bash\nnpm i -D beasties\n```\n\nCritical CSS generation will automatically be enabled for you.\n\nTo configure `beasties`, pass [its options](https://github.com/danielroe/beasties#usage)\ninto `ssgOptions.beastiesOptions` in `vite.config.ts`:\n\n```ts\n// vite.config.ts\nexport default defineConfig({\n  ssgOptions: {\n    beastiesOptions: {\n      // E.g., change the preload strategy\n      preload: 'media',\n      // Other options: https://github.com/danielroe/beasties#usage\n    },\n  },\n})\n```\n\n## Configuration\n\nYou can pass options to Vite SSG in the `ssgOptions` field of your `vite.config.js`\n\n```js\n// vite.config.js\n\nexport default {\n  plugins: [],\n  ssgOptions: {\n    script: 'async',\n  },\n}\n```\n\n```ts\ninterface ViteReactSSGOptions {\n  /**\n   * Set the scripts' loading mode. Only works for `type=\"module\"`.\n   *\n   * @default 'sync'\n   */\n  script?: 'sync' | 'async' | 'defer' | 'async defer'\n  /**\n   * Build format.\n   *\n   * @default 'esm'\n   */\n  format?: 'esm' | 'cjs'\n  /**\n   * The path of the main entry file (relative to the project root).\n   *\n   * @default 'src/main.ts'\n   */\n  entry?: string\n  /**\n   * The path of the index.html file (relative to the project root).\n   * @default 'index.html'\n   */\n  htmlEntry?: string\n  /**\n   * Mock browser global variables (window, document, etc...) from SSG.\n   *\n   * @default false\n   */\n  mock?: boolean\n  /**\n   * Apply formatter to the generated index file.\n   *\n   * **It will cause Hydration Failed.**\n   *\n   * @default 'none'\n   */\n  formatting?: 'prettify' | 'none'\n  /**\n   * Vite environment mode.\n   */\n  mode?: string\n  /**\n   * Directory style of the output directory.\n   *\n   * flat: `/foo` -\u003e `/foo.html`\n   * nested: `/foo` -\u003e `/foo/index.html`\n   *\n   * @default 'flat'\n   */\n  dirStyle?: 'flat' | 'nested'\n  /**\n   * Generate for all routes, including dynamic routes.\n   * If enabled, you will need to configure your serve\n   * manually to handle dynamic routes properly.\n   *\n   * @default false\n   */\n  includeAllRoutes?: boolean\n  /**\n   * Options for the beasties packages.\n   *\n   * @see https://github.com/danielroe/beasties#usage\n   */\n  beastiesOptions?: BeastiesOptions | false\n  /**\n   * Custom function to modify the routes to do the SSG.\n   *\n   * Works only when `includeAllRoutes` is set to false.\n   *\n   * Defaults to a handler that filters out all the dynamic routes.\n   * When passing your custom handler, you should also take care of the dynamic routes yourself.\n   */\n  includedRoutes?: (paths: string[], routes: Readonly\u003cRouteRecord[]\u003e) =\u003e Promise\u003cstring[]\u003e | string[]\n  /**\n   * Callback to be called before every page render.\n   *\n   * It can be used to transform the project's `index.html` file before passing it to the renderer.\n   *\n   * To do so, you can change the 'index.html' file contents (passed in through the `indexHTML` parameter), and return it.\n   * The returned value will then be passed to renderer.\n   */\n  onBeforePageRender?: (route: string, indexHTML: string, appCtx: ViteReactSSGContext\u003ctrue\u003e) =\u003e Promise\u003cstring | null | undefined\u003e | string | null | undefined\n  /**\n   * Callback to be called on every rendered page.\n   *\n   * It can be used to transform the current route's rendered HTML.\n   *\n   * To do so, you can transform the route's rendered HTML (passed in through the `renderedHTML` parameter), and return it.\n   * The returned value will be used as the HTML of the route.\n   */\n  onPageRendered?: (route: string, renderedHTML: string, appCtx: ViteReactSSGContext\u003ctrue\u003e) =\u003e Promise\u003cstring | null | undefined\u003e | string | null | undefined\n\n  onFinished?: () =\u003e Promise\u003cvoid\u003e | void\n  /**\n   * The application's root container `id`.\n   *\n   * @default `root`\n   */\n  rootContainerId?: string\n  /**\n   * The size of the SSG processing queue.\n   *\n   * @default 20\n   */\n  concurrency?: number\n}\n```\n\nSee [src/types.ts](./src/types.ts). for more options available.\n\n### Custom Routes to Render\n\nYou can use the `includedRoutes` hook to include or exclude route paths to render, or even provide some completely custom ones.\n\n```js\n// vite.config.js\n\nexport default {\n  plugins: [],\n  ssgOptions: {\n    includedRoutes(paths, routes) {\n      // exclude all the route paths that contains 'foo'\n      return paths.filter(i =\u003e !i.includes('foo'))\n    },\n  },\n}\n```\n\n```js\n// vite.config.js\n\nexport default {\n  plugins: [],\n  ssgOptions: {\n    includedRoutes(paths, routes) {\n      // use original route records\n      return routes.flatMap(route =\u003e {\n        return route.name === 'Blog'\n          ? myBlogSlugs.map(slug =\u003e `/blog/${slug}`)\n          : route.path\n      })\n    },\n  },\n}\n```\n\n```ts\nexport default defineConfig({\n  server: {\n    https: true,\n  },\n})\n```\n\n### React17 Support\n\n- for react18, with flag `useLegacyRender: true`, it will use the legacy `render` and `hydrate` methods.\n- for react17, on top of above, you will need minor update to react and react-dom [example](https://github.com/jesse23/webpack-test-bed/blob/main/scripts/define-react-exports.js) to polyfill the mjs import and the `react-dom/client`.\n\n## Roadmap\n\n- [ ] Support `react19`\n- [ ] no index.html mode\n\n## Credits\n\nThis project inspired by [vite-ssg](https://github.com/antfu/vite-ssg), thanks to [@antfu](https://github.com/antfu) for his awesome work.\n\n## License\n\n[MIT](./LICENSE) License © 2023 [Riri](https://github.com/Daydreamer-riri)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDaydreamer-riri%2Fvite-react-ssg","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FDaydreamer-riri%2Fvite-react-ssg","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDaydreamer-riri%2Fvite-react-ssg/lists"}