ReactNative: New init setup#34665
Conversation
…ator-orchestration
Wires the React Native generator end-to-end during `storybook init`:
- Calls the M1 metro-config codemod to wrap the project's
`metro.config.{js,ts,cjs}` with `withStorybook(...)`, falling back to a
guidance comment when the AST transform can't be applied safely.
- Calls the M2 entrypoint generator to write `.rnstorybook/index.{ts,js}`.
- Adds `generateScripts` to derive `storybook:ios` / `storybook:android`
npm scripts and request `cross-env` when needed.
- Updates `ProjectTypeService` to detect React Native projects via the
`expo` dependency in addition to `react-native` / `react-native-scripts`.
This is the orchestration layer that makes the React Native init flow
user-facing. It depends on the M1 codemod and M2 entrypoint generator —
this PR is stacked on top of those branches and should be merged after
them. Once M1 and M2 land on `next`, this PR's diff will reduce to the
M3-only files.
Files added (M3):
- `src/generators/REACT_NATIVE/generateScripts.{ts,test.ts}`
- `src/generators/REACT_NATIVE/index.test.ts`
Files modified (M3):
- `src/generators/REACT_NATIVE/index.ts` — orchestration
- `src/services/ProjectTypeService.{ts,test.ts}` — expo detection
Split out of #34333 (M3). Tracking issue: #34276.
Made-with: Cursor
There was a problem hiding this comment.
Pull request overview
Wires up a new end-to-end React Native setup path for storybook init in create-storybook, including Metro config codemodding, .rnstorybook entrypoint generation, and platform run-script derivation, plus improved RN project detection.
Changes:
- Add Metro config codemod to wrap
metro.config.*exports withwithStorybook(...), with fallback guidance comment on unsupported shapes. - Generate
.rnstorybook/index.(ts|js)entrypoint and derivestorybook:ios/storybook:androidscripts (optionally addingcross-env). - Expand RN project auto-detection to include
expodependency, with unit tests.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| code/lib/create-storybook/templates/react-native/index.js | Adds user-editable RN Storybook entrypoint template. |
| code/lib/create-storybook/src/services/ProjectTypeService.ts | Detects RN projects via expo dependency. |
| code/lib/create-storybook/src/services/ProjectTypeService.test.ts | Adds coverage for expo → RN detection. |
| code/lib/create-storybook/src/generators/REACT_NATIVE/metroConfig.ts | Implements Metro codemod + fallback comment behavior. |
| code/lib/create-storybook/src/generators/REACT_NATIVE/metroConfig.test.ts | Adds tests for Metro codemod/update/fallback flows. |
| code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts | Orchestrates scripts + entrypoint generation + Metro codemod; updates post-config messaging. |
| code/lib/create-storybook/src/generators/REACT_NATIVE/index.test.ts | Adds unit tests for RN generator orchestration and messaging. |
| code/lib/create-storybook/src/generators/REACT_NATIVE/generateScripts.ts | Derives storybook:ios/android scripts from base scripts. |
| code/lib/create-storybook/src/generators/REACT_NATIVE/generateScripts.test.ts | Adds unit tests for script derivation behavior. |
| code/lib/create-storybook/src/generators/REACT_NATIVE/generateEntrypoint.ts | Generates `.rnstorybook/index.(ts |
| code/lib/create-storybook/src/generators/REACT_NATIVE/generateEntrypoint.test.ts | Adds unit tests for entrypoint generation/overwrite behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughDerives platform-specific Storybook run scripts from existing React Native Storybook Setup Automation
sequenceDiagram
participant CLI as User/CLI
participant Generator as RN Generator
participant Pkg as package.json
participant Deriver as Script Derivation
participant PM as Package Manager
participant FS as File System
participant Metro as Metro Codemod
CLI->>Generator: configure()
Generator->>Pkg: read scripts (ios/android)
Pkg-->>Generator: base scripts
Generator->>Deriver: deriveStorybookPlatformScripts(scripts)
Deriver->>Deriver: trim & inject STORYBOOK_ENABLED / handle cross-env
Deriver-->>Generator: scriptsToAdd, missingBaseScripts
Generator->>PM: getDependencyVersion('cross-env')
alt cross-env needed and missing
Generator->>PM: add cross-env to versioned packages
end
Generator->>Pkg: addScripts(scriptsToAdd)
Generator->>FS: generateReactNativeEntrypoint()
Generator->>Metro: runMetroCodemodOrFallback({ packageManager, yes })
Metro->>FS: detect metro config candidates (attempt expo customize if needed)
Metro->>FS: read selected config
Metro->>Metro: parse AST, detect Storybook import
alt already configured
Metro-->>Generator: skipped-existing-storybook-import
else transformable
Metro->>FS: write wrapped config (withStorybook)
Metro-->>Generator: updated
else unsupported / error
Metro->>FS: prepend fallback comment
Metro-->>Generator: fallback-commented
end
Generator-->>CLI: postConfigure logs (scripts, metro status, warnings)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
code/lib/create-storybook/src/generators/REACT_NATIVE/metroConfig.ts (1)
34-38: 💤 Low valueMinor: consider consolidating pattern logic.
STORYBOOK_PACKAGE_PATTERNSis only used in the catch fallback (line 103), whilehasStorybookPackageduplicates the same check logic inline. This is fine for correctness but could be simplified by havinghasStorybookPackagereference the constant.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@code/lib/create-storybook/src/generators/REACT_NATIVE/metroConfig.ts` around lines 34 - 38, hasStorybookPackage duplicates the package-check logic already expressed in STORYBOOK_PACKAGE_PATTERNS; update hasStorybookPackage to reference the constant instead of reimplementing the checks (e.g., use STORYBOOK_PACKAGE_PATTERNS.some(...) or equivalent) so the pattern logic is centralized and the catch-fallback still uses the same source of truth (STORYBOOK_PACKAGE_PATTERNS) — modify the hasStorybookPackage function accordingly.code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts (1)
20-21: ⚖️ Poor tradeoffModule-level mutable state couples
configureandpostConfigureimplicitly.Using module-scoped
letvariables to share state between lifecycle methods is fragile. Ifconfigureisn't called beforepostConfigure, or if the module is reused across multiple invocations without reinitializing, the state could be stale or undefined. Consider passing this data through a returned context object or storing it in a way that's explicitly scoped to the generator instance.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts` around lines 20 - 21, The module-level mutable variables lastMetroCodemodResult and lastScriptDerivationResult create hidden coupling between configure and postConfigure; instead refactor so configure returns (or stores in an instance-scoped context) the results it computes and postConfigure accepts that context as an argument (or the generator returns an object containing configure and postConfigure bound to the same instance), remove the module-scoped lets, and update callers to pass the returned context to postConfigure so state is explicit and not shared across generator invocations.code/lib/create-storybook/src/generators/REACT_NATIVE/index.test.ts (1)
150-172: 💤 Low valueConsider moving mock customization to a nested
describeblock with its ownbeforeEach.The mock modification at line 155-157 happens inline within the test case. Per coding guidelines, mock implementations should be in
beforeEachblocks rather than inline within test cases. You could wrap this test in a nesteddescribewith its ownbeforeEachto configure the differentgetDependencyVersionbehavior.♻️ Suggested refactor
+ describe('when cross-env is already a dependency', () => { + beforeEach(() => { + // Override for this specific scenario + }); + + it('does not add cross-env', async () => { + const packageManager = createPackageManager({ + ios: 'react-native run-ios', + android: 'react-native run-android', + }); + packageManager.getDependencyVersion = vi.fn((dep: string) => + dep === 'cross-env' ? '^7.0.3' : null + ); + // ... rest of test + }); + });As per coding guidelines: "Avoid inline mock implementations within test cases in Vitest tests"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@code/lib/create-storybook/src/generators/REACT_NATIVE/index.test.ts` around lines 150 - 172, Move the inline mock override of packageManager.getDependencyVersion out of the it('does not add cross-env when it is already a dependency') body by creating a nested describe block for this scenario and adding a beforeEach that sets packageManager = createPackageManager(...) and then assigns packageManager.getDependencyVersion = vi.fn((dep: string) => dep === 'cross-env' ? '^7.0.3' : null); keep the test body only calling reactNativeGenerator.configure(...) and the expect assertion (remove the inline mock), ensuring the nested describe's beforeEach initializes or resets DependencyCollector and other inputs the test relies on so state is isolated for this case.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@code/lib/create-storybook/src/generators/REACT_NATIVE/metroConfig.ts`:
- Line 9: Replace the placeholder string in the exported constant
METRO_SETUP_DOCS_LINK with the official React Native Metro documentation URL;
locate the constant export (METRO_SETUP_DOCS_LINK) in the metroConfig.ts file
and update its value to the correct docs link (e.g., the canonical Metro bundler
docs or React Native Metro setup page) so consumers of METRO_SETUP_DOCS_LINK get
a valid reference before merging/release.
---
Nitpick comments:
In `@code/lib/create-storybook/src/generators/REACT_NATIVE/index.test.ts`:
- Around line 150-172: Move the inline mock override of
packageManager.getDependencyVersion out of the it('does not add cross-env when
it is already a dependency') body by creating a nested describe block for this
scenario and adding a beforeEach that sets packageManager =
createPackageManager(...) and then assigns packageManager.getDependencyVersion =
vi.fn((dep: string) => dep === 'cross-env' ? '^7.0.3' : null); keep the test
body only calling reactNativeGenerator.configure(...) and the expect assertion
(remove the inline mock), ensuring the nested describe's beforeEach initializes
or resets DependencyCollector and other inputs the test relies on so state is
isolated for this case.
In `@code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts`:
- Around line 20-21: The module-level mutable variables lastMetroCodemodResult
and lastScriptDerivationResult create hidden coupling between configure and
postConfigure; instead refactor so configure returns (or stores in an
instance-scoped context) the results it computes and postConfigure accepts that
context as an argument (or the generator returns an object containing configure
and postConfigure bound to the same instance), remove the module-scoped lets,
and update callers to pass the returned context to postConfigure so state is
explicit and not shared across generator invocations.
In `@code/lib/create-storybook/src/generators/REACT_NATIVE/metroConfig.ts`:
- Around line 34-38: hasStorybookPackage duplicates the package-check logic
already expressed in STORYBOOK_PACKAGE_PATTERNS; update hasStorybookPackage to
reference the constant instead of reimplementing the checks (e.g., use
STORYBOOK_PACKAGE_PATTERNS.some(...) or equivalent) so the pattern logic is
centralized and the catch-fallback still uses the same source of truth
(STORYBOOK_PACKAGE_PATTERNS) — modify the hasStorybookPackage function
accordingly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: ee79b61a-9654-4ce2-8363-93f012ad3ef1
📒 Files selected for processing (11)
code/lib/create-storybook/src/generators/REACT_NATIVE/generateEntrypoint.test.tscode/lib/create-storybook/src/generators/REACT_NATIVE/generateEntrypoint.tscode/lib/create-storybook/src/generators/REACT_NATIVE/generateScripts.test.tscode/lib/create-storybook/src/generators/REACT_NATIVE/generateScripts.tscode/lib/create-storybook/src/generators/REACT_NATIVE/index.test.tscode/lib/create-storybook/src/generators/REACT_NATIVE/index.tscode/lib/create-storybook/src/generators/REACT_NATIVE/metroConfig.test.tscode/lib/create-storybook/src/generators/REACT_NATIVE/metroConfig.tscode/lib/create-storybook/src/services/ProjectTypeService.test.tscode/lib/create-storybook/src/services/ProjectTypeService.tscode/lib/create-storybook/templates/react-native/index.js
Package BenchmarksCommit: The following packages have significant changes to their size or dependencies:
|
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 184 | 184 | 0 |
| Self size | 880 KB | 880 KB | 🚨 +8 B 🚨 |
| Dependency size | 68.28 MB | 68.30 MB | 🚨 +19 KB 🚨 |
| Bundle Size Analyzer | Link | Link |
create-storybook
| Before | After | Difference | |
|---|---|---|---|
| Dependency count | 51 | 51 | 0 |
| Self size | 1.05 MB | 1.07 MB | 🚨 +18 KB 🚨 |
| Dependency size | 37.15 MB | 37.15 MB | 🚨 +2 KB 🚨 |
| Bundle Size Analyzer | node | node |
- Added tests to ensure correct behavior when the base script already sets STORYBOOK_ENABLED. - Verified that explicit STORYBOOK_ENABLED=false is respected without overriding. - Ensured STORYBOOK_ENABLED is injected correctly into existing cross-env and cross-env-shell prefixes. - Included a test for trimming whitespace before applying the prefix. These changes improve coverage and reliability of the script generation logic for React Native. Fixes #34665 (comment)
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts (1)
8-13:⚠️ Potential issue | 🔴 CriticalRemove the duplicate
generateReactNativeEntrypointimport on line 13.Lines 8–11 already import
generateReactNativeEntrypointfrom'./generateEntrypoint.ts'. The re-import on line 13 creates a duplicate identifier and will prevent compilation.Fix
import { type ReactNativeEntrypointTemplateVariant, generateReactNativeEntrypoint, } from './generateEntrypoint.ts'; import { defineGeneratorModule } from '../modules/GeneratorModule.ts'; -import { generateReactNativeEntrypoint } from './generateEntrypoint.ts';🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts` around lines 8 - 13, Remove the duplicate import of generateReactNativeEntrypoint (the second import statement) so the module only imports generateReactNativeEntrypoint once alongside ReactNativeEntrypointTemplateVariant; update the import block that currently includes ReactNativeEntrypointTemplateVariant and generateReactNativeEntrypoint and delete the redundant standalone generateReactNativeEntrypoint import to avoid the duplicate identifier error.
🧹 Nitpick comments (1)
code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts (1)
103-117: ⚡ Quick winCall the entrypoint generator only once.
The entrypoint is generated before
templateVariantis known and then generated again with the derived variant. That first pass is redundant and may write the default variant before it gets overwritten.Fix
- await generateReactNativeEntrypoint({ language: context.language }); - const templateVariant: ReactNativeEntrypointTemplateVariant = detectReactNativeEntrypointTemplateVariant(packageManager.getAllDependencies());🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts` around lines 103 - 117, Remove the premature call to generateReactNativeEntrypoint so the entrypoint is only created once after the template variant is known: run runMetroCodemodOrFallback(...), call detectReactNativeEntrypointTemplateVariant(packageManager.getAllDependencies()), then invoke generateReactNativeEntrypoint({ language: context.language, templateVariant }) (i.e., delete or move the earlier generateReactNativeEntrypoint call so only the later call with the derived templateVariant remains).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts`:
- Around line 8-13: Remove the duplicate import of generateReactNativeEntrypoint
(the second import statement) so the module only imports
generateReactNativeEntrypoint once alongside
ReactNativeEntrypointTemplateVariant; update the import block that currently
includes ReactNativeEntrypointTemplateVariant and generateReactNativeEntrypoint
and delete the redundant standalone generateReactNativeEntrypoint import to
avoid the duplicate identifier error.
---
Nitpick comments:
In `@code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts`:
- Around line 103-117: Remove the premature call to
generateReactNativeEntrypoint so the entrypoint is only created once after the
template variant is known: run runMetroCodemodOrFallback(...), call
detectReactNativeEntrypointTemplateVariant(packageManager.getAllDependencies()),
then invoke generateReactNativeEntrypoint({ language: context.language,
templateVariant }) (i.e., delete or move the earlier
generateReactNativeEntrypoint call so only the later call with the derived
templateVariant remains).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: f835b8e2-ac60-4ca2-9960-18f9a5ceabbd
📒 Files selected for processing (4)
code/lib/create-storybook/src/generators/REACT_NATIVE/index.test.tscode/lib/create-storybook/src/generators/REACT_NATIVE/index.tscode/lib/create-storybook/src/generators/REACT_NATIVE/metroConfig.test.tscode/lib/create-storybook/src/generators/REACT_NATIVE/metroConfig.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- code/lib/create-storybook/src/generators/REACT_NATIVE/index.test.ts
- code/lib/create-storybook/src/generators/REACT_NATIVE/metroConfig.ts
…tor-orchestration
…ies mock function
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts (1)
102-115:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winDuplicate
generateReactNativeEntrypointcall.
generateReactNativeEntrypointis called twice: once on line 102 withouttemplateVariant, and again on lines 112-115 withtemplateVariant. The first call appears redundant since the second call immediately overwrites the generated entrypoint with the correct variant-specific template.🔧 Suggested fix: remove the redundant first call
- await generateReactNativeEntrypoint({ language: context.language }); - lastMetroCodemodResult = await runMetroCodemodOrFallback({ packageManager, yes: !!context.yes, }); const templateVariant: ReactNativeEntrypointTemplateVariant = detectReactNativeEntrypointTemplateVariant(packageManager.getAllDependencies()); await generateReactNativeEntrypoint({ language: context.language, templateVariant, });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts` around lines 102 - 115, The file calls generateReactNativeEntrypoint twice — once before detecting the template variant and once after — causing the first generated file to be immediately overwritten; remove the redundant first call (the await generateReactNativeEntrypoint({ language: context.language }) placed before runMetroCodemodOrFallback) so that generateReactNativeEntrypoint is only invoked once after you compute templateVariant via detectReactNativeEntrypointTemplateVariant(packageManager.getAllDependencies()), keeping the runMetroCodemodOrFallback call and lastMetroCodemodResult intact.
🧹 Nitpick comments (1)
code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts (1)
23-24: 💤 Low valueModule-level state for cross-phase communication.
The module-level variables
lastMetroCodemodResultandlastScriptDerivationResultare used to share state betweenconfigureandpostConfigure. This pattern works within the generator lifecycle but could retain stale values if the module is reused across multiple init runs without process restart. Consider whether this is acceptable for your testing/CLI reuse scenarios.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts` around lines 23 - 24, The module-level variables lastMetroCodemodResult and lastScriptDerivationResult are being used to pass data between configure and postConfigure which can leak stale state across multiple runs; change the flow to avoid module-level state by returning the results from configure (or attaching them to the generator execution context/options) and then reading that return/context in postConfigure, or if returning isn’t possible, explicitly reset/clear those variables at the end of postConfigure; update references to lastMetroCodemodResult and lastScriptDerivationResult in the configure and postConfigure implementations so they use the passed/attached values (or are cleared) instead of relying on module scope.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts`:
- Around line 102-115: The file calls generateReactNativeEntrypoint twice — once
before detecting the template variant and once after — causing the first
generated file to be immediately overwritten; remove the redundant first call
(the await generateReactNativeEntrypoint({ language: context.language }) placed
before runMetroCodemodOrFallback) so that generateReactNativeEntrypoint is only
invoked once after you compute templateVariant via
detectReactNativeEntrypointTemplateVariant(packageManager.getAllDependencies()),
keeping the runMetroCodemodOrFallback call and lastMetroCodemodResult intact.
---
Nitpick comments:
In `@code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts`:
- Around line 23-24: The module-level variables lastMetroCodemodResult and
lastScriptDerivationResult are being used to pass data between configure and
postConfigure which can leak stale state across multiple runs; change the flow
to avoid module-level state by returning the results from configure (or
attaching them to the generator execution context/options) and then reading that
return/context in postConfigure, or if returning isn’t possible, explicitly
reset/clear those variables at the end of postConfigure; update references to
lastMetroCodemodResult and lastScriptDerivationResult in the configure and
postConfigure implementations so they use the passed/attached values (or are
cleared) instead of relying on module scope.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: f6bfc79c-9a7b-4471-8f84-52d423643eaa
📒 Files selected for processing (4)
code/lib/create-storybook/src/generators/REACT_NATIVE/index.test.tscode/lib/create-storybook/src/generators/REACT_NATIVE/index.tscode/lib/create-storybook/src/generators/REACT_NATIVE/metroConfig.test.tscode/lib/create-storybook/src/generators/REACT_NATIVE/metroConfig.ts
✅ Files skipped from review due to trivial changes (1)
- code/lib/create-storybook/src/generators/REACT_NATIVE/metroConfig.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- code/lib/create-storybook/src/generators/REACT_NATIVE/index.test.ts
There was a problem hiding this comment.
🧹 Nitpick comments (1)
code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts (1)
103-116: ⚡ Quick winRedundant entrypoint generation calls.
generateReactNativeEntrypointis called twice: first at line 103 withouttemplateVariant, then again at lines 113-116 with the detected variant. The second call overwrites the first. Move thedetectReactNativeEntrypointTemplateVariantcall before line 103 to consolidate into a single generation.♻️ Proposed consolidation
+ const templateVariant: ReactNativeEntrypointTemplateVariant = + detectReactNativeEntrypointTemplateVariant(packageManager.getAllDependencies()); + + await generateReactNativeEntrypoint({ + language: context.language, + templateVariant, + }); - await generateReactNativeEntrypoint({ language: context.language }); lastMetroCodemodResult = await runMetroCodemodOrFallback({ packageManager, yes: !!context.yes, }); - const templateVariant: ReactNativeEntrypointTemplateVariant = - detectReactNativeEntrypointTemplateVariant(packageManager.getAllDependencies()); - - await generateReactNativeEntrypoint({ - language: context.language, - templateVariant, - });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts` around lines 103 - 116, There are two calls to generateReactNativeEntrypoint; remove the first call and call detectReactNativeEntrypointTemplateVariant once before generating the entrypoint so you only invoke generateReactNativeEntrypoint once with the detected templateVariant. Specifically, call detectReactNativeEntrypointTemplateVariant(packageManager.getAllDependencies()) earlier (before the initial generateReactNativeEntrypoint), then run runMetroCodemodOrFallback as required, and finally call generateReactNativeEntrypoint({ language: context.language, templateVariant }) once; delete the duplicate generateReactNativeEntrypoint invocation and keep uses of context.language and context.yes as before.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts`:
- Around line 103-116: There are two calls to generateReactNativeEntrypoint;
remove the first call and call detectReactNativeEntrypointTemplateVariant once
before generating the entrypoint so you only invoke
generateReactNativeEntrypoint once with the detected templateVariant.
Specifically, call
detectReactNativeEntrypointTemplateVariant(packageManager.getAllDependencies())
earlier (before the initial generateReactNativeEntrypoint), then run
runMetroCodemodOrFallback as required, and finally call
generateReactNativeEntrypoint({ language: context.language, templateVariant })
once; delete the duplicate generateReactNativeEntrypoint invocation and keep
uses of context.language and context.yes as before.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 29741652-6d2e-4489-9dd0-228e3915f395
📒 Files selected for processing (1)
code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts
Split out of #34333 (M1). Tracking issue: #34276.
What I did
Wires the React Native generator end-to-end during
storybook init:metro.config.{js,ts,cjs}withwithStorybook(...), falling back to a guidance comment when the AST transform can't be applied safely..rnstorybook/index.{ts,js}.generateScriptsto derivestorybook:ios/storybook:androidnpm scripts and requestcross-envwhen needed.ProjectTypeServiceto detect React Native projects via theexpodependency in addition toreact-native/react-native-scripts.This is the orchestration layer that makes the React Native init flow user-facing.
Stack
This PR is stacked on M1 + M2 and depends on them. It's targeted at
nextfor review, but the diff right now also includes the M1 and M2 commits because GitHub shows everything between this branch andnext. Once those merge, this PR's diff will collapse to the M3-only files.norbert/m1-metro-config-codemodnorbert/m2-entrypoint-generationdeviceAddons#34659Tracking issue: [Tracking]: Auto setup for ReactNative #34276. Original PR being split: ReactNative: Overhaul RN setup #34333.
Merge order
Checklist for Contributors
Testing
The changes in this PR are covered in the following automated tests:
Manual testing
Test 1: Fresh Expo project (TypeScript)
npx create-expo-app@latest MyExpoApp cd MyExpoApp npx storybook@canary initVerify:
metro.config.jsis wrapped withwithStorybook(...)and imports from@storybook/react-native/withStorybook.rnstorybook/index.tsxexists and containsAppRegistry.registerComponent.rnstorybook/main.tsand.rnstorybook/preview.tsxexistpackage.jsonhasstorybook:iosandstorybook:androidscripts withSTORYBOOK_ENABLED=trueSTORYBOOK_ENABLED=true npx expo start— Storybook launches with example stories visiblenpx expo start(without the env var) — your app launches normally, no StorybookTest 2: Existing project with a metro config already present
npx create-expo-app@latest MyExistingApp cd MyExistingApp npx expo customize metro.config.js npx storybook@canary initVerify:
metro.config.jsis modified in-place, not overwrittenwithStorybook(...)wraps the existing exportgetDefaultConfig) is preserved inside the wrapperTest 3: React Native CLI project (no Expo)
npx @react-native-community/cli init MyRNApp cd MyRNApp npx storybook@canary initVerify:
metro.config.jsis detected and wrapped correctlypackage.jsonscripts wrap the existingreact-nativecommands (notexpo)STORYBOOK_ENABLED=true npx react-native startlaunches StorybookDocumentation
MIGRATION.MD
Checklist for Maintainers
When this PR is ready for testing, make sure to add
ci:normal,ci:mergedorci:dailyGH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found incode/lib/cli-storybook/src/sandbox-templates.tsMake sure this PR contains one of the labels below:
Available labels
bug: Internal changes that fixes incorrect behavior.maintenance: User-facing maintenance tasks.dependencies: Upgrading (sometimes downgrading) dependencies.build: Internal-facing build tooling & test updates. Will not show up in release changelog.cleanup: Minor cleanup style change. Will not show up in release changelog.documentation: Documentation only changes. Will not show up in release changelog.feature request: Introducing a new feature.BREAKING CHANGE: Changes that break compatibility in some way with current major version.other: Changes that don't fit in the above categories.🦋 Canary release
This PR does not have a canary release associated. You can request a canary release of this pull request by mentioning the
@storybookjs/coreteam here.core team members can create a canary release here or locally with
gh workflow run --repo storybookjs/storybook publish.yml --field pr=<PR_NUMBER>