From 5fd8728ddcd0c8a277793da8da6812b867dfe433 Mon Sep 17 00:00:00 2001 From: Ian VanSchooten Date: Mon, 10 Oct 2022 19:34:52 -0400 Subject: [PATCH 1/3] CLI: Add PNPM support (--use-pnpm) --- code/lib/cli/src/add.ts | 8 +- code/lib/cli/src/automigrate/index.ts | 6 +- code/lib/cli/src/generate.ts | 10 +- code/lib/cli/src/generators/types.ts | 1 + code/lib/cli/src/initiate.ts | 5 +- .../js-package-manager/JsPackageManager.ts | 2 +- .../JsPackageManagerFactory.test.ts | 259 +++++++++++++----- .../JsPackageManagerFactory.ts | 28 +- .../src/js-package-manager/PNPMProxy.test.ts | 204 ++++++++++++++ .../cli/src/js-package-manager/PNPMProxy.ts | 77 ++++++ .../cli/src/js-package-manager/Yarn2Proxy.ts | 1 + code/lib/cli/src/upgrade.ts | 6 +- .../next-repro-generators/generate-repros.ts | 2 +- scripts/tasks/sandbox-parts.ts | 2 +- 14 files changed, 524 insertions(+), 87 deletions(-) create mode 100644 code/lib/cli/src/js-package-manager/PNPMProxy.test.ts create mode 100644 code/lib/cli/src/js-package-manager/PNPMProxy.ts diff --git a/code/lib/cli/src/add.ts b/code/lib/cli/src/add.ts index 369ce570efd8..667b41447acc 100644 --- a/code/lib/cli/src/add.ts +++ b/code/lib/cli/src/add.ts @@ -65,8 +65,12 @@ const getVersionSpecifier = (addon: string) => { * it will try to use the version specifier matching your current * Storybook install version. */ -export async function add(addon: string, options: { useNpm: boolean; skipPostinstall: boolean }) { - const packageManager = JsPackageManagerFactory.getPackageManager(options.useNpm); +export async function add( + addon: string, + options: { useNpm: boolean; usePnpm: boolean; skipPostinstall: boolean } +) { + const { useNpm, usePnpm } = options; + const packageManager = JsPackageManagerFactory.getPackageManager({ useNpm, usePnpm }); const packageJson = packageManager.retrievePackageJson(); const [addonName, versionSpecifier] = getVersionSpecifier(addon); diff --git a/code/lib/cli/src/automigrate/index.ts b/code/lib/cli/src/automigrate/index.ts index 0eab9bca3d9c..04f49483a6c6 100644 --- a/code/lib/cli/src/automigrate/index.ts +++ b/code/lib/cli/src/automigrate/index.ts @@ -12,10 +12,12 @@ interface FixOptions { fixId?: string; yes?: boolean; dryRun?: boolean; + useNpm?: boolean; + usePnpm?: boolean; } -export const automigrate = async ({ fixId, dryRun, yes }: FixOptions = {}) => { - const packageManager = JsPackageManagerFactory.getPackageManager(); +export const automigrate = async ({ fixId, dryRun, yes, useNpm, usePnpm }: FixOptions = {}) => { + const packageManager = JsPackageManagerFactory.getPackageManager({ useNpm, usePnpm }); const filtered = fixId ? fixes.filter((f) => f.id === fixId) : fixes; logger.info('🔎 checking possible migrations..'); diff --git a/code/lib/cli/src/generate.ts b/code/lib/cli/src/generate.ts index acfcb7e79021..0234791a9c4a 100644 --- a/code/lib/cli/src/generate.ts +++ b/code/lib/cli/src/generate.ts @@ -7,6 +7,7 @@ import { sync as readUpSync } from 'read-pkg-up'; import { logger } from '@storybook/node-logger'; +import { CommandOptions } from './generators/types'; import { initiate } from './initiate'; import { add } from './add'; import { migrate } from './migrate'; @@ -39,13 +40,14 @@ program .option('-f --force', 'Force add Storybook') .option('-s --skip-install', 'Skip installing deps') .option('-N --use-npm', 'Use npm to install deps') + .option('--use-pnpm', 'Use pnpm to install deps') .option('--use-pnp', 'Enable pnp mode') .option('-p --parser ', 'jscodeshift parser') .option('-t --type ', 'Add Storybook for a specific project type') .option('-y --yes', 'Answer yes to all prompts') - .option('-b --builder ', 'Builder library') + .option('-b --builder ', 'Builder library') .option('-l --linkable', 'Prepare installation for link (contributor helper)') - .action((options) => + .action((options: CommandOptions) => initiate(options, pkg).catch((err) => { logger.error(err); process.exit(1); @@ -56,6 +58,7 @@ program .command('add ') .description('Add an addon to your Storybook') .option('-N --use-npm', 'Use NPM to build the Storybook server') + .option('--use-pnpm', 'Use PNPM to build the Storybook server') .option('-s --skip-postinstall', 'Skip package specific postinstall config modifications') .action((addonName, options) => add(addonName, options)); @@ -68,6 +71,7 @@ program .command('upgrade') .description('Upgrade your Storybook packages to the latest') .option('-N --use-npm', 'Use NPM to build the Storybook server') + .option('--use-pnpm', 'Use PNPM to build the Storybook server') .option('-y --yes', 'Skip prompting the user') .option('-n --dry-run', 'Only check for upgrades, do not install') .option('-p --prerelease', 'Upgrade to the pre-release packages') @@ -177,6 +181,8 @@ program .description('Check storybook for known problems or migrations and apply fixes') .option('-y --yes', 'Skip prompting the user') .option('-n --dry-run', 'Only check for fixes, do not actually run them') + .option('-N --use-npm', 'Use npm as package manager') + .option('--use-pnpm', 'Use pnpm as package manager') .action((fixId, options) => automigrate({ fixId, ...options }).catch((e) => { logger.error(e); diff --git a/code/lib/cli/src/generators/types.ts b/code/lib/cli/src/generators/types.ts index ecc5d209c3c4..4f8abe421b07 100644 --- a/code/lib/cli/src/generators/types.ts +++ b/code/lib/cli/src/generators/types.ts @@ -32,6 +32,7 @@ export type Generator = ( export type CommandOptions = { useNpm?: boolean; + usePnpm?: boolean; usePnp?: boolean; type?: ProjectType; force?: any; diff --git a/code/lib/cli/src/initiate.ts b/code/lib/cli/src/initiate.ts index 9015ff5fe528..006e4bb49678 100644 --- a/code/lib/cli/src/initiate.ts +++ b/code/lib/cli/src/initiate.ts @@ -251,7 +251,8 @@ const projectTypeInquirer = async ( }; export async function initiate(options: CommandOptions, pkg: Package): Promise { - const packageManager = JsPackageManagerFactory.getPackageManager(options.useNpm); + const { useNpm, usePnpm } = options; + const packageManager = JsPackageManagerFactory.getPackageManager({ useNpm, usePnpm }); const welcomeMessage = 'storybook init - the simplest way to add a Storybook to your project.'; logger.log(chalk.inverse(`\n ${welcomeMessage} \n`)); @@ -307,7 +308,7 @@ export async function initiate(options: CommandOptions, pkg: Package): Promise { describe('getPackageManager', () => { describe('return an NPM proxy', () => { it('when `useNpm` option is used', () => { - expect(JsPackageManagerFactory.getPackageManager(true)).toBeInstanceOf(NPMProxy); + expect(JsPackageManagerFactory.getPackageManager({ useNpm: true })).toBeInstanceOf( + NPMProxy + ); + }); + + it('when all package managers are ok, but only a `package-lock.json` file', () => { + spawnSyncMock.mockImplementation((command) => { + // Yarn is ok + if (command === 'yarn') { + return { + status: 0, + output: '1.22.4', + }; + } + // NPM is ok + if (command === 'npm') { + return { + status: 0, + output: '6.5.12', + }; + } + // PNPM is ok + if (command === 'pnpm') { + return { + status: 0, + output: '7.9.5', + }; + } + // Unknown package manager is ko + return { + status: 1, + }; + }); + + // There is only a package-lock.json + findUpSyncMock.mockImplementation((file) => + file === 'package-lock.json' ? 'found' : undefined + ); + + expect(JsPackageManagerFactory.getPackageManager()).toBeInstanceOf(NPMProxy); }); + }); - it('when NPM command is ok, Yarn is ok, there is no `yarn.lock` file', () => { + describe('return a PNPM proxy', () => { + it('when `usePnpm` option is used', () => { + expect(JsPackageManagerFactory.getPackageManager({ usePnpm: true })).toBeInstanceOf( + PNPMProxy + ); + }); + + it('when all package managers are ok, but only a `pnpm-lock.yaml` file', () => { spawnSyncMock.mockImplementation((command) => { - return command === 'yarn' - ? { - // Yarn is ok - status: 0, - output: '1.22.4', - } - : { - // NPM is ok - status: 0, - output: '6.5.12', - }; + // Yarn is ok + if (command === 'yarn') { + return { + status: 0, + output: '1.22.4', + }; + } + // NPM is ok + if (command === 'npm') { + return { + status: 0, + output: '6.5.12', + }; + } + // PNPM is ok + if (command === 'pnpm') { + return { + status: 0, + output: '7.9.5', + }; + } + // Unknown package manager is ko + return { + status: 1, + }; }); - // There is no yarn.lock - findUpSyncMock.mockImplementation((file) => (file === 'yarn.lock' ? undefined : '')); + // There is only a pnpm-lock.yaml + findUpSyncMock.mockImplementation((file) => { + if (file === 'pnpm-lock.yaml') { + return 'found'; + } + return undefined; + }); - expect(JsPackageManagerFactory.getPackageManager(false)).toBeInstanceOf(NPMProxy); + expect(JsPackageManagerFactory.getPackageManager()).toBeInstanceOf(PNPMProxy); }); }); describe('return a Yarn 1 proxy', () => { - it('when Yarn command is ok, Yarn version is <2, NPM is ko', () => { + it('when Yarn command is ok, Yarn version is <2, NPM is ko, PNPM is ko', () => { spawnSyncMock.mockImplementation((command) => { - return command === 'yarn' - ? { - // Yarn is ok - status: 0, - output: '1.22.4', - } - : { - // NPM is ko - status: 1, - }; + // Yarn is ok + if (command === 'yarn') { + return { + status: 0, + output: '1.22.4', + }; + } + // NPM is ko + if (command === 'npm') { + return { + status: 1, + }; + } + // PNPM is ko + if (command === 'pnpm') { + return { + status: 1, + }; + } + // Unknown package manager is ko + return { + status: 1, + }; }); - // there is no + // there is no lockfile findUpSyncMock.mockReturnValue(undefined); - expect(JsPackageManagerFactory.getPackageManager(false)).toBeInstanceOf(Yarn1Proxy); + expect(JsPackageManagerFactory.getPackageManager()).toBeInstanceOf(Yarn1Proxy); }); - it('when Yarn command is ok, Yarn version is <2, NPM is ok, there is a `yarn.lock` file', () => { + it('when Yarn command is ok, Yarn version is <2, NPM and PNPM are ok, there is a `yarn.lock` file', () => { spawnSyncMock.mockImplementation((command) => { - return command === 'yarn' - ? { - // Yarn is ok - status: 0, - output: '1.22.4', - } - : { - // NPM is ok - status: 0, - output: '6.5.12', - }; + // Yarn is ok + if (command === 'yarn') { + return { + status: 0, + output: '1.22.4', + }; + } + // NPM is ok + if (command === 'npm') { + return { + status: 0, + output: '6.5.12', + }; + } + // PNPM is ok + if (command === 'pnpm') { + return { + status: 0, + output: '7.9.5', + }; + } + // Unknown package manager is ko + return { + status: 1, + }; }); // There is a yarn.lock @@ -82,41 +176,68 @@ describe('JsPackageManagerFactory', () => { file === 'yarn.lock' ? '/Users/johndoe/Documents/yarn.lock' : undefined ); - expect(JsPackageManagerFactory.getPackageManager(false)).toBeInstanceOf(Yarn1Proxy); + expect(JsPackageManagerFactory.getPackageManager()).toBeInstanceOf(Yarn1Proxy); }); }); describe('return a Yarn 2 proxy', () => { - it('when Yarn command is ok, Yarn version is >=2, NPM is ko', () => { + it('when Yarn command is ok, Yarn version is >=2, NPM is ko, PNPM is ko', () => { spawnSyncMock.mockImplementation((command) => { - return command === 'yarn' - ? { - // Yarn is ok - status: 0, - output: '2.0.0-rc.33', - } - : { - // NPM is ko - status: 1, - }; + // Yarn is ok + if (command === 'yarn') { + return { + status: 0, + output: '2.0.0-rc.33', + }; + } + // NPM is ko + if (command === 'npm') { + return { + status: 1, + }; + } + // PNPM is ko + if (command === 'pnpm') { + return { + status: 1, + }; + } + // Unknown package manager is ko + return { + status: 1, + }; }); - expect(JsPackageManagerFactory.getPackageManager(false)).toBeInstanceOf(Yarn2Proxy); + expect(JsPackageManagerFactory.getPackageManager()).toBeInstanceOf(Yarn2Proxy); }); - it('when Yarn command is ok, Yarn version is >=2, NPM is ok, there is a `yarn.lock` file', () => { + it('when Yarn command is ok, Yarn version is >=2, NPM and PNPM are ok, there is a `yarn.lock` file', () => { spawnSyncMock.mockImplementation((command) => { - return command === 'yarn' - ? { - // Yarn is ok - status: 0, - output: '2.0.0-rc.33', - } - : { - // NPM is ok - status: 0, - output: '6.5.12', - }; + // Yarn is ok + if (command === 'yarn') { + return { + status: 0, + output: '2.0.0-rc.33', + }; + } + // NPM is ok + if (command === 'npm') { + return { + status: 0, + output: '6.5.12', + }; + } + // PNPM is ok + if (command === 'pnpm') { + return { + status: 0, + output: '7.9.5', + }; + } + // Unknown package manager is ko + return { + status: 1, + }; }); // There is a yarn.lock @@ -124,13 +245,13 @@ describe('JsPackageManagerFactory', () => { file === 'yarn.lock' ? '/Users/johndoe/Documents/yarn.lock' : undefined ); - expect(JsPackageManagerFactory.getPackageManager(false)).toBeInstanceOf(Yarn2Proxy); + expect(JsPackageManagerFactory.getPackageManager()).toBeInstanceOf(Yarn2Proxy); }); }); - it('throws an error if Yarn is ko and NPM is ko', () => { + it('throws an error if Yarn, NPM, and PNPM are not found', () => { spawnSyncMock.mockReturnValue({ status: 1 }); - expect(() => JsPackageManagerFactory.getPackageManager(false)).toThrow(); + expect(() => JsPackageManagerFactory.getPackageManager()).toThrow(); }); }); }); diff --git a/code/lib/cli/src/js-package-manager/JsPackageManagerFactory.ts b/code/lib/cli/src/js-package-manager/JsPackageManagerFactory.ts index df1ad452ec1b..473f251fb8c9 100644 --- a/code/lib/cli/src/js-package-manager/JsPackageManagerFactory.ts +++ b/code/lib/cli/src/js-package-manager/JsPackageManagerFactory.ts @@ -1,30 +1,43 @@ import { sync as spawnSync } from 'cross-spawn'; import { sync as findUpSync } from 'find-up'; import { NPMProxy } from './NPMProxy'; +import { PNPMProxy } from './PNPMProxy'; import { JsPackageManager } from './JsPackageManager'; import { Yarn2Proxy } from './Yarn2Proxy'; import { Yarn1Proxy } from './Yarn1Proxy'; export class JsPackageManagerFactory { - public static getPackageManager(forceNpmUsage = false, cwd?: string): JsPackageManager { - if (forceNpmUsage) { + public static getPackageManager( + { usePnpm, useNpm }: { usePnpm?: boolean; useNpm?: boolean } = {}, + cwd?: string + ): JsPackageManager { + if (useNpm) { return new NPMProxy({ cwd }); } + if (usePnpm) { + return new PNPMProxy({ cwd }); + } const yarnVersion = getYarnVersion(cwd); - const hasYarnLockFile = findUpSync('yarn.lock', { cwd }); + const hasYarnLockFile = Boolean(findUpSync('yarn.lock', { cwd })); + const hasPNPMLockFile = Boolean(findUpSync('pnpm-lock.yaml', { cwd })); const hasNPMCommand = hasNPM(cwd); + const hasPNPMCommand = hasPNPM(cwd); - if (yarnVersion && (hasYarnLockFile || !hasNPMCommand)) { + if (yarnVersion && (hasYarnLockFile || (!hasNPMCommand && !hasPNPMCommand))) { return yarnVersion === 1 ? new Yarn1Proxy({ cwd }) : new Yarn2Proxy({ cwd }); } + if (hasPNPMCommand && hasPNPMLockFile) { + return new PNPMProxy({ cwd }); + } + if (hasNPMCommand) { return new NPMProxy({ cwd }); } - throw new Error('Unable to find a usable package manager within NPM, Yarn and Yarn 2'); + throw new Error('Unable to find a usable package manager within NPM, PNPM, Yarn and Yarn 2'); } } @@ -33,6 +46,11 @@ function hasNPM(cwd?: string) { return npmVersionCommand.status === 0; } +function hasPNPM(cwd?: string) { + const pnpmVersionCommand = spawnSync('pnpm', ['--version'], { cwd, shell: true }); + return pnpmVersionCommand.status === 0; +} + function getYarnVersion(cwd?: string): 1 | 2 | undefined { const yarnVersionCommand = spawnSync('yarn', ['--version'], { cwd, shell: true }); diff --git a/code/lib/cli/src/js-package-manager/PNPMProxy.test.ts b/code/lib/cli/src/js-package-manager/PNPMProxy.test.ts new file mode 100644 index 000000000000..17ebaffad8b2 --- /dev/null +++ b/code/lib/cli/src/js-package-manager/PNPMProxy.test.ts @@ -0,0 +1,204 @@ +import { PNPMProxy } from './PNPMProxy'; + +describe('NPM Proxy', () => { + let pnpmProxy: PNPMProxy; + + beforeEach(() => { + pnpmProxy = new PNPMProxy(); + }); + + it('type should be npm', () => { + expect(pnpmProxy.type).toEqual('pnpm'); + }); + + describe('initPackageJson', () => { + it('should run `npm init -y`', () => { + const executeCommandSpy = jest.spyOn(pnpmProxy, 'executeCommand').mockReturnValue(''); + + pnpmProxy.initPackageJson(); + + expect(executeCommandSpy).toHaveBeenCalledWith('pnpm', ['init', '-y']); + }); + }); + + describe('setRegistryUrl', () => { + it('should run `npm config set registry https://foo.bar`', () => { + const executeCommandSpy = jest.spyOn(pnpmProxy, 'executeCommand').mockReturnValue(''); + + pnpmProxy.setRegistryURL('https://foo.bar'); + + expect(executeCommandSpy).toHaveBeenCalledWith('npm', [ + 'config', + 'set', + 'registry', + 'https://foo.bar', + ]); + }); + }); + + describe('installDependencies', () => { + it('should run `pnpm install`', () => { + const executeCommandSpy = jest.spyOn(pnpmProxy, 'executeCommand').mockReturnValue('7.1.0'); + + pnpmProxy.installDependencies(); + + expect(executeCommandSpy).toHaveBeenLastCalledWith('pnpm', ['install'], expect.any(String)); + }); + }); + + describe('addDependencies', () => { + it('with devDep it should run `pnpm add -D @storybook/addons`', () => { + const executeCommandSpy = jest.spyOn(pnpmProxy, 'executeCommand').mockReturnValue('6.0.0'); + + pnpmProxy.addDependencies({ installAsDevDependencies: true }, ['@storybook/addons']); + + expect(executeCommandSpy).toHaveBeenLastCalledWith( + 'pnpm', + ['add', '-D', '@storybook/addons'], + expect.any(String) + ); + }); + }); + + describe('removeDependencies', () => { + it('with devDep it should run `npm uninstall @storybook/addons`', () => { + const executeCommandSpy = jest.spyOn(pnpmProxy, 'executeCommand').mockReturnValue('6.0.0'); + + pnpmProxy.removeDependencies({}, ['@storybook/addons']); + + expect(executeCommandSpy).toHaveBeenLastCalledWith( + 'pnpm', + ['remove', '@storybook/addons'], + expect.any(String) + ); + }); + + describe('skipInstall', () => { + it('should only change package.json without running install', () => { + const executeCommandSpy = jest.spyOn(pnpmProxy, 'executeCommand').mockReturnValue('7.0.0'); + const writePackageSpy = jest + .spyOn(pnpmProxy, 'writePackageJson') + .mockImplementation(jest.fn); + + pnpmProxy.removeDependencies( + { + skipInstall: true, + packageJson: { + devDependencies: { + '@storybook/manager-webpack5': 'x.x.x', + '@storybook/react': 'x.x.x', + }, + }, + }, + ['@storybook/manager-webpack5'] + ); + + expect(writePackageSpy).toHaveBeenCalledWith({ + devDependencies: { + '@storybook/react': 'x.x.x', + }, + }); + expect(executeCommandSpy).not.toHaveBeenCalled(); + }); + }); + }); + + describe('latestVersion', () => { + it('without constraint it returns the latest version', async () => { + const executeCommandSpy = jest.spyOn(pnpmProxy, 'executeCommand').mockReturnValue('"5.3.19"'); + + const version = await pnpmProxy.latestVersion('@storybook/addons'); + + expect(executeCommandSpy).toHaveBeenCalledWith('pnpm', [ + 'info', + '@storybook/addons', + 'version', + '--json', + ]); + expect(version).toEqual('5.3.19'); + }); + + it('with constraint it returns the latest version satisfying the constraint', async () => { + const executeCommandSpy = jest + .spyOn(pnpmProxy, 'executeCommand') + .mockReturnValue('["4.25.3","5.3.19","6.0.0-beta.23"]'); + + const version = await pnpmProxy.latestVersion('@storybook/addons', '5.X'); + + expect(executeCommandSpy).toHaveBeenCalledWith('pnpm', [ + 'info', + '@storybook/addons', + 'versions', + '--json', + ]); + expect(version).toEqual('5.3.19'); + }); + + it('throws an error if command output is not a valid JSON', async () => { + jest.spyOn(pnpmProxy, 'executeCommand').mockReturnValue('NOT A JSON'); + + await expect(pnpmProxy.latestVersion('@storybook/addons')).rejects.toThrow(); + }); + }); + + describe('getVersion', () => { + it('with a Storybook package listed in versions.json it returns the version', async () => { + // eslint-disable-next-line global-require + const storybookAngularVersion = require('../versions').default['@storybook/angular']; + const executeCommandSpy = jest.spyOn(pnpmProxy, 'executeCommand').mockReturnValue('"5.3.19"'); + + const version = await pnpmProxy.getVersion('@storybook/angular'); + + expect(executeCommandSpy).toHaveBeenCalledWith('pnpm', [ + 'info', + '@storybook/angular', + 'version', + '--json', + ]); + expect(version).toEqual(`^${storybookAngularVersion}`); + }); + + it('with a Storybook package not listed in versions.json it returns the latest version', async () => { + const packageVersion = '5.3.19'; + const executeCommandSpy = jest + .spyOn(pnpmProxy, 'executeCommand') + .mockReturnValue(`"${packageVersion}"`); + + const version = await pnpmProxy.getVersion('@storybook/react-native'); + + expect(executeCommandSpy).toHaveBeenCalledWith('pnpm', [ + 'info', + '@storybook/react-native', + 'version', + '--json', + ]); + expect(version).toEqual(`^${packageVersion}`); + }); + }); + + describe('addPackageResolutions', () => { + it('adds resolutions to package.json and account for existing resolutions', () => { + const writePackageSpy = jest.spyOn(pnpmProxy, 'writePackageJson').mockImplementation(jest.fn); + + jest.spyOn(pnpmProxy, 'retrievePackageJson').mockImplementation( + jest.fn(() => ({ + overrides: { + bar: 'x.x.x', + }, + })) + ); + + const versions = { + foo: 'x.x.x', + }; + pnpmProxy.addPackageResolutions(versions); + + expect(writePackageSpy).toHaveBeenCalledWith({ + overrides: { + ...versions, + bar: 'x.x.x', + }, + }); + }); + }); +}); diff --git a/code/lib/cli/src/js-package-manager/PNPMProxy.ts b/code/lib/cli/src/js-package-manager/PNPMProxy.ts new file mode 100644 index 000000000000..cd305b16e673 --- /dev/null +++ b/code/lib/cli/src/js-package-manager/PNPMProxy.ts @@ -0,0 +1,77 @@ +import { JsPackageManager } from './JsPackageManager'; +import type { PackageJson } from './PackageJson'; + +export class PNPMProxy extends JsPackageManager { + readonly type = 'pnpm'; + + installArgs: string[] | undefined; + + uninstallArgs: string[] | undefined; + + initPackageJson() { + return this.executeCommand('pnpm', ['init', '-y']); + } + + getRunStorybookCommand(): string { + return 'pnpm run storybook'; + } + + getRunCommand(command: string): string { + return `pnpm run ${command}`; + } + + getPnpmVersion(): string { + return this.executeCommand('pnpm', ['--version']); + } + + protected getResolutions(packageJson: PackageJson, versions: Record) { + return { + overrides: { + ...packageJson.overrides, + ...versions, + }, + }; + } + + protected runInstall(): void { + this.executeCommand('pnpm', ['install'], 'inherit'); + } + + protected runAddDeps(dependencies: string[], installAsDevDependencies: boolean): void { + let args = [...dependencies]; + + if (installAsDevDependencies) { + args = ['-D', ...args]; + } + + this.executeCommand('pnpm', ['add', ...args], 'inherit'); + } + + protected runRemoveDeps(dependencies: string[]): void { + const args = [...dependencies]; + + this.executeCommand('pnpm', ['remove', ...args], 'inherit'); + } + + protected runGetVersions( + packageName: string, + fetchAllVersions: T + ): Promise { + const args = [fetchAllVersions ? 'versions' : 'version', '--json']; + + const commandResult = this.executeCommand('pnpm', ['info', packageName, ...args]); + + try { + const parsedOutput = JSON.parse(commandResult); + + if (parsedOutput.error) { + // FIXME: improve error handling + throw new Error(parsedOutput.error.summary); + } else { + return parsedOutput; + } + } catch (e) { + throw new Error(`Unable to find versions of ${packageName} using pnpm`); + } + } +} diff --git a/code/lib/cli/src/js-package-manager/Yarn2Proxy.ts b/code/lib/cli/src/js-package-manager/Yarn2Proxy.ts index 63736283424f..63c1bf07c87a 100644 --- a/code/lib/cli/src/js-package-manager/Yarn2Proxy.ts +++ b/code/lib/cli/src/js-package-manager/Yarn2Proxy.ts @@ -1,6 +1,7 @@ import { JsPackageManager } from './JsPackageManager'; import type { PackageJson } from './PackageJson'; +// This encompasses both yarn 2 and yarn 3 export class Yarn2Proxy extends JsPackageManager { readonly type = 'yarn2'; diff --git a/code/lib/cli/src/upgrade.ts b/code/lib/cli/src/upgrade.ts index e0e3c6d14b8d..3f25f99fcf1c 100644 --- a/code/lib/cli/src/upgrade.ts +++ b/code/lib/cli/src/upgrade.ts @@ -141,6 +141,7 @@ interface UpgradeOptions { prerelease: boolean; skipCheck: boolean; useNpm: boolean; + usePnpm: boolean; dryRun: boolean; yes: boolean; disableTelemetry: boolean; @@ -150,11 +151,12 @@ export const upgrade = async ({ prerelease, skipCheck, useNpm, + usePnpm, dryRun, yes, ...options }: UpgradeOptions) => { - const packageManager = JsPackageManagerFactory.getPackageManager(useNpm); + const packageManager = JsPackageManagerFactory.getPackageManager({ useNpm, usePnpm }); commandLog(`Checking for latest versions of '@storybook/*' packages`); if (!options.disableTelemetry) { @@ -179,6 +181,6 @@ export const upgrade = async ({ if (!skipCheck) { checkVersionConsistency(); - await automigrate({ dryRun, yes }); + await automigrate({ dryRun, yes, useNpm, usePnpm }); } }; diff --git a/scripts/next-repro-generators/generate-repros.ts b/scripts/next-repro-generators/generate-repros.ts index fe386ae64dda..58dcf2be79f9 100755 --- a/scripts/next-repro-generators/generate-repros.ts +++ b/scripts/next-repro-generators/generate-repros.ts @@ -54,7 +54,7 @@ const addStorybook = async (baseDir: string, localRegistry: boolean) => { await copy(beforeDir, tmpDir); - const packageManager = JsPackageManagerFactory.getPackageManager(false, tmpDir); + const packageManager = JsPackageManagerFactory.getPackageManager({}, tmpDir); if (localRegistry) { await withLocalRegistry(packageManager, async () => { packageManager.addPackageResolutions(storybookVersions); diff --git a/scripts/tasks/sandbox-parts.ts b/scripts/tasks/sandbox-parts.ts index 58ce0f7d1f27..a93a6c17ff82 100644 --- a/scripts/tasks/sandbox-parts.ts +++ b/scripts/tasks/sandbox-parts.ts @@ -292,7 +292,7 @@ function addExtraDependencies({ const extraDeps = ['@storybook/jest', '@storybook/testing-library@0.0.14-next.0']; if (debug) logger.log('🎁 Adding extra deps', extraDeps); if (!dryRun) { - const packageManager = JsPackageManagerFactory.getPackageManager(false, cwd); + const packageManager = JsPackageManagerFactory.getPackageManager({}, cwd); packageManager.addDependencies({ installAsDevDependencies: true }, extraDeps); } } From abb264aa3f6a7e87184338c04303afdf2bdbfef7 Mon Sep 17 00:00:00 2001 From: Ian VanSchooten Date: Mon, 17 Oct 2022 09:34:07 -0400 Subject: [PATCH 2/3] Deprecate `--use-npm`, add `--package-manager` --- MIGRATION.md | 5 ++++ code/lib/cli/README.md | 20 +++++++++++-- code/lib/cli/package.json | 4 ++- code/lib/cli/src/add.ts | 15 +++++++--- code/lib/cli/src/automigrate/index.ts | 8 ++--- code/lib/cli/src/generate.ts | 30 +++++++++++-------- code/lib/cli/src/generators/types.ts | 4 +-- code/lib/cli/src/initiate.ts | 11 ++++--- .../js-package-manager/JsPackageManager.ts | 4 ++- .../JsPackageManagerFactory.test.ts | 22 ++++++++++++-- .../JsPackageManagerFactory.ts | 14 ++++++--- .../src/js-package-manager/deprecations.ts | 8 +++++ code/lib/cli/src/js-package-manager/index.ts | 1 + code/lib/cli/src/upgrade.ts | 15 ++++++---- code/yarn.lock | 2 ++ .../installation-problems/angular.mdx | 6 ++-- .../installation-problems/ember.mdx | 8 ++--- .../installation-problems/preact.mdx | 8 ++--- .../installation-problems/react.mdx | 6 ++-- .../installation-problems/svelte.mdx | 8 ++--- .../get-started/installation-problems/vue.mdx | 6 ++-- 21 files changed, 142 insertions(+), 63 deletions(-) create mode 100644 code/lib/cli/src/js-package-manager/deprecations.ts diff --git a/MIGRATION.md b/MIGRATION.md index 0b0475d293fe..32e98c598b26 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -18,6 +18,7 @@ - [Docs modern inline rendering by default](#docs-modern-inline-rendering-by-default) - [Babel mode v7 by default](#babel-mode-v7-by-default) - [7.0 feature flags removed](#70-feature-flags-removed) + - [CLI option `--use-npm` deprecated](#cli-option---use-npm-deprecated) - [Vite builder uses vite config automatically](#vite-builder-uses-vite-config-automatically) - [Vite cache moved to node_modules/.cache/.vite-storybook](#vite-cache-moved-to-node_modulescachevite-storybook) - [Removed docs.getContainer and getPage parameters](#removed-docsgetcontainer-and-getpage-parameters) @@ -522,6 +523,10 @@ In 7.0 we've removed the following feature flags: | `emotionAlias` | This flag is no longer needed and should be deleted. | | `breakingChangesV7` | This flag is no longer needed and should be deleted. | +#### CLI option `--use-npm` deprecated + +With increased support for more package managers (pnpm), we have introduced the `--package-manager` CLI option. Please use `--package-manager=npm` to force NPM to be used to install dependencies when running Storybook CLI commands. Other valid options are `pnpm`, `yarn1`, and `yarn2` (`yarn2` is for versions 2 and higher). + #### Vite builder uses vite config automatically When using a [Vite-based framework](#framework-field-mandatory), Storybook will automatically use your `vite.config.(ctm)js` config file starting in 7.0. diff --git a/code/lib/cli/README.md b/code/lib/cli/README.md index fd5d25472c48..0152be4e6aef 100644 --- a/code/lib/cli/README.md +++ b/code/lib/cli/README.md @@ -23,12 +23,26 @@ See the command-line help with `-h` for details. ## [Yarn](https://github.com/yarnpkg/yarn) support -The CLI supports yarn. If you have installed yarn in your system and your project has `yarn.lock` file, it'll detect it and use `yarn` instead of `npm`. +The CLI supports yarn. If you have installed yarn in your system and your project has a `yarn.lock` file, it'll detect it and use `yarn` to install dependencies. -If you don't want to use `yarn` always you can use the `--use-npm` option like this: +If you don't want to use `yarn` always you can use the `--package-manager` option like this: ```sh -npx sb init --use-npm +npx sb init --package-manager=npm +``` + +If you would like to force a particular version of yarn, you can use the `--package-manager` flag with a value of `yarn1` or `yarn2`. + +--- + +## [PNPM](https://pnpm.io/) support + +The CLI supports pnpm. If you have installed pnpm in your system and your project has a `pnpm-lock.yaml` file, it'll detect it and use `pnpm` to install dependencies. + +If you don't have a lock file and would like to force pnpm to be used, you can use the `--package-manager` option like this: + +```sh +npx sb init --package-manager=pnpm ``` --- diff --git a/code/lib/cli/package.json b/code/lib/cli/package.json index 1984c5b7402a..c3c52a67c28c 100644 --- a/code/lib/cli/package.json +++ b/code/lib/cli/package.json @@ -71,7 +71,8 @@ "shelljs": "^0.8.5", "strip-json-comments": "^3.0.1", "ts-dedent": "^2.0.0", - "update-notifier": "^5.0.1" + "update-notifier": "^5.0.1", + "util-deprecate": "^1.0.2" }, "devDependencies": { "@storybook/client-api": "7.0.0-alpha.38", @@ -82,6 +83,7 @@ "@types/semver": "^7.3.4", "@types/shelljs": "^0.8.7", "@types/update-notifier": "^5.0.0", + "@types/util-deprecate": "^1.0.0", "strip-json-comments": "^3.1.1", "typescript": "~4.6.3", "update-notifier": "^5.0.1" diff --git a/code/lib/cli/src/add.ts b/code/lib/cli/src/add.ts index bd7b88246996..669ae857f90d 100644 --- a/code/lib/cli/src/add.ts +++ b/code/lib/cli/src/add.ts @@ -6,7 +6,11 @@ import { getStorybookInfo } from '@storybook/core-common'; import { readConfig, writeConfig } from '@storybook/csf-tools'; import { commandLog } from './helpers'; -import { JsPackageManagerFactory } from './js-package-manager'; +import { + JsPackageManagerFactory, + useNpmWarning, + type PackageManagerName, +} from './js-package-manager'; const logger = console; @@ -68,10 +72,13 @@ const getVersionSpecifier = (addon: string) => { */ export async function add( addon: string, - options: { useNpm: boolean; usePnpm: boolean; skipPostinstall: boolean } + options: { useNpm: boolean; packageManager: PackageManagerName; skipPostinstall: boolean } ) { - const { useNpm, usePnpm } = options; - const packageManager = JsPackageManagerFactory.getPackageManager({ useNpm, usePnpm }); + const { useNpm, packageManager: pkgMgr } = options; + if (useNpm) { + useNpmWarning(); + } + const packageManager = JsPackageManagerFactory.getPackageManager({ useNpm, force: pkgMgr }); const packageJson = packageManager.retrievePackageJson(); const [addonName, versionSpecifier] = getVersionSpecifier(addon); diff --git a/code/lib/cli/src/automigrate/index.ts b/code/lib/cli/src/automigrate/index.ts index 04f49483a6c6..23fe787cfe1e 100644 --- a/code/lib/cli/src/automigrate/index.ts +++ b/code/lib/cli/src/automigrate/index.ts @@ -2,7 +2,7 @@ import prompts from 'prompts'; import chalk from 'chalk'; import boxen from 'boxen'; -import { JsPackageManagerFactory } from '../js-package-manager'; +import { JsPackageManagerFactory, type PackageManagerName } from '../js-package-manager'; import { fixes, Fix } from './fixes'; @@ -13,11 +13,11 @@ interface FixOptions { yes?: boolean; dryRun?: boolean; useNpm?: boolean; - usePnpm?: boolean; + force?: PackageManagerName; } -export const automigrate = async ({ fixId, dryRun, yes, useNpm, usePnpm }: FixOptions = {}) => { - const packageManager = JsPackageManagerFactory.getPackageManager({ useNpm, usePnpm }); +export const automigrate = async ({ fixId, dryRun, yes, useNpm, force }: FixOptions = {}) => { + const packageManager = JsPackageManagerFactory.getPackageManager({ useNpm, force }); const filtered = fixId ? fixes.filter((f) => f.id === fixId) : fixes; logger.info('🔎 checking possible migrations..'); diff --git a/code/lib/cli/src/generate.ts b/code/lib/cli/src/generate.ts index 0234791a9c4a..921cc8574d98 100644 --- a/code/lib/cli/src/generate.ts +++ b/code/lib/cli/src/generate.ts @@ -12,7 +12,7 @@ import { initiate } from './initiate'; import { add } from './add'; import { migrate } from './migrate'; import { extract } from './extract'; -import { upgrade } from './upgrade'; +import { upgrade, type UpgradeOptions } from './upgrade'; import { repro } from './repro'; import { reproNext } from './repro-next'; import { link } from './link'; @@ -39,9 +39,9 @@ program .description('Initialize Storybook into your project.') .option('-f --force', 'Force add Storybook') .option('-s --skip-install', 'Skip installing deps') - .option('-N --use-npm', 'Use npm to install deps') - .option('--use-pnpm', 'Use pnpm to install deps') - .option('--use-pnp', 'Enable pnp mode') + .option('--package-manager ', 'Force package manager for installing deps') + .option('-N --use-npm', 'Use npm to install deps (deprecated)') + .option('--use-pnp', 'Enable pnp mode for Yarn 2+') .option('-p --parser ', 'jscodeshift parser') .option('-t --type ', 'Add Storybook for a specific project type') .option('-y --yes', 'Answer yes to all prompts') @@ -57,10 +57,13 @@ program program .command('add ') .description('Add an addon to your Storybook') - .option('-N --use-npm', 'Use NPM to build the Storybook server') - .option('--use-pnpm', 'Use PNPM to build the Storybook server') + .option( + '--package-manager ', + 'Force package manager for installing dependencies' + ) + .option('-N --use-npm', 'Use NPM to install dependencies (deprecated)') .option('-s --skip-postinstall', 'Skip package specific postinstall config modifications') - .action((addonName, options) => add(addonName, options)); + .action((addonName: string, options: any) => add(addonName, options)); program .command('babelrc') @@ -70,13 +73,16 @@ program program .command('upgrade') .description('Upgrade your Storybook packages to the latest') - .option('-N --use-npm', 'Use NPM to build the Storybook server') - .option('--use-pnpm', 'Use PNPM to build the Storybook server') + .option( + '--package-manager ', + 'Force package manager for installing dependencies' + ) + .option('-N --use-npm', 'Use NPM to install dependencies (deprecated)') .option('-y --yes', 'Skip prompting the user') .option('-n --dry-run', 'Only check for upgrades, do not install') .option('-p --prerelease', 'Upgrade to the pre-release packages') .option('-s --skip-check', 'Skip postinstall version and automigration checks') - .action((options) => upgrade(options)); + .action((options: UpgradeOptions) => upgrade(options)); program .command('info') @@ -181,8 +187,8 @@ program .description('Check storybook for known problems or migrations and apply fixes') .option('-y --yes', 'Skip prompting the user') .option('-n --dry-run', 'Only check for fixes, do not actually run them') - .option('-N --use-npm', 'Use npm as package manager') - .option('--use-pnpm', 'Use pnpm as package manager') + .option('--package-manager ', 'Force package manager') + .option('-N --use-npm', 'Use npm as package manager (deprecated)') .action((fixId, options) => automigrate({ fixId, ...options }).catch((e) => { logger.error(e); diff --git a/code/lib/cli/src/generators/types.ts b/code/lib/cli/src/generators/types.ts index 4f8abe421b07..d96729c0ceba 100644 --- a/code/lib/cli/src/generators/types.ts +++ b/code/lib/cli/src/generators/types.ts @@ -1,6 +1,6 @@ import { NpmOptions } from '../NpmOptions'; import { SupportedLanguage, Builder, ProjectType } from '../project_types'; -import { JsPackageManager } from '../js-package-manager/JsPackageManager'; +import { JsPackageManager, type PackageManagerName } from '../js-package-manager/JsPackageManager'; export type GeneratorOptions = { language: SupportedLanguage; @@ -31,8 +31,8 @@ export type Generator = ( ) => Promise; export type CommandOptions = { + packageManager: PackageManagerName; useNpm?: boolean; - usePnpm?: boolean; usePnp?: boolean; type?: ProjectType; force?: any; diff --git a/code/lib/cli/src/initiate.ts b/code/lib/cli/src/initiate.ts index 006e4bb49678..cf6fb76ae0a9 100644 --- a/code/lib/cli/src/initiate.ts +++ b/code/lib/cli/src/initiate.ts @@ -25,7 +25,7 @@ import preactGenerator from './generators/PREACT'; import svelteGenerator from './generators/SVELTE'; import raxGenerator from './generators/RAX'; import serverGenerator from './generators/SERVER'; -import { JsPackageManagerFactory, JsPackageManager } from './js-package-manager'; +import { JsPackageManagerFactory, JsPackageManager, useNpmWarning } from './js-package-manager'; import { NpmOptions } from './NpmOptions'; import { automigrate } from './automigrate'; import { CommandOptions } from './generators/types'; @@ -251,8 +251,11 @@ const projectTypeInquirer = async ( }; export async function initiate(options: CommandOptions, pkg: Package): Promise { - const { useNpm, usePnpm } = options; - const packageManager = JsPackageManagerFactory.getPackageManager({ useNpm, usePnpm }); + const { useNpm, packageManager: pkgMgr } = options; + if (useNpm) { + useNpmWarning(); + } + const packageManager = JsPackageManagerFactory.getPackageManager({ useNpm, force: pkgMgr }); const welcomeMessage = 'storybook init - the simplest way to add a Storybook to your project.'; logger.log(chalk.inverse(`\n ${welcomeMessage} \n`)); @@ -308,7 +311,7 @@ export async function initiate(options: CommandOptions, pkg: Package): Promise { ); }); + it('when `force` option is `npm`', () => { + expect(JsPackageManagerFactory.getPackageManager({ force: 'npm' })).toBeInstanceOf( + NPMProxy + ); + }); + it('when all package managers are ok, but only a `package-lock.json` file', () => { spawnSyncMock.mockImplementation((command) => { // Yarn is ok @@ -61,8 +67,8 @@ describe('JsPackageManagerFactory', () => { }); describe('return a PNPM proxy', () => { - it('when `usePnpm` option is used', () => { - expect(JsPackageManagerFactory.getPackageManager({ usePnpm: true })).toBeInstanceOf( + it('when `force` option is `pnpm`', () => { + expect(JsPackageManagerFactory.getPackageManager({ force: 'pnpm' })).toBeInstanceOf( PNPMProxy ); }); @@ -109,6 +115,12 @@ describe('JsPackageManagerFactory', () => { }); describe('return a Yarn 1 proxy', () => { + it('when `force` option is `yarn1`', () => { + expect(JsPackageManagerFactory.getPackageManager({ force: 'yarn1' })).toBeInstanceOf( + Yarn1Proxy + ); + }); + it('when Yarn command is ok, Yarn version is <2, NPM is ko, PNPM is ko', () => { spawnSyncMock.mockImplementation((command) => { // Yarn is ok @@ -181,6 +193,12 @@ describe('JsPackageManagerFactory', () => { }); describe('return a Yarn 2 proxy', () => { + it('when `force` option is `yarn2`', () => { + expect(JsPackageManagerFactory.getPackageManager({ force: 'yarn2' })).toBeInstanceOf( + Yarn2Proxy + ); + }); + it('when Yarn command is ok, Yarn version is >=2, NPM is ko, PNPM is ko', () => { spawnSyncMock.mockImplementation((command) => { // Yarn is ok diff --git a/code/lib/cli/src/js-package-manager/JsPackageManagerFactory.ts b/code/lib/cli/src/js-package-manager/JsPackageManagerFactory.ts index 473f251fb8c9..379e1cc24540 100644 --- a/code/lib/cli/src/js-package-manager/JsPackageManagerFactory.ts +++ b/code/lib/cli/src/js-package-manager/JsPackageManagerFactory.ts @@ -2,21 +2,27 @@ import { sync as spawnSync } from 'cross-spawn'; import { sync as findUpSync } from 'find-up'; import { NPMProxy } from './NPMProxy'; import { PNPMProxy } from './PNPMProxy'; -import { JsPackageManager } from './JsPackageManager'; +import { JsPackageManager, type PackageManagerName } from './JsPackageManager'; import { Yarn2Proxy } from './Yarn2Proxy'; import { Yarn1Proxy } from './Yarn1Proxy'; export class JsPackageManagerFactory { public static getPackageManager( - { usePnpm, useNpm }: { usePnpm?: boolean; useNpm?: boolean } = {}, + { force, useNpm }: { force?: PackageManagerName; useNpm?: boolean } = {}, cwd?: string ): JsPackageManager { - if (useNpm) { + if (useNpm || force === 'npm') { return new NPMProxy({ cwd }); } - if (usePnpm) { + if (force === 'pnpm') { return new PNPMProxy({ cwd }); } + if (force === 'yarn1') { + return new Yarn1Proxy({ cwd }); + } + if (force === 'yarn2') { + return new Yarn2Proxy({ cwd }); + } const yarnVersion = getYarnVersion(cwd); const hasYarnLockFile = Boolean(findUpSync('yarn.lock', { cwd })); diff --git a/code/lib/cli/src/js-package-manager/deprecations.ts b/code/lib/cli/src/js-package-manager/deprecations.ts new file mode 100644 index 000000000000..5883fad3a294 --- /dev/null +++ b/code/lib/cli/src/js-package-manager/deprecations.ts @@ -0,0 +1,8 @@ +import deprecate from 'util-deprecate'; + +export const useNpmWarning = deprecate( + () => {}, + `\`--use-npm\` is deprecated and will be removed in Storybook 8.0. +Please use the \`--package-manager=npm\` option instead. +Read more at https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#cli-option---use-npm-deprecated` +); diff --git a/code/lib/cli/src/js-package-manager/index.ts b/code/lib/cli/src/js-package-manager/index.ts index 3a2b877d5030..2e29cb8e15f4 100644 --- a/code/lib/cli/src/js-package-manager/index.ts +++ b/code/lib/cli/src/js-package-manager/index.ts @@ -1,3 +1,4 @@ +export * from './deprecations'; export * from './JsPackageManagerFactory'; export * from './JsPackageManager'; export * from './PackageJson'; diff --git a/code/lib/cli/src/upgrade.ts b/code/lib/cli/src/upgrade.ts index 3ab806a6d670..e9dc68079901 100644 --- a/code/lib/cli/src/upgrade.ts +++ b/code/lib/cli/src/upgrade.ts @@ -6,6 +6,8 @@ import { getPackageDetails, JsPackageManagerFactory, PackageJsonWithMaybeDeps, + PackageManagerName, + useNpmWarning, } from './js-package-manager'; import { commandLog } from './helpers'; import { automigrate } from './automigrate'; @@ -136,11 +138,11 @@ export const addExtraFlags = ( ); }; -interface UpgradeOptions { +export interface UpgradeOptions { prerelease: boolean; skipCheck: boolean; useNpm: boolean; - usePnpm: boolean; + packageManager: PackageManagerName; dryRun: boolean; yes: boolean; disableTelemetry: boolean; @@ -150,12 +152,15 @@ export const upgrade = async ({ prerelease, skipCheck, useNpm, - usePnpm, + packageManager: pkgMgr, dryRun, yes, ...options }: UpgradeOptions) => { - const packageManager = JsPackageManagerFactory.getPackageManager({ useNpm, usePnpm }); + if (useNpm) { + useNpmWarning(); + } + const packageManager = JsPackageManagerFactory.getPackageManager({ useNpm, force: pkgMgr }); commandLog(`Checking for latest versions of '@storybook/*' packages`); if (!options.disableTelemetry) { @@ -180,6 +185,6 @@ export const upgrade = async ({ if (!skipCheck) { checkVersionConsistency(); - await automigrate({ dryRun, yes, useNpm, usePnpm }); + await automigrate({ dryRun, yes, useNpm, force: pkgMgr }); } }; diff --git a/code/yarn.lock b/code/yarn.lock index c288ac22dc3b..e69989cfcb12 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -7319,6 +7319,7 @@ __metadata: "@types/semver": ^7.3.4 "@types/shelljs": ^0.8.7 "@types/update-notifier": ^5.0.0 + "@types/util-deprecate": ^1.0.0 boxen: ^5.1.2 chalk: ^4.1.0 commander: ^6.2.1 @@ -7342,6 +7343,7 @@ __metadata: ts-dedent: ^2.0.0 typescript: ~4.6.3 update-notifier: ^5.0.1 + util-deprecate: ^1.0.2 bin: getstorybook: ./bin/index.js sb: ./bin/index.js diff --git a/docs/get-started/installation-problems/angular.mdx b/docs/get-started/installation-problems/angular.mdx index 8113277199e3..af6939fe2e9c 100644 --- a/docs/get-started/installation-problems/angular.mdx +++ b/docs/get-started/installation-problems/angular.mdx @@ -4,10 +4,10 @@ npx storybook init --type angular ``` -- Storybook's CLI provides support for both [Yarn](https://yarnpkg.com/) and [npm](https://www.npmjs.com/) package managers. If you have Yarn installed in your environment but prefer to use npm as your default package manager add the `--use-npm` flag to your installation command. For example: +- Storybook's CLI provides support for [Yarn](https://yarnpkg.com/), [npm](https://www.npmjs.com/), and [pnpm](https://pnpm.io/) package managers. If you have Yarn installed in your environment but prefer to use another as your default package manager add the `--package-manager` flag to your installation command. For example: ```shell - npx storybook init --use-npm + npx storybook init --package-manager=npm ``` - Storybook supports Webpack 5 out of the box. If you're upgrading from a previous version, run the following command to enable it: @@ -42,4 +42,4 @@ | `"styles"` | Provide the location of the [application's styles](../configure/styling-and-css.md#importing-css-files) to be used with Storybook.
`"styles": ["src/styles.css", "src/styles.scss"]`
| | `"stylePreprocessorOptions"` | Provides further customization for style preprocessors resolved to the workspace root.
`"stylePreprocessorOptions": { "includePaths": ["src/styles"] }` | -- For other installation issues, check the [Angular README](../../app/angular/README.md) for additional instructions. \ No newline at end of file +- For other installation issues, check the [Angular README](../../app/angular/README.md) for additional instructions. diff --git a/docs/get-started/installation-problems/ember.mdx b/docs/get-started/installation-problems/ember.mdx index 04920a346755..f1d494f05860 100644 --- a/docs/get-started/installation-problems/ember.mdx +++ b/docs/get-started/installation-problems/ember.mdx @@ -14,10 +14,10 @@ Update the [`@storybook/ember-cli-storybook`](https://www.npmjs.com/package/@storybook/ember-cli-storybook) package to the latest version to fix it. -- Storybook's CLI provides support for both [Yarn](https://yarnpkg.com/) and [npm](https://www.npmjs.com/) package managers. If you have Yarn installed in your environment but prefer to use npm as your default package manager add the `--use-npm` flag to your installation command. For example: +- Storybook's CLI provides support for [Yarn](https://yarnpkg.com/), [npm](https://www.npmjs.com/), and [pnpm](https://pnpm.io/) package managers. If you have Yarn installed in your environment but prefer to use another as your default package manager add the `--package-manager` flag to your installation command. For example: ```shell - npx storybook init --use-npm + npx storybook init --package-manager=npm ``` - -- For other installation issues, check the [Ember README](../../app/ember/README.md) for additional instructions. \ No newline at end of file + +- For other installation issues, check the [Ember README](../../app/ember/README.md) for additional instructions. diff --git a/docs/get-started/installation-problems/preact.mdx b/docs/get-started/installation-problems/preact.mdx index d3c98c8a2f38..10db561f96ce 100644 --- a/docs/get-started/installation-problems/preact.mdx +++ b/docs/get-started/installation-problems/preact.mdx @@ -3,11 +3,11 @@ ```shell npx storybook init --type preact ``` - - - Storybook's CLI provides support for both [Yarn](https://yarnpkg.com/) and [npm](https://www.npmjs.com/) package managers. If you have Yarn installed in your environment but prefer to use npm as your default package manager add the `--use-npm` flag to your installation command. For example: + +- Storybook's CLI provides support for [Yarn](https://yarnpkg.com/), [npm](https://www.npmjs.com/), and [pnpm](https://pnpm.io/) package managers. If you have Yarn installed in your environment but prefer to use another as your default package manager add the `--package-manager` flag to your installation command. For example: ```shell - npx storybook init --use-npm + npx storybook init --package-manager=npm ``` -- For other installation issues, check the [Preact README](../../app/preact/README.md) for additional instructions. \ No newline at end of file +- For other installation issues, check the [Preact README](../../app/preact/README.md) for additional instructions. diff --git a/docs/get-started/installation-problems/react.mdx b/docs/get-started/installation-problems/react.mdx index 6f2853b02b41..7993718555bf 100644 --- a/docs/get-started/installation-problems/react.mdx +++ b/docs/get-started/installation-problems/react.mdx @@ -4,10 +4,10 @@ npx storybook init --type react ``` - - Storybook's CLI provides support for both [Yarn](https://yarnpkg.com/) and [npm](https://www.npmjs.com/) package managers. If you have Yarn installed in your environment but prefer to use npm as your default package manager add the `--use-npm` flag to your installation command. For example: +- Storybook's CLI provides support for [Yarn](https://yarnpkg.com/), [npm](https://www.npmjs.com/), and [pnpm](https://pnpm.io/) package managers. If you have Yarn installed in your environment but prefer to use another as your default package manager add the `--package-manager` flag to your installation command. For example: ```shell - npx storybook init --use-npm + npx storybook init --package-manager=npm ``` - Storybook supports Webpack 5 out of the box. If you're upgrading from a previous version, run the following command to enable it: @@ -18,4 +18,4 @@ Check the [Migration Guide](https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#cra5-upgrade) for more information on how to set up Webpack 5. -- For other installation issues, check the [React README](../../app/react/README.md) for additional instructions. \ No newline at end of file +- For other installation issues, check the [React README](../../app/react/README.md) for additional instructions. diff --git a/docs/get-started/installation-problems/svelte.mdx b/docs/get-started/installation-problems/svelte.mdx index 0fa6d9782b37..fc13ced5eea6 100644 --- a/docs/get-started/installation-problems/svelte.mdx +++ b/docs/get-started/installation-problems/svelte.mdx @@ -3,12 +3,12 @@ ```shell npx storybook init --type svelte ``` - - - Storybook's CLI provides support for both [Yarn](https://yarnpkg.com/) and [npm](https://www.npmjs.com/) package managers. If you have Yarn installed in your environment but prefer to use npm as your default package manager add the `--use-npm` flag to your installation command. For example: + +- Storybook's CLI provides support for [Yarn](https://yarnpkg.com/), [npm](https://www.npmjs.com/), and [pnpm](https://pnpm.io/) package managers. If you have Yarn installed in your environment but prefer to use another as your default package manager add the `--package-manager` flag to your installation command. For example: ```shell - npx storybook init --use-npm + npx storybook init --package-manager=npm ``` - For issues with Svelte Native Story Format, check the [Svelte Story Format addon repository](https://github.com/storybookjs/addon-svelte-csf) for instructions. -- For other installation issues, check the [Svelte README](../../app/svelte/README.md) for additional instructions. \ No newline at end of file +- For other installation issues, check the [Svelte README](../../app/svelte/README.md) for additional instructions. diff --git a/docs/get-started/installation-problems/vue.mdx b/docs/get-started/installation-problems/vue.mdx index 3caa0a56199e..cfd752e0f8b7 100644 --- a/docs/get-started/installation-problems/vue.mdx +++ b/docs/get-started/installation-problems/vue.mdx @@ -8,11 +8,11 @@ npx storybook init --type vue3 ``` - - Storybook's CLI provides support for both [Yarn](https://yarnpkg.com/) and [npm](https://www.npmjs.com/) package managers. If you have Yarn installed in your environment but prefer to use npm as your default package manager add the `--use-npm` flag to your installation command. For example: +- Storybook's CLI provides support for [Yarn](https://yarnpkg.com/), [npm](https://www.npmjs.com/), and [pnpm](https://pnpm.io/) package managers. If you have Yarn installed in your environment but prefer to use another as your default package manager add the `--package-manager` flag to your installation command. For example: ```shell - npx storybook init --use-npm + npx storybook init --package-manager=npm ``` - For other installation issues, check the [Vue 2 README](../../app/vue/README.md), or the [Vue 3 README](../../app/vue3/README.md) for additional instructions. -- Vue 3 support is under active development, and we encourage feedback and improvements. Check the [contribution guidelines to help us improve it](../../CONTRIBUTING.md). \ No newline at end of file +- Vue 3 support is under active development, and we encourage feedback and improvements. Check the [contribution guidelines to help us improve it](../../CONTRIBUTING.md). From 450b2a34a0b8707bf822911556ef426145d4d344 Mon Sep 17 00:00:00 2001 From: Ian VanSchooten Date: Mon, 17 Oct 2022 10:21:33 -0400 Subject: [PATCH 3/3] Fix typescript error --- code/lib/cli/src/initiate.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/lib/cli/src/initiate.ts b/code/lib/cli/src/initiate.ts index cf6fb76ae0a9..28571f61f858 100644 --- a/code/lib/cli/src/initiate.ts +++ b/code/lib/cli/src/initiate.ts @@ -220,7 +220,7 @@ const installStorybook = ( }; const projectTypeInquirer = async ( - options: { yes?: boolean }, + options: CommandOptions & { yes?: boolean }, packageManager: JsPackageManager ) => { const manualAnswer = options.yes