Skip to content

ReactNative: Overhaul RN setup#34333

Closed
ndelangen wants to merge 43 commits into
nextfrom
norbert/rn-init-overhaul
Closed

ReactNative: Overhaul RN setup#34333
ndelangen wants to merge 43 commits into
nextfrom
norbert/rn-init-overhaul

Conversation

@ndelangen
Copy link
Copy Markdown
Member

@ndelangen ndelangen commented Mar 26, 2026

Tracked by #34276

Closes: M1, M2, M3 and partially M8

Companion PR: storybookjs/react-native#871

What I did

Overhauled storybook init for React Native to deliver a fully automated, zero-manual-config setup — matching the Storybook for Web mental model where Storybook runs as its own entry point.

Metro config codemod (M1)

  • AST-based transformation of metro.config.js to wrap the exported config with withStorybook()
  • Handles ESM, CommonJS, function declarations, async functions, and TypeScript
  • Idempotent — skips if already wrapped
  • Fallback comment system for unsupported config shapes with link to docs

Entrypoint generation (M2)

  • Generates .rnstorybook/index.{ts,js} from a template
  • Language-aware (TypeScript or JavaScript based on project)
  • User-editable — serves a similar role to preview.js on web

SB init orchestration (M3)

  • Runs the metro codemod, generates the entrypoint, and derives storybook:ios / storybook:android npm scripts
  • Scripts wrap existing ios/android scripts with STORYBOOK_ENABLED=true
  • Post-configure messaging guides users on next steps
  • Detects and handles cross-env for Windows compatibility

On-device addons automigration (M8)

  • New automigration rn-ondevice-addons-to-device-addons: moves any addon with ondevice in its name from addonsdeviceAddons in the user's .rnstorybook/main.ts
  • Handles both string and object ({ name, options }) addon forms
  • MIGRATION.md updated with before/after example (v10.3 → 10.4 section)
  • Context: on-device addons in addons break extract on SB10 because Core evaluates them as Node.js presets — see Split addons from "ondevice" addons in main.ts react-native#873

Project detection

  • Added expo as a recognized React Native dependency in ProjectTypeService

Checklist for Contributors

Testing

The changes in this PR are covered in the following automated tests:

  • stories
  • unit tests
  • integration tests
  • end-to-end tests

Manual testing

  1. Run npx storybook@0.0.0-pr-34333-sha-865b50bc init in a fresh Expo project
  2. Verify .rnstorybook/index.ts is generated
  3. Verify metro.config.js is wrapped with withStorybook()
  4. Verify storybook:ios and storybook:android scripts are added to package.json
  5. Run npx storybook@0.0.0-pr-34333-sha-865b50bc automigrate in a project with on-device addons in addons — verify they move to deviceAddons

I verified the above

Documentation

  • Add or update documentation reflecting your changes
  • If you are deprecating/removing a feature, make sure to update
    MIGRATION.MD

🦋 Canary release

This pull request has been released as version 0.0.0-pr-34333-sha-823a6755. Try it out in a new sandbox by running npx storybook@0.0.0-pr-34333-sha-823a6755 sandbox or in an existing project with npx storybook@0.0.0-pr-34333-sha-823a6755 upgrade.

More information
Published version 0.0.0-pr-34333-sha-823a6755
Triggered by @ndelangen
Repository storybookjs/storybook
Branch norbert/rn-init-overhaul
Commit 823a6755
Datetime Thu Apr 23 18:43:20 UTC 2026 (1776969800)
Workflow run 24852596938

To request a new release of this pull request, mention the @storybookjs/core team.

core team members can create a new canary release here or locally with gh workflow run --repo storybookjs/storybook publish.yml --field pr=34333

Summary by CodeRabbit

  • New Features

    • Automated Metro config updates with Storybook integration
    • Auto-generated iOS/Android run scripts prefixed with STORYBOOK env
    • Generates React Native Storybook entrypoint for TypeScript and JavaScript
    • Improved post-configuration messaging with inferred run-script guidance and Metro status
  • Documentation

    • Migration note: move on-device addons from addons → deviceAddons in .rnstorybook/main.ts
  • Tests

    • Added comprehensive tests for entrypoint generation, script derivation, Metro codemod, and generator flows

