{"id":19417206,"url":"https://github.com/effector/next","last_synced_at":"2025-04-24T13:33:23.338Z","repository":{"id":150063710,"uuid":"622295170","full_name":"effector/next","owner":"effector","description":"Minimal compatibility layer for effector + Next.js","archived":false,"fork":false,"pushed_at":"2025-03-26T17:05:12.000Z","size":523,"stargazers_count":56,"open_issues_count":4,"forks_count":7,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-04-11T18:06:55.595Z","etag":null,"topics":["effector","effector-react","next"],"latest_commit_sha":null,"homepage":"https://npmjs.com/@effector/next","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/effector.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,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2023-04-01T17:29:02.000Z","updated_at":"2025-04-08T10:02:32.000Z","dependencies_parsed_at":"2023-04-15T20:17:54.986Z","dependency_job_id":"c1e9fe41-02c3-48d0-9401-9fae17ffb933","html_url":"https://github.com/effector/next","commit_stats":{"total_commits":142,"total_committers":6,"mean_commits":"23.666666666666668","dds":0.4154929577464789,"last_synced_commit":"f3751ecb9d61e74966cb2641d3e49714937e1d43"},"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/effector%2Fnext","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/effector%2Fnext/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/effector%2Fnext/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/effector%2Fnext/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/effector","download_url":"https://codeload.github.com/effector/next/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249974922,"owners_count":21354422,"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":["effector","effector-react","next"],"created_at":"2024-11-10T13:08:06.781Z","updated_at":"2025-04-24T13:33:23.287Z","avatar_url":"https://github.com/effector.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Bindings for Next.js\n\nThis is minimal compatibility layer for effector + Next.js - it only provides one special `EffectorNext` provider component, which allows to fully leverage effector's Fork API, while handling some _special_ parts of Next.js SSR and SSG flow.\n\n## Installation\n\n```bash\nnpm add effector effector-react @effector/next\n```\n\nAlso, you can use Yarn or **PNPM** to install dependencies.\n\n## Usage\n\nYou can find example app at the [`apps/playground-app`](/apps/playground-app) - it contains both App Router and Pages Router usage examples in various cases.\n\n### SIDs\n\nTo serialize and transfer state of effector stores between the network boundaries all stores must have a Stable IDentifier - sid.\n\nSid's are added automatically via either built-in babel plugin or our experimental SWC plugin.\n\n#### Babel-plugin\n\nEffector comes with built-in official Babel plugin, which you can use for SIDs:\n\n```json\n{\n  \"presets\": [\"next/babel\"],\n  \"plugins\": [\"effector/babel-plugin\"]\n}\n```\n\nNotice, that **you don't need** the `reactSsr` option of the plugin, when using `@effector/next`. The `reactSsr` is a legacy API which is deprecated in the latest release of Effector.\n\n[Read the docs](https://effector.dev/docs/api/effector/babel-plugin/#usage)\n\n#### SWC Plugin\n\nThere is a awesome SWC port of the plugin, check it out:\n\n[Read effector SWC plugin documentation](https://github.com/kireevmp/effector-swc-plugin)\n\n### Effector ESlint Plugin\n\nIt is recommened to install the official [Effector ESlint Plugin](https://eslint.effector.dev/) with React Preset, it will help you follow best practices and avoid common mistakes, like always using `useUnit`\n\n#### Installation\n\nSee the [installation guide here](https://github.com/effector/eslint-plugin?tab=readme-ov-file#installation).\n\n#### Setup\n\n**.eslintrc**\n\n```json\n{\n  \"plugins\": [\"effector\"],\n  \"extends\": [\"plugin:effector/react\"]\n}\n```\n\n#### Don't forget `useUnit` for all `effector` units\n\nIn SSR applications all of effector's units need to be \"binded\" to the current `Scope`, which means that you should always use `useUnit` in components:\n\n```tsx\nimport { useUnit } from \"effector-react\"\nimport { eventTriggered, effectFx, $store } from \"./model\"\n\nexport function Component() {\n const {\n  value,\n  trigger,\n  callEffect\n } = useUnit({\n   value: $store,\n   trigger: eventTriggered,\n   callEffect: effectFx\n })\n\n // rest of the components code\n}\n```\nYou can find full docs about `useUnit` [here](https://effector.dev/docs/api/effector-react/useUnit).\n\nThe official [Effector ESlint Plugin](https://eslint.effector.dev/) with React Preset will help you to follow this rule.\n\n### [Pages Router](https://nextjs.org/docs/pages/building-your-application/routing) usage\n\nBefore Next.js `13.4.0` Pages router was the main way to build Next.js applications. \nThe Pages Router [will be supported for multiple Next.js major updates](https://nextjs.org/blog/next-13-4#is-the-pages-router-going-away).\n\nThe `@effector/next` fully supports Pages Router out of the box.\n\n#### 1. EffectorNext provider setup\n\nAdd provider to the `pages/_app.tsx` and provide it with server-side `values`\n\n```tsx\nimport { EffectorNext } from \"@effector/next\";\n\nexport default function App({ Component, pageProps }: AppProps) {\n  return (\n    \u003cmain\u003e\n      \u003cEffectorNext values={pageProps.values}\u003e\n        \u003cLayout\u003e\n          \u003cComponent /\u003e\n        \u003c/Layout\u003e\n      \u003c/EffectorNext\u003e\n    \u003c/main\u003e\n  );\n}\n```\n\nNotice, that `EffectorNext` should get serialized scope values via props.\n\n#### 2. Server-side computations\n\nStart your computations in server handlers using Fork API. Workflow is the same for all server-side functions of Next.js.\n\n**`getStaticProps` example**\n\n```ts\nimport { fork, allSettled, serialize } from \"effector\";\n\nimport { pageStarted } from \"../src/my-page-model\";\n\nexport async function getStaticProps() {\n  const scope = fork();\n\n  await allSettled(pageStarted, { scope, params });\n\n  return {\n    props: {\n      // notice serialized effector's scope here!\n      values: serialize(scope),\n    },\n  };\n}\n```\n\nNotice, that serialized scope values are provided via the same `values` prop, which is used in the `_app.tsx` for providing values to `EffectorNext`.\nIt is up to you to pick some prop name to connect server handlers with client prop in `_app.tsx`.\n\n#### 3. Next.js Pages Router API Usage\n\nThere is a bunch of special APIs, which work in the Pages Router mode.\n\n[See the relevant Next.js docs for API details](https://nextjs.org/docs/pages/api-reference)\n\n**`getServerSideProps` with `{ notFound: true }`**\n\nYou can return a special object of `{ notFound: true }` shape to command Next.js render the [common 404 page](https://nextjs.org/docs/pages/building-your-application/routing/custom-error#404-page)\n\n```tsx\nimport { fork, allSettled, serialize } from \"effector\";\n\nimport { pageStarted, $isNotFound } from \"../src/my-page-model\";\n\nexport async function getStaticProps() {\n  const scope = fork();\n\n  await allSettled(pageStarted, { scope, params });\n\n  if (scope.getState($isNotFound)) {\n    // If, after all computations there is still something missing,\n    // and user is meant to see the 404\n\n    return {\n      notFound: true,\n    }\n  }\n\n  return {\n    props: {\n      // notice serialized effector's scope here!\n      values: serialize(scope),\n    },\n  };\n}\n```\n☝️ This `scope.getState` pattern works the same way for any other Next.js Pages Router server-side APIs, as well as for App Router APIs (see below)\n\nYou're all set. Just use effector's units anywhere in components code via `useUnit` from `effector-react`.\n\nAlso see the [`nextjs-effector`](https://github.com/risen228/nextjs-effector) package (_yeah, naming of the Next.js-related packages is kind of compicated_), which provides better DX to Pages Router usage and is built on top of the `@effector/next`.\n\n## [App Router](https://nextjs.org/docs/app/building-your-application/routing) usage\n\nThe App Router is a new paradigm for building Next.js applications using React's latest features, which declared stable since Next.js `13.4.0`.\n\nThe `@effector/next` fully supports App Router out of the box.\n\n#### 1. Setup provider in the Root Layout\n\nTo use client components with effector units anywhere in the tree - add `EffectorNext` provider at your [Root Layout](https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts#root-layout-required)\n\nIf you are using [multiple Root Layouts](https://nextjs.org/docs/app/building-your-application/routing/route-groups#creating-multiple-root-layouts) - each one of them should also have the `EffectorNext` provider.\n\n```tsx\n// app/layout.tsx\nimport { EffectorNext } from \"@effector/next\";\n\nexport function RootLayout({ children }: { children: React.ReactNode }) {\n  return (\n    \u003chtml lang=\"en\"\u003e\n      \u003cbody\u003e\n        \u003cEffectorNext\u003e{/* rest of the components tree */}\u003c/EffectorNext\u003e\n      \u003c/body\u003e\n    \u003c/html\u003e\n  );\n}\n```\n\n☝️ This will allow any component anywhere in the tree to access any Effector store, regardless of whether that page performs any server-side computations or not\n\n#### 2. Server-side computations\n\nServer computations work in a similiar way to `pages` directory, but inside Server Components of the `app` pages.\n\nIn this case you will need to add the `EffectorNext` provider to the tree of this Server Component and provide it with serialized scope.\n\n```tsx\n// app/some-path/page.tsx\nimport { EffectorNext } from \"@effector/next\";\n\nexport default async function Page() {\n  const scope = fork();\n\n  await allSettled(pageStarted, { scope, params });\n\n  const values = serialize(scope);\n\n  return (\n    \u003cEffectorNext values={values}\u003e\n      {/* rest of the components tree */}\n    \u003c/EffectorNext\u003e\n  );\n}\n```\n\n☝️ This will automatically render [this subtree](https://github.com/effector/next/tree/main#app-router-architecture-edge-case) with calculated effector's state and also will automatically \"hydrate\" **client scope** with new values, once this update is rendered in the browser.\n\n#### 3. Next.js API's usage\n\nStart your computations via Fork API and use `scope.getState` to extract data from stores and provide it to the Next.js API's like [`generateStaticParams`](https://nextjs.org/docs/app/api-reference/functions/generate-static-params)\n\nIt should be noted, that `getState` usage is typically undesirable in production code - except for the cases when you need to connect effector with some external thing or api, which is exactly the case with Next.js here.\n\n##### `generateStaticParams` example\n\n[See relevant Next.js docs for API details](https://nextjs.org/docs/app/api-reference/functions/generate-static-params)\n\n```tsx\n// app/blog/[slug]/page.tsx\nimport { fork, allSettled, serialize } from \"effector\"\n\nimport { blogPostOpened, blogPostsStarted, $postsList } from \"@app/features/blog\"\n\n// Return a list of `params` to populate the [slug] dynamic segment\nexport async function generateStaticParams() {\n  const scope = fork();\n\n  await allSettled(blogPostsStarted, { scope });\n\n  const posts = scope.getState($postsList); // { name: string; id: string; }[]\n\n  // map to match `[slug]` param naming\n  return posts.map(({ id }) =\u003e ({ slug: id }));\n}\n\n// Multiple versions of this page will be statically generated\n// using the `params` returned by `generateStaticParams`\nexport default async function Page({ params }: { params: { slug: string } }) {\n  const { slug } = params;\n\n  const scope = fork();\n\n  await allSettled(blogPostOpened, { scope, params: { id: slug } });\n\n  const values = serialize(scope);\n\n  return (\n    \u003cEffectorNext values={values}\u003e\n      {/* rest of the components tree */}\n    \u003c/EffectorNext\u003e\n  );\n}\n```\n\n##### `notFound` and `redirect` example\n\nThere are few special functions, which, when called from inside of an server component, will throw a special exception, which will command Next.js to perform redirect somewhere.\nThe `notFound` function will redirect to `notFound.tsx` view for a current page.\n\n[See relevant Next.js docs for API details](https://nextjs.org/docs/app/api-reference/functions/not-found)\n\n```tsx\n// app/blog/[slug]/page.tsx\nimport { fork, allSettled, serialize } from \"effector\"\nimport { notFound } from \"next/navigation\"\n\nimport { blogPostOpened, $currentPost } from \"@app/features/blog\"\n\nexport default async function Page({ params }: { params: { slug: string } }) {\n  const { slug } = params;\n\n  const scope = fork();\n\n  await allSettled(blogPostOpened, { scope, params: { id: slug } });\n\n  if (!scope.getState($currentPost)) {\n    // If there is no current post available after all computations\n    // Next.js redirect to `notFound.tsx` is triggered\n    notFound()\n  }\n\n  const values = serialize(scope);\n\n  return (\n    \u003cEffectorNext values={values}\u003e\n      {/* rest of the components tree */}\n    \u003c/EffectorNext\u003e\n  );\n}\n```\n☝️ It works the same for any other of Next.js special functions: if you need to access the store value outside of client components, you will need to use `scope.getState`.\n\n##### `Server Actions` example\n\n1. Server actions must be created [as usual](https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations).\n\n```typescript\n// src/feature/action.ts\n\"use server\"\n\nexport const myAction = async () =\u003e doServerOnlyStuff()\n```\n\n2. Then server action can be used in Effector models as an [effect handler](https://effector.dev/en/api/effector/createeffect/)\n\n```typescript\n// src/feature/model.ts\nimport { createEffect } from \"effector\"\nimport { myAction } from \"./action.ts\"\n\nconst myActionFx = createEffect(myAction)\n```\n☝️ This effect can be called anywhere\n\nThat's it.\n\nSee [`apps/playground-app/src/features/server-action`](https://github.com/effector/next/tree/main/apps/playground-app/src/features/server-action) for live example.\n\n#### Don't forget about `use client` for client components:\n\nJust [write effector's models as usual](https://effector.dev/) and use effector's units anywhere in components code [via `useUnit` from `effector-react`](https://effector.dev/docs/api/effector-react/useUnit) - but don't forget, that to use hooks you need the `\"use client\"` directive.\n\n```tsx\n// src/features/blog/post.view.tsx\n// you should use `use client`, if your component uses any hooks\n\"use client\"\nimport { useUnit } from \"effector-react\"\nimport { Title, Content } from \"@app/shared/ui-kit\"\nimport { PostCommentsView } from \"@app/features/comments\"\n\nimport { $currentPost } from \"./model.ts\"\n\nexport function CurrentBlogPost() {\n  const post = useUnit($currentPost)\n\n  return (\n    \u003carticle\u003e\n      \u003cTitle{post.title}\u003c/Title\u003e\n      \u003cContent\u003e\n        {post.content}\n      \u003c/Content\u003e\n      \u003cPostCommentsView postId={post.id} /\u003e\n    \u003c/article\u003e\n  )\n}\n```\n\n### Dev-Tools integration\n\nMost of `effector` dev-tools options require direct access to the `scope` of the app.\nAt the client you can get current scope via `getClientScope` function, which will return `Scope` in the browser and `null` at the server.\n\nHere are few examples of `@effector/redux-devtools-adapter` integration.\n\n#### Pages Router Dev-Tools example\n\nIn case of Pages Router dev-tools setup must be placed at the [custom App component file (pages/\\_app.tsx)](https://nextjs.org/docs/pages/building-your-application/routing/custom-app).\n\n```tsx\n// pages/_app.tsx\nimport type { AppProps } from \"next/app\";\nimport { EffectorNext, getClientScope } from \"@effector/next\";\nimport { attachReduxDevTools } from \"@effector/redux-devtools-adapter\";\n\nconst clientScope = getClientScope();\n\nif (clientScope) {\n  /**\n   * Notice, that we need to check for the client scope first\n   *\n   * It will be `null` at the server\n   */\n  attachReduxDevTools({\n    scope: clientScope,\n    name: \"playground-app\",\n    trace: true,\n  });\n}\n\nfunction App({\n  Component,\n  pageProps,\n}: AppProps\u003c{ values: Record\u003cstring, unknown\u003e }\u003e) {\n  const { values } = pageProps;\n\n  return (\n    \u003cEffectorNext values={values}\u003e\n      \u003cComponent /\u003e\n    \u003c/EffectorNext\u003e\n  );\n}\n\nexport default App;\n```\n\n#### App Router Dev-Tools example\n\nIn case of the App Router dev-tools setup must be placed at the [the Root Layout](https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts#root-layout-required) - this way dev-tools integration will work for all pages of the app.\n\n##### Create client component\n\nSince Redux Dev-Tools are client thing - we need to prepare it as a client component.\n\n```tsx\n// src/shared/redux-dev-tools-provider.tsx\n\"use client\";\n\nimport { getClientScope } from \"@effector/next\";\nimport { attachReduxDevTools } from \"@effector/redux-devtools-adapter\";\n\nconst clientScope = getClientScope();\n\nif (clientScope) {\n  /**\n   * Notice, that we need to check for the client scope first\n   *\n   * It will be `null` at the server\n   */\n  attachReduxDevTools({\n    scope: clientScope,\n    name: \"playground-app-app-router\",\n    trace: true,\n  });\n}\n\nexport function ReduxDevToolsAdapter({\n  children,\n}: {\n  children?: React.ReactNode;\n}) {\n  return \u003c\u003e{children}\u003c/\u003e;\n}\n```\n\n##### Add this component to the Root Layout\n\n```tsx\n// app/layout.tsx\nimport { EffectorNext } from \"@effector/next\";\n\nimport { ReduxDevToolsAdapter } from \"app-root/shared/redux-dev-tools-provider\"\n\nexport function RootLayout({ children }: { children: React.ReactNode }) {\n  return (\n    \u003chtml lang=\"en\"\u003e\n      \u003cbody\u003e\n        \u003cReduxDevToolsAdapter /\u003e\n        \u003cEffectorNext\u003e{children}\u003c/EffectorNext\u003e\n      \u003c/body\u003e\n    \u003c/html\u003e\n  );\n}\n```\n\n## Important caveats\n\nThere are a few special nuances of Next.js behaviour, that you need to consider.\n\n### Using Pages Router along with App Router\n\nBe aware that Next.js basically builds two different app bundles for Pages and App Router modes.\n\nTransitions between pages of `Pages Router` and `App Router` are always performed via full page reload blowing away any client state.\nThis is enough for gradual `App Router` adoption, but if you want the best experience, you should avoid mixing different Router modes in the same application. Pages that users frequently transition between should ideally move to `App Router` together.\n\nNew apps should always be started with App Router, as it is the main way to build Next.js applications now.\n\n### App Router architecture edge-case\n\nThere is a known caveat with App Router architecture, which, so far, applies to `effector` and `@effector/next` too:\n\n**Layout Components, Page Components and any nested React Server Components cannot be aware of each other during server rendering.**\n\n☝️ It means that if there is a some effector's store, that is used in the Layout Component and later is updated during rendering of Page Component - at the client browser there might be a layout flicker visible at the Layout Component.\n\nIt happens, because at the server, by the moment of Page Component rendering, its Layout **had already rendered** its part of the response, including all components in it, which will use the stores state at the moment of their rendering. So, if such store is later changed in Page Component - Layout Compoment at the client will \"see\" and react to this change only after hydration at the client.\n\nYou can reproduce that behavior in the example [`playground-app`](/apps/playground-app), by changing the `$counter` store, which controls the state of the counter button in the navbar which is rendered at the common `layout.tsx`, in some of `page.tsx` components.\n\nThe navbar counter button will first be visible with count `0` (as it is a state of the `$counter` at the moment of layout render) and then it will change to whatever value was set during `page.tsx` render.\n\n### Non-serializable values\n\nIf you have Effector stores that contain values that cannot be safely passed to `JSON.stringify`, you will have problems passing the values to the client.\n\nIn that case, you have to specify a custom serialization rule through the store settings.\n\n#### Example\n\n`Date` object will be serialized to ISO-string by default, but will not be parsed back to `Date` object via `JSON.parse`.\nWe can fix it by providing custom serialization rule.\n\n```ts\nconst $date = createStore\u003cnull | Date\u003e(null, {\n  serialize: {\n    write: (dateOrNull) =\u003e (dateOrNull ? dateOrNull.toISOString() : dateOrNull),\n    read: (isoStringOrNull) =\u003e\n      isoStringOrNull ? new Date(isoStringOrNull) : isoStringOrNull,\n  },\n});\n```\n\n[Docs about custom serialize feature](https://effector.dev/docs/api/effector/createStore#example-with-custom-serialize-configuration)\n\n### Effector's `serialize: \"ignore\"` is not recommended\n\nNext.js network (and serialization) boundary is placed before any client components rendering, so any stores with `serialize: \"ignore\"` setting will always use default values for renders, which may lead to confusing results.\n\n#### Example\n\n```tsx\n// some-module.ts\nconst $serverOnlyValue = createStore(null, { serialize: \"ignore\" })\n\n// $someValue is a derived store - such stores are never included in effector's serialization,\n// because it is always possible to safely recalculate them from parent stores\n//\n// But in this case, combined with `serialize: \"ignore\"` on parent store, it will lead to confusing result\nexport const $someValue = $serverOnlyValue.map(value =\u003e value ? extractSomeSafeForClientData(value) : null)\n\n// some-component\n\nexport function Component() {\n const value = useUnit($someValue)\n\n return value ? \u003c\u003e{value}\u003c\u003e : \u003c\u003eNo value\u003c/\u003e\n}\n\n// pages/some-page\nexport async function getServerSideProps(req) {\n const scope = fork()\n\n  await allSettled(appStarted, { scope, params: req })\n\n  // `scope.getState($serverOnlyValue)` is not null at this point\n  // as well as `scope.getState($someValue)` is correctly calculated here\n\n  // Next.js network boundary happens here and is separated from rendering components at the server\n  return {\n   props: {\n    values: serialize(scope)\n    // `scope.getState($serverOnlyValue)` is stripped off here, it's value will be default one :(\n    // And `$someValue` is also calculated as if `$serverOnlyValue` is still null\n    //\n    // As a result - `Component` will always render \"No value\"\n   }\n  }\n}\n```\n\n#### Workaround\n\nYou can workaround it by using another non-derived store, which will be included in effector's serialization.\n\n```tsx\n// some-module.ts\nconst $serverOnlyValue = createStore(null, { serialize: \"ignore\" })\n\n// $someValue is non-derived and will be included in serialization, if changed\nexport const $someValue = createStore(null)\n\nsample({\n clock: $serverOnlyValue,\n fn: value =\u003e value ? extractSomeSafeForClientData(value) : null,\n target: $someValue,\n})\n\n// some-component\n\nexport function Component() {\n const value = useUnit($someValue)\n\n return value ? \u003c\u003e{value}\u003c\u003e : \u003c\u003eNo value\u003c/\u003e\n}\n\n// pages/some-page\nexport async function getServerSideProps(req) {\n const scope = fork()\n\n  await allSettled(appStarted, { scope, params: req })\n\n  // `scope.getState($serverOnlyValue)` is not null at this point\n  // as well as `scope.getState($someValue)` is correctly calculated here\n\n  // Next.js network boundary happens here and is separated from rendering components at the server\n  return {\n   props: {\n    values: serialize(scope)\n    // `scope.getState($serverOnlyValue)` is stripped off here, it's value will be default one :(\n    // But since `$someValue` is also non-derived store and it was changed on `$serverOnlyValue` update\n    // it will be included in `values`\n    //\n    // As a result - `Component` will render `value` properly\n   }\n  }\n}\n```\n\n### Do not use `$store.watch` calls for debugging\n\nThe `$store.watch` method works well for speeding up debugging in SPA-like environments, because in such cases effector applications usually run without `Scope`.\nHowever, this is not the case for Next.js, which runs as an SSR application - there are Scope instances on the server and client, and the actual state of the application is also stored in Scope.\nYou can find more details [in this article](https://beta.effector.dev/en/guides/server-side-rendering/).\n\nThe problem is that `$store.watch(cb)` call triggers `cb` immediately with current \"non-scope\" state of this store - it works this way due to historical reasons, as the watch API was created before Scopes and SSR support.\n\nYou can find detailed explainer in this article:\nhttps://withease.pages.dev/magazine/watch_calls\n\n### ESM dependencies and library duplicates in the bundle\n\nSince Next.js 12 [ESM imports are prioritized over CommonJS imports](https://nextjs.org/blog/next-12#es-modules-support-and-url-imports). While CJS-only dependencies are still supported, it is not recommended to use them.\n\nIt may lead to duplicated instances of the library in the bundle, which in case of `@effector/next` or `effector` leads to weird bugs like missing context provider errors.\n\nYou can check for library duplicates in the bundle either automatically with [statoscope.tech](https://statoscope.tech/) Webpack Plugin, [which have special rule for this purpose](https://github.com/statoscope/statoscope/blob/master/packages/stats-validator-plugin-webpack/docs/rules/no-packages-dups.md).\n\nYou can also check it manually via `Debug -\u003e Sources -\u003e Webpack -\u003e _N_E -\u003e node_modules` tab in the browser developer tools. Duplicated modules will be presented here in both `mjs` and `cjs` kinds.\n\n\u003cimg width=\"418\" alt=\"image\" src=\"https://user-images.githubusercontent.com/32790736/233786487-304cfac0-3686-460b-b2f9-9fb0de38a4dc.png\"\u003e\n\n## Release process\n\n1. Check out the [draft release](https://github.com/effector/next/releases).\n1. All PRs should have correct labels and useful titles. You can [review available labels here](https://github.com/effector/next/blob/main/.github/release-drafter.yml).\n1. Update labels for PRs and titles, next [manually run the release drafter action](https://github.com/effector/next/actions/workflows/release-drafter.yml) to regenerate the draft release.\n1. Review the new version and press \"Publish\"\n1. If required check \"Create discussion for this release\"\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feffector%2Fnext","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feffector%2Fnext","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feffector%2Fnext/lists"}