-
-
Notifications
You must be signed in to change notification settings - Fork 9.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #25215 from storybookjs/norbert/prompt-removal-rea…
…ct-automigration CLI: Add prompt-only automigrate asking for react-removal
- Loading branch information
Showing
2 changed files
with
204 additions
and
0 deletions.
There are no files selected for viewing
158 changes: 158 additions & 0 deletions
158
code/lib/cli/src/automigrate/fixes/prompt-remove-react.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
import type { StorybookConfig } from '@storybook/types'; | ||
import { glob } from 'glob'; | ||
import { removeReactDependency } from './prompt-remove-react'; | ||
import type { JsPackageManager } from '../../js-package-manager'; | ||
|
||
const check = async ({ | ||
packageManagerContent, | ||
main: mainConfig, | ||
storybookVersion = '8.0.0', | ||
}: { | ||
packageManagerContent: Pick< | ||
Partial<Awaited<ReturnType<JsPackageManager['retrievePackageJson']>>>, | ||
'dependencies' | 'devDependencies' | 'peerDependencies' | ||
>; | ||
main: Partial<StorybookConfig> & Record<string, unknown>; | ||
storybookVersion?: string; | ||
}) => { | ||
const packageManager = { | ||
retrievePackageJson: async () => packageManagerContent, | ||
} as JsPackageManager; | ||
|
||
return removeReactDependency.check({ | ||
packageManager, | ||
configDir: '', | ||
mainConfig: mainConfig as any, | ||
storybookVersion, | ||
}); | ||
}; | ||
|
||
jest.mock('glob', () => ({ glob: jest.fn(() => []) })); | ||
|
||
describe('early exits', () => { | ||
test('cancel if storybookVersion < 8', async () => { | ||
await expect( | ||
check({ | ||
packageManagerContent: { | ||
dependencies: { react: '16.0.0' }, | ||
}, | ||
main: { | ||
stories: [], | ||
framework: '@storybook/vue-vite', | ||
}, | ||
storybookVersion: '7.0.0', | ||
}) | ||
).resolves.toBeFalsy(); | ||
}); | ||
|
||
test('cancel if no react deps', async () => { | ||
await expect( | ||
check({ | ||
packageManagerContent: {}, | ||
main: { | ||
stories: [], | ||
framework: '@storybook/vue-vite', | ||
}, | ||
}) | ||
).resolves.toBeFalsy(); | ||
}); | ||
|
||
test('cancel if react renderer', async () => { | ||
await expect( | ||
check({ | ||
packageManagerContent: { | ||
dependencies: { react: '16.0.0' }, | ||
}, | ||
main: { | ||
stories: [], | ||
framework: '@storybook/react-vite', | ||
}, | ||
}) | ||
).resolves.toBeFalsy(); | ||
|
||
await expect( | ||
check({ | ||
packageManagerContent: { | ||
dependencies: { react: '16.0.0' }, | ||
}, | ||
main: { | ||
stories: [], | ||
framework: '@storybook/nextjs', | ||
}, | ||
}) | ||
).resolves.toBeFalsy(); | ||
|
||
await expect( | ||
check({ | ||
packageManagerContent: { | ||
dependencies: { react: '16.0.0' }, | ||
}, | ||
main: { | ||
stories: [], | ||
framework: { name: '@storybook/react-webpack5' }, | ||
}, | ||
}) | ||
).resolves.toBeFalsy(); | ||
}); | ||
}); | ||
|
||
describe('prompts', () => { | ||
test('simple', async () => { | ||
await expect( | ||
check({ | ||
packageManagerContent: { | ||
dependencies: { react: '16.0.0' }, | ||
}, | ||
main: { | ||
stories: ['*.stories.ts'], | ||
addons: [], | ||
framework: '@storybook/vue-vite', | ||
}, | ||
}) | ||
).resolves.toEqual(true); | ||
}); | ||
test('detects addon docs', async () => { | ||
await expect( | ||
check({ | ||
packageManagerContent: { | ||
dependencies: { react: '16.0.0' }, | ||
}, | ||
main: { | ||
stories: ['*.stories.ts'], | ||
addons: ['@storybook/addon-docs'], | ||
framework: '@storybook/vue-vite', | ||
}, | ||
}) | ||
).resolves.toEqual(true); | ||
}); | ||
test('detects addon essentials', async () => { | ||
await expect( | ||
check({ | ||
packageManagerContent: { | ||
dependencies: { react: '16.0.0' }, | ||
}, | ||
main: { | ||
stories: ['*.stories.ts'], | ||
addons: ['@storybook/addon-docs', '@storybook/addon-essentials'], | ||
framework: '@storybook/vue-vite', | ||
}, | ||
}) | ||
).resolves.toEqual(true); | ||
}); | ||
test('detects MDX usage', async () => { | ||
// @ts-expect-error (jest mocked) | ||
glob.mockImplementationOnce(() => ['*.stories.mdx']); | ||
await expect( | ||
check({ | ||
packageManagerContent: { | ||
dependencies: { react: '16.0.0' }, | ||
}, | ||
main: { | ||
stories: ['*.stories.ts'], | ||
addons: ['@storybook/addon-docs', '@storybook/addon-essentials'], | ||
framework: '@storybook/vue-vite', | ||
}, | ||
}) | ||
).resolves.toEqual(true); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import dedent from 'ts-dedent'; | ||
import semver from 'semver'; | ||
import { getFrameworkPackageName } from '../helpers/mainConfigFile'; | ||
import type { Fix } from '../types'; | ||
|
||
export const removeReactDependency: Fix<{}> = { | ||
id: 'remove-react-dependency', | ||
|
||
async check({ packageManager, mainConfig, storybookVersion }) { | ||
// when the user is using the react renderer, we should not prompt them to remove react | ||
const frameworkPackageName = getFrameworkPackageName(mainConfig); | ||
if (frameworkPackageName?.includes('react') || frameworkPackageName?.includes('nextjs')) { | ||
return null; | ||
} | ||
|
||
// if the user has no dependency on react, we can skip this fix | ||
const packageJson = await packageManager.retrievePackageJson(); | ||
if ( | ||
!packageJson?.dependencies?.['react'] && | ||
!packageJson?.peerDependencies?.['react'] && | ||
!packageJson?.devDependencies?.['react'] | ||
) { | ||
return null; | ||
} | ||
|
||
// do not prompt to remove react for older versions of storybook | ||
if (!semver.gte(storybookVersion, '8.0.0')) { | ||
return null; | ||
} | ||
|
||
return true; | ||
}, | ||
prompt() { | ||
return dedent` | ||
We detected that your project has a dependency for "react" that it might not need. | ||
Nothing breaks by having it, you can safely ignore this message, if you wish. | ||
Storybook asked you to add "react" as a direct dependency in the past. | ||
However, since version 8.0, Storybook no longer requires you to provide "react" as a dependency. | ||
Some community addons might still wrongfully list "react" and "react-dom" as required peer dependencies, but since Storybook 7.6 it should not be needed in the majority of cases. | ||
If you know you are not using React outside of Storybook, it should be safe to remove the "react" and "react-dom" dependencies from your project's package.json. | ||
Storybook cannot do this automatically as removing it might break your project, so it should be done manually with care. | ||
`; | ||
}, | ||
}; |