@ndelangen ndelangen marked this pull request as draft March 26, 2026 08:57
@ndelangen ndelangen self-assigned this Mar 26, 2026
@nx-cloud
Copy link
Copy Markdown

nx-cloud Bot commented Mar 26, 2026

View your CI Pipeline Execution ↗ for commit 0872682

Command Status Duration Result
nx run-many -t compile,check,knip,test,lint,fmt... ✅ Succeeded 8m 23s View ↗

☁️ Nx Cloud last updated this comment at 2026-04-17 12:18:20 UTC

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 26, 2026

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds React Native Storybook support: generates an RN entrypoint, derives platform run scripts, applies a Metro config codemod (with fallback), integrates these into the RN generator lifecycle, and documents an on-device addons migration.

Changes

Cohort / File(s) Summary
Entrypoint Generation
code/lib/create-storybook/src/generators/REACT_NATIVE/generateEntrypoint.ts, code/lib/create-storybook/src/generators/REACT_NATIVE/generateEntrypoint.test.ts
New module to render/write `.rnstorybook/index.<ts
Platform Scripts Derivation
code/lib/create-storybook/src/generators/REACT_NATIVE/generateScripts.ts, code/lib/create-storybook/src/generators/REACT_NATIVE/generateScripts.test.ts
New logic to derive storybook:ios / storybook:android by prefixing base scripts with cross-env STORYBOOK_ENABLED=true; returns derived scripts and missingBaseScripts; tests cover generation, missing detection, and immutability.
Metro Config Codemod
code/lib/create-storybook/src/generators/REACT_NATIVE/metroConfig.ts, code/lib/create-storybook/src/generators/REACT_NATIVE/metroConfig.test.ts
Adds codemod to detect/inject Storybook imports (ESM/CJS), wrap exports with withStorybook (preserving async/generic signatures), handle Expo variants, idempotency, candidate selection/prompting, and prepend a fallback guidance comment; extensive tests included.
Generator Integration
code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts, code/lib/create-storybook/src/generators/REACT_NATIVE/index.test.ts
Integrates script derivation, entrypoint generation, and Metro codemod into configure/postConfigure: conditionally adds cross-env, pins on-device deps to canary, writes RN entrypoint to RN_STORYBOOK_DIR, records codemod result, and updates console messaging; tests verify script writes, legacy cleanup, and messaging.
Documentation / Migration
MIGRATION.md
Adds 10.3.0→10.4.0 migration notes: move on-device addons from addonsdeviceAddons in .rnstorybook/main.ts, shows before/after, and names the automigration.

Sequence Diagrams

sequenceDiagram
    participant User
    participant Generator
    participant PackageManager
    participant FileSystem
    participant MetroCodemod
    participant Logger

    User->>Generator: configure({ language, yes? })
    Generator->>PackageManager: read package.json scripts
    PackageManager-->>Generator: scripts
    Generator->>Generator: deriveStorybookPlatformScripts(scripts)
    Generator->>FileSystem: write .rnstorybook/index.<ts|js>
    FileSystem-->>Generator: targetPath
    Generator->>MetroCodemod: runMetroCodemodOrFallback({ packageManager, yes })
    MetroCodemod-->>Generator: MetroCodemodResult
    Generator->>PackageManager: addScripts(derived scripts + storybook-generate)
    Generator->>Logger: save derivation & codemod result
    Generator-->>User: configure complete

    User->>Generator: postConfigure()
    Generator->>Logger: print "Storybook run scripts" guidance
    alt missing base scripts
        Generator->>Logger: print STORYBOOK_ENABLED=true fallback instruction
    end
    Generator->>Logger: print Metro codemod status
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~70 minutes

Possibly related PRs


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
code/lib/create-storybook/src/generators/REACT_NATIVE/generateScripts.test.ts (1)

5-48: Consider adding edge case tests.

The current tests cover the main scenarios well. Consider adding tests for edge cases like undefined scripts, empty string values, and non-string script values (e.g., { ios: 123 }), which the implementation handles but aren't explicitly tested.

🤖 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/generateScripts.test.ts`
around lines 5 - 48, Add edge-case unit tests for
deriveStorybookPlatformScripts: add cases where input scripts contain undefined
values (e.g., { ios: undefined }), empty strings ({ android: '' }), and
non-string values ({ ios: 123 }) and assert the function treats those as missing
base scripts (appear in missingBaseScripts) and does not add corresponding
storybook:* entries to scriptsToAdd; also confirm the function does not mutate
the original input object (compare against a snapshot) and that scriptsToAdd
only contains entries for valid string commands. Use
deriveStorybookPlatformScripts, scriptsToAdd, and missingBaseScripts in the new
tests to mirror existing test style.
code/lib/create-storybook/src/generators/REACT_NATIVE/index.test.ts (1)

99-120: Consider making the output assertions more robust.

The test relies on checking the last logged message via mock.calls.at(-1). If additional log calls are added in the future, this could become fragile.

Consider using toHaveBeenCalledWith(expect.stringContaining(...)) or iterating over all calls to find relevant messages:

const allLogs = vi.mocked(logger.log).mock.calls.map(c => String(c[0]));
expect(allLogs.some(log => log.includes('npm run storybook:ios'))).toBe(true);

That said, testing the final output message is reasonable for verifying user-facing behavior.

🤖 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 99 - 120, The test "postConfigure removes legacy entry replacement copy"
is brittle because it asserts on the last logger.log call via
vi.mocked(logger.log).mock.calls.at(-1); update the assertions to inspect all
logger.log calls instead: map vi.mocked(logger.log).mock.calls to strings (or
use
expect(vi.mocked(logger.log)).toHaveBeenCalledWith(expect.stringContaining(...)))
and assert that some log includes 'npm run storybook:ios' and 'npm run
storybook:android' and that none include 'Replace the contents of your app
entry'; update the assertions around logger.log in this test and keep the rest
of the test (including invoking reactNativeGenerator.configure/postConfigure)
unchanged.
🤖 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/generateScripts.ts`:
- Around line 8-12: The generated Storybook scripts use the STORYBOOK_ENV_PREFIX
(which includes "cross-env") via withStorybookEnv, but the configure function in
REACT_NATIVE/index.ts never adds cross-env to devDependencies; update the
configure function to add "cross-env" to the devDependencies/packages list
that's installed for React Native projects so the generated scripts will run.
Locate the configure function in REACT_NATIVE/index.ts and include "cross-env"
alongside the other dev packages added during setup (ensure it's added as a
devDependency, not a runtime dependency).

In `@code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts`:
- Around line 19-20: The module-level variables lastMetroCodemodResult and
lastScriptDerivationResult can leak state between generator runs; update the
implementation so state is not stored at module scope—either clear these
variables at the start of configure or move them into per-run storage (e.g.,
capture them in a closure/class instance or return them from configure for
postConfigure to consume). Concretely, remove reliance on the module-level
lastMetroCodemodResult/lastScriptDerivationResult and ensure configure
initializes fresh per-run state (or returns a state object) that postConfigure
uses, updating references in configure and postConfigure accordingly (symbols:
lastMetroCodemodResult, lastScriptDerivationResult, configure, postConfigure,
GeneratorModule).

In `@code/lib/create-storybook/src/generators/REACT_NATIVE/metroConfig.ts`:
- Around line 8-14: Replace the placeholder constants that will be exposed to
users: update METRO_SETUP_DOCS_LINK to point to the real React Native Metro docs
URL and replace EXPO_CREATE_METRO_COMMAND (the command and args in the
EXPO_CREATE_METRO_COMMAND constant) with the actual Expo CLI command and
arguments used to generate a metro config; ensure the values are accurate,
user-friendly, and tested (references: METRO_SETUP_DOCS_LINK and
EXPO_CREATE_METRO_COMMAND in this file), and keep METRO_CONFIG_CANDIDATES and
METRO_FALLBACK_COMMENT_MARKER unchanged unless you need to add another candidate
or alter the marker text for clarity.

---

Nitpick comments:
In
`@code/lib/create-storybook/src/generators/REACT_NATIVE/generateScripts.test.ts`:
- Around line 5-48: Add edge-case unit tests for deriveStorybookPlatformScripts:
add cases where input scripts contain undefined values (e.g., { ios: undefined
}), empty strings ({ android: '' }), and non-string values ({ ios: 123 }) and
assert the function treats those as missing base scripts (appear in
missingBaseScripts) and does not add corresponding storybook:* entries to
scriptsToAdd; also confirm the function does not mutate the original input
object (compare against a snapshot) and that scriptsToAdd only contains entries
for valid string commands. Use deriveStorybookPlatformScripts, scriptsToAdd, and
missingBaseScripts in the new tests to mirror existing test style.

In `@code/lib/create-storybook/src/generators/REACT_NATIVE/index.test.ts`:
- Around line 99-120: The test "postConfigure removes legacy entry replacement
copy" is brittle because it asserts on the last logger.log call via
vi.mocked(logger.log).mock.calls.at(-1); update the assertions to inspect all
logger.log calls instead: map vi.mocked(logger.log).mock.calls to strings (or
use
expect(vi.mocked(logger.log)).toHaveBeenCalledWith(expect.stringContaining(...)))
and assert that some log includes 'npm run storybook:ios' and 'npm run
storybook:android' and that none include 'Replace the contents of your app
entry'; update the assertions around logger.log in this test and keep the rest
of the test (including invoking reactNativeGenerator.configure/postConfigure)
unchanged.
🪄 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: 6cf731fa-ff73-4e11-a696-0e40bc249414

📥 Commits

Reviewing files that changed from the base of the PR and between 1c38a36 and db8ded3.

📒 Files selected for processing (9)
  • code/lib/create-storybook/src/generators/REACT_NATIVE/generateEntrypoint.test.ts
  • code/lib/create-storybook/src/generators/REACT_NATIVE/generateEntrypoint.ts
  • code/lib/create-storybook/src/generators/REACT_NATIVE/generateScripts.test.ts
  • code/lib/create-storybook/src/generators/REACT_NATIVE/generateScripts.ts
  • code/lib/create-storybook/src/generators/REACT_NATIVE/index.test.ts
  • code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts
  • code/lib/create-storybook/src/generators/REACT_NATIVE/metroConfig.test.ts
  • code/lib/create-storybook/src/generators/REACT_NATIVE/metroConfig.ts
  • code/lib/create-storybook/src/generators/REACT_NATIVE/templates/index.js

Comment thread code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts
@storybook-app-bot
Copy link
Copy Markdown

storybook-app-bot Bot commented Mar 26, 2026

Package Benchmarks

Commit: 81972cc, ran on 29 April 2026 at 13:09:22 UTC

The following packages have significant changes to their size or dependencies:

@storybook/cli

Before After Difference
Dependency count 184 184 0
Self size 782 KB 785 KB 🚨 +4 KB 🚨
Dependency size 68.22 MB 68.24 MB 🚨 +17 KB 🚨
Bundle Size Analyzer Link Link

create-storybook

Before After Difference
Dependency count 51 51 0
Self size 1.04 MB 1.06 MB 🚨 +16 KB 🚨
Dependency size 37.10 MB 37.10 MB 🚨 +740 B 🚨
Bundle Size Analyzer node node

ndelangen and others added 10 commits March 26, 2026 11:26
- Add `deviceAddons` field to `StorybookConfigRaw` type in core-common.ts
- Create `rn-ondevice-addons-to-device-addons` automigration fix that
  moves addons with 'ondevice' in their name from `addons` to `deviceAddons`
  in React Native Storybook projects
- Register the new fix in the allFixes list
- Add comprehensive tests (9 tests) for the check and run phases

Agent-Logs-Url: https://github.com/storybookjs/storybook/sessions/4e6650e3-b5dc-4d8c-b331-2c0b7f9506e4

Co-authored-by: ndelangen <3070389+ndelangen@users.noreply.github.com>
Per review feedback, deviceAddons is React Native-specific and should not
live in the shared core type. The automigration fix uses ConfigFile string-path
APIs so it works without the type definition.

Agent-Logs-Url: https://github.com/storybookjs/storybook/sessions/98fca5c1-3428-4436-8892-f4254f66193f

Co-authored-by: ndelangen <3070389+ndelangen@users.noreply.github.com>
Co-authored-by: ndelangen <3070389+ndelangen@users.noreply.github.com>
@ndelangen
Copy link
Copy Markdown
Member Author

@copilot, can you update this PR to match the base branch and resolve any merge conflicts?

# Conflicts:
#	code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts

Co-authored-by: ndelangen <3070389+ndelangen@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 9, 2026

@copilot, can you update this PR to match the base branch and resolve any merge conflicts?

Done. Merged origin/next into this branch (commit dda4bb1). There was one conflict in index.ts — resolved by keeping the React Native implementation and updating the GeneratorModule import to use the .ts extension, consistent with the codebase migration to native Node execution.

@ndelangen ndelangen changed the title Storybook for ReactNative overhaul ReactNative: Overhaul RN setup Apr 9, 2026
…opilot/add-device-addons-property

Co-authored-by: ndelangen <3070389+ndelangen@users.noreply.github.com>
@ndelangen ndelangen marked this pull request as ready for review April 17, 2026 11:13
Copilot AI review requested due to automatic review settings April 17, 2026 11:13
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Overhauls the React Native storybook init flow to generate a dedicated .rnstorybook entrypoint, automatically update Metro config via codemod, and add platform run scripts; also adds an automigration to move on-device addons from addons to deviceAddons.

Changes:

  • Add Metro config codemod with fallback commenting + tests.
  • Generate .rnstorybook/index.(ts|js) entrypoint and derive storybook:ios / storybook:android scripts (with optional cross-env).
  • Add RN automigration for on-device addons and document it in MIGRATION.md; improve RN project detection (treat expo as RN signal).

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
code/lib/create-storybook/templates/react-native/index.js New user-editable RN Storybook entrypoint template.
code/lib/create-storybook/src/services/ProjectTypeService.ts Adds expo as a dependency signal for React Native project detection.
code/lib/create-storybook/src/services/ProjectTypeService.test.ts Adds coverage for RN detection via expo.
code/lib/create-storybook/src/generators/REACT_NATIVE/metroConfig.ts Implements Metro config codemod + fallback comment behavior.
code/lib/create-storybook/src/generators/REACT_NATIVE/metroConfig.test.ts Adds unit tests for Metro codemod behavior and prompting paths.
code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts Orchestrates RN init: entrypoint generation, Metro codemod, script derivation, updated post-configure 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 existing platform scripts.
code/lib/create-storybook/src/generators/REACT_NATIVE/generateScripts.test.ts 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 Unit tests for entrypoint generation behavior.
code/lib/cli-storybook/src/automigrate/multi-project.ts Uses shared RN config dir constant during RN automigration path rewriting.
code/lib/cli-storybook/src/automigrate/fixes/rnstorybook-config.ts Uses shared RN config dir constant for .rnstorybook rename operations.
code/lib/cli-storybook/src/automigrate/fixes/rn-ondevice-addons-to-device-addons.ts New automigration moving ondevice addons to deviceAddons (including sibling .storybook/.rnstorybook).
code/lib/cli-storybook/src/automigrate/fixes/rn-ondevice-addons-to-device-addons.test.ts Unit tests for the new automigration.
code/lib/cli-storybook/src/automigrate/fixes/index.ts Registers the new RN automigration fix.
code/core/src/shared/constants/config-folder.ts Introduces RN_STORYBOOK_DIR constant.
MIGRATION.md Documents RN on-device addon migration in 10.3 → 10.4 section.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +59 to +61
'@storybook/addon-ondevice-controls@10.4.0-canary-20260410142651',
'@storybook/addon-ondevice-actions@10.4.0-canary-20260410142651',
'@storybook/react-native@10.4.0-canary-20260410142651',
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The generator pins @storybook/react-native and on-device addons to a specific canary timestamp version. Because these packages are external to this monorepo, getVersionedPackages() will keep the exact canary string, which can quickly become stale and makes storybook init non-reproducible across releases. Prefer leaving these unpinned (let getVersionedPackages() choose @^<latest>), or pin them via a stable tag/channel that you control (e.g. next) rather than a one-off canary build.

Suggested change
'@storybook/addon-ondevice-controls@10.4.0-canary-20260410142651',
'@storybook/addon-ondevice-actions@10.4.0-canary-20260410142651',
'@storybook/react-native@10.4.0-canary-20260410142651',
'@storybook/addon-ondevice-controls',
'@storybook/addon-ondevice-actions',
'@storybook/react-native',

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll revert this change before merging, but only after the RN PR has been merged.

Comment thread code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts Outdated
Comment thread MIGRATION.md Outdated
import { logger, prompt } from 'storybook/internal/node-logger';

export const METRO_CONFIG_CANDIDATES = ['metro.config.ts', 'metro.config.js', 'metro.config.cjs'];
export const METRO_SETUP_DOCS_LINK = 'TODO_REPLACE_WITH_REACT_NATIVE_METRO_DOCS_LINK';
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

METRO_SETUP_DOCS_LINK is still a TODO placeholder string. This will surface to users both in the inserted fallback comment and in the post-configure CLI output, leaving them without a real docs URL. Replace this constant with the actual React Native Metro setup documentation link (and consider adding a simple test asserting it's not left as a TODO).

Suggested change
export const METRO_SETUP_DOCS_LINK = 'TODO_REPLACE_WITH_REACT_NATIVE_METRO_DOCS_LINK';
export const METRO_SETUP_DOCS_LINK = 'https://reactnative.dev/docs/metro';

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, this should likely point to a page created/updated in this PR:
storybookjs/react-native#877

Comment thread code/lib/create-storybook/src/generators/REACT_NATIVE/metroConfig.ts Outdated
ndelangen and others added 4 commits April 17, 2026 13:59
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…s and improve logging for manual setup guidance
…ul' of github.com:storybookjs/storybook into norbert/rn-init-overhaul
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (1)
code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts (1)

20-21: ⚠️ Potential issue | 🟡 Minor

Avoid carrying per-run results in module globals.

lastMetroCodemodResult and lastScriptDerivationResult still persist across invocations, so a later generator run in the same process can print stale post-configure guidance. Please reset them per run or thread the data through configure/postConfigure instead.

🤖 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, lastMetroCodemodResult and lastScriptDerivationResult are stored as
module-level globals and can leak stale data between generator runs; instead
reset them at the start of each run or pass their values through the
configure/postConfigure flow. Update the generator so that before each
invocation you clear or reinitialize lastMetroCodemodResult and
lastScriptDerivationResult, or refactor the logic to return the
MetroCodemodResult and StorybookPlatformScriptDerivationResult from the
configure function and accept them as parameters to postConfigure (referencing
the configure and postConfigure functions and the symbols lastMetroCodemodResult
and lastScriptDerivationResult). Ensure no code path relies on the module
globals after the change.
🤖 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/index.ts`:
- Around line 127-155: The metro codemod result 'skipped-codemod-failed' is not
being handled: update the metroCodemodSummary IIFE to include a branch for
lastMetroCodemodResult.status === 'skipped-codemod-failed' that returns a clear
failure message (referencing metroCodemodSummary and lastMetroCodemodResult),
and add 'skipped-codemod-failed' to the showWithStorybookManualSnippet condition
so the manual recovery snippet and notes are shown when
runMetroCodemodOrFallback() reports that failure.
- Line 89: generateReactNativeEntrypoint currently overwrites existing
.rnstorybook/index.* unconditionally; change it so existing user customizations
are preserved by only creating the entrypoint when it does not exist or by
prompting before replacing. Specifically, before calling
generateReactNativeEntrypoint (or inside that function), detect the presence of
.rnstorybook/index.js/.ts/.tsx and skip generation if any exist (or present an
interactive confirmation to overwrite), and ensure generateReactNativeEntrypoint
is updated to accept an option like overwrite: boolean or to return a status so
the caller can decide; reference generateReactNativeEntrypoint and the
.rnstorybook/index.* target files when making the change.
- Around line 118-125: Update the scriptWarningSummary so it does not hard-code
POSIX "STORYBOOK_ENABLED=true" but instead reuses the same cross-platform
environment-prefix helper used for the derived-script output (i.e., call the
shared env-prefix function the codebase uses for inferred scripts) to produce
the correct prefix and then render the fallback command(s); use
lastScriptDerivationResult?.missingBaseScripts to map each missing script into a
platform-safe command like `${envPrefix} <script>` (or show platform-specific
variants) rather than emitting the raw POSIX-only string.

---

Duplicate comments:
In `@code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts`:
- Around line 20-21: lastMetroCodemodResult and lastScriptDerivationResult are
stored as module-level globals and can leak stale data between generator runs;
instead reset them at the start of each run or pass their values through the
configure/postConfigure flow. Update the generator so that before each
invocation you clear or reinitialize lastMetroCodemodResult and
lastScriptDerivationResult, or refactor the logic to return the
MetroCodemodResult and StorybookPlatformScriptDerivationResult from the
configure function and accept them as parameters to postConfigure (referencing
the configure and postConfigure functions and the symbols lastMetroCodemodResult
and lastScriptDerivationResult). Ensure no code path relies on the module
globals after the change.
🪄 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: d92e83a8-89bd-46ef-bdf6-186f48848727

📥 Commits

Reviewing files that changed from the base of the PR and between ffca1b8 and b27b132.

📒 Files selected for processing (1)
  • code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts

Comment thread code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts
Comment thread code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts
Comment thread code/lib/create-storybook/src/generators/REACT_NATIVE/index.ts
ndelangen

This comment was marked as resolved.

@ndelangen
Copy link
Copy Markdown
Member Author

I'm splitting this review up to make it easier to review.

@ndelangen ndelangen mentioned this pull request Apr 30, 2026
20 tasks
@ndelangen
Copy link
Copy Markdown
Member Author

Closing this PR in favor of smaller, milestone-scoped PRs that are easier to review independently:

M8 — deviceAddons automigration: #34659
M1 — Metro config AST codemod: #34660
M2 — Entrypoint generation: #34663
M3 — Generator orchestration + scripts: #34665

Each PR is a complete, reviewable, mergeable unit. M8 is independent (different package). M1 and M2 are self-contained utilities with full test coverage. M3 wires them together and depends on M1 + M2 being merged first.
Tracking issue: #34276

@ndelangen ndelangen closed this Apr 30, 2026
pull Bot pushed a commit to NeatNerdPrime/storybook that referenced this pull request May 4, 2026
…dons`

Adds a new `rn-ondevice-addons-to-device-addons` automigration that moves
on-device addons (packages whose name contains `ondevice`) from the shared
`addons` array into a new `deviceAddons` array in `.rnstorybook/main.ts`.

This is needed because Storybook Core evaluates every entry in `addons` as
a Node.js preset, which on-device addons are not, and that causes
`storybook extract` to fail.

Split out of storybookjs#34333 (M8). Tracking issue: storybookjs#34276.

Made-with: Cursor
pull Bot pushed a commit to MichaelDeBoey/storybook that referenced this pull request May 4, 2026
Adds a self-contained generator that creates the `.rnstorybook/index.{ts,js}`
entry point for React Native projects, copying it from a static template and
choosing the file extension based on the project's language preference
(TypeScript vs JavaScript).

The entry point template registers a root component via
`AppRegistry.registerComponent` and configures `getStorybookUI` with storage,
producing a user-editable file.

Files added:
- `src/generators/REACT_NATIVE/generateEntrypoint.ts` — the generator
- `src/generators/REACT_NATIVE/generateEntrypoint.test.ts` — full coverage
- `templates/react-native/index.js` — the static template

This module is intentionally not yet wired into the React Native generator;
that orchestration arrives in M3.

Split out of storybookjs#34333 (M2). Tracking issue: storybookjs#34276.

Made-with: Cursor
pull Bot pushed a commit to NeatNerdPrime/storybook that referenced this pull request May 5, 2026
Adds an AST-based codemod (using `recast` + `@babel/parser` via the existing
`storybook/internal/babel` re-export) that wraps a project's `metro.config.{js,ts,cjs}`
export with `withStorybook(...)` and adds the matching import.

Handles:
- CommonJS (`module.exports = ...`) and ESM (`export default ...`)
- Direct config objects, function declarations, and `async` functions
- TypeScript sources
- Idempotency (won't double-wrap configs that already include Storybook)

Also exports a fallback path that prepends a guidance comment to the metro
config when the AST transform can't be applied safely.

This module is intentionally a self-contained, tested utility — it is not
yet wired into the React Native generator. That orchestration arrives in M3.

Split out of storybookjs#34333 (M1). Tracking issue: storybookjs#34276.

Made-with: Cursor
pull Bot pushed a commit to MichaelDeBoey/storybook that referenced this pull request May 5, 2026
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 storybookjs#34333 (M3). Tracking issue: storybookjs#34276.

Made-with: Cursor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants