Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release: Prerelease 8.0.0-alpha.9 #25545

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
263ed62
fix: Check optionalDependencies for storybook versions
reyronald Jan 2, 2024
4974d6d
Merge branch 'next' into patch-1
ndelangen Jan 3, 2024
6e8f823
Formatting
reyronald Jan 3, 2024
b7d72d5
Update helpers.ts
reyronald Jan 3, 2024
f44e808
Merge branch 'next' into patch-1
reyronald Jan 3, 2024
8206b39
Doc blocks: Remove deprecated props from Primary block
yannbf Jan 5, 2024
94d113a
Merge branch 'next' into patch-1
reyronald Jan 8, 2024
e66c43e
get versioned packages from monorepo if not-latest, bail on init if c…
ndelangen Jan 9, 2024
37ea07e
remove simple-update-notifier and replace it with actual checking
ndelangen Jan 9, 2024
388f698
Merge branch 'next' into norbert/cli-versioning-base2
ndelangen Jan 9, 2024
aa02264
fix version detection
ndelangen Jan 9, 2024
ca72143
Merge branch 'next' into norbert/cli-versioning-base2
ndelangen Jan 9, 2024
3140c35
Refactor Primary component in blocks
valentinpalkovic Jan 9, 2024
ef3de5a
Merge branch 'next' into norbert/cli-versioning-base2
ndelangen Jan 9, 2024
ac23207
apply review comments
ndelangen Jan 9, 2024
a2f7280
Merge branch 'next' into norbert/cli-versioning-base2
ndelangen Jan 9, 2024
defcd7c
Merge branch 'next' into yann/remove-deprecated-primary-storyblock-props
valentinpalkovic Jan 10, 2024
1679414
Merge remote-tracking branch 'origin/next' into yann/remove-deprecate…
valentinpalkovic Jan 10, 2024
835feb5
CLI: Add addon `remove` command
shilman Jan 10, 2024
c95711d
Merge branch 'next' into norbert/cli-versioning-base2
ndelangen Jan 10, 2024
7ca83ab
ConfigFile: Fix PNP wrapping logic
shilman Jan 10, 2024
992148f
ensure CsfFile.stories follows the order of __namedExportsOrder
JReinhold Jan 10, 2024
12ce91e
Merge branch 'next' into shlman/add-cli-remove-command
shilman Jan 10, 2024
44608bd
correctly get primary story from CsfFile
JReinhold Jan 10, 2024
677476f
Merge branch 'yann/remove-deprecated-primary-storyblock-props' of git…
JReinhold Jan 10, 2024
080bf57
Merge pull request #25406 from reyronald/patch-1
ndelangen Jan 10, 2024
5d970c7
oops
ndelangen Jan 10, 2024
4e3ef87
get primary story via componentStoriesFromCSFFile
JReinhold Jan 10, 2024
4ac3f9e
Merge pull request #25517 from storybookjs/norbert/cli-versioning-base2
JReinhold Jan 10, 2024
b29d2a7
Merge pull request #25461 from storybookjs/yann/remove-deprecated-pri…
valentinpalkovic Jan 10, 2024
4b4efed
Merge pull request #25538 from storybookjs/shlman/add-cli-remove-command
shilman Jan 10, 2024
d35bd03
Write changelog for 8.0.0-alpha.9 [skip ci]
storybook-bot Jan 10, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions CHANGELOG.prerelease.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
## 8.0.0-alpha.9

- AutoTitle: Fix case-insensitive trailing duplicate - [#25452](https://github.com/storybookjs/storybook/pull/25452), thanks [@ksugawara61](https://github.com/ksugawara61)!
- CLI: Add addon `remove` command - [#25538](https://github.com/storybookjs/storybook/pull/25538), thanks [@shilman](https://github.com/shilman)!
- CLI: Check optionalDependencies for storybook versions - [#25406](https://github.com/storybookjs/storybook/pull/25406), thanks [@reyronald](https://github.com/reyronald)!
- CLI: Fix using wrong package managers in existing projects - [#25474](https://github.com/storybookjs/storybook/pull/25474), thanks [@JReinhold](https://github.com/JReinhold)!
- CLI: Never prompt for ESLint plugin - [#25289](https://github.com/storybookjs/storybook/pull/25289), thanks [@shilman](https://github.com/shilman)!
- CLI: Versioned installation of monorepo packages - [#25517](https://github.com/storybookjs/storybook/pull/25517), thanks [@ndelangen](https://github.com/ndelangen)!
- CSF-tools: Allow type checking in storySort - [#25265](https://github.com/storybookjs/storybook/pull/25265), thanks [@honzahruby](https://github.com/honzahruby)!
- Core: Remove `storyStoreV7` feature flag - [#24658](https://github.com/storybookjs/storybook/pull/24658), thanks [@ndelangen](https://github.com/ndelangen)!
- Core: Remove deprecated createChannel APIs - [#25487](https://github.com/storybookjs/storybook/pull/25487), thanks [@yannbf](https://github.com/yannbf)!
- Doc blocks: Remove deprecated props from Primary block - [#25461](https://github.com/storybookjs/storybook/pull/25461), thanks [@yannbf](https://github.com/yannbf)!
- Node.js: Update version requirement to >= 18.0.0 - [#25516](https://github.com/storybookjs/storybook/pull/25516), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!
- Storysource: Fix import error - [#25391](https://github.com/storybookjs/storybook/pull/25391), thanks [@unional](https://github.com/unional)!
- UI: Fix sidebar top and bottom addon slots - [#25426](https://github.com/storybookjs/storybook/pull/25426), thanks [@ndelangen](https://github.com/ndelangen)!
- Webpack5: Remove babel and SWC compiler from builder - [#25379](https://github.com/storybookjs/storybook/pull/25379), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!

## 8.0.0-alpha.8

- Addon Links: Remove LinkTo from direct import - [#25418](https://github.com/storybookjs/storybook/pull/25418), thanks [@yannbf](https://github.com/yannbf)!
Expand Down
5 changes: 5 additions & 0 deletions MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
- [Deprecated docs parameters](#deprecated-docs-parameters)
- [Description Doc block properties](#description-doc-block-properties)
- [Manager API expandAll and collapseAll methods](#manager-api-expandall-and-collapseall-methods)
- [`Primary` Doc block properties](#primary-doc-block-properties)
- [`createChannel` from `@storybook/postmessage` and `@storybook/channel-websocket`](#createchannel-from-storybookpostmessage-and--storybookchannel-websocket)
- [From version 7.5.0 to 7.6.0](#from-version-750-to-760)
- [CommonJS with Vite is deprecated](#commonjs-with-vite-is-deprecated)
Expand Down Expand Up @@ -899,6 +900,10 @@ api.collapseAll() // becomes api.emit(STORIES_COLLAPSE_ALL)
api.expandAll() // becomes api.emit(STORIES_EXPAND_ALL)
```

#### `Primary` Doc block properties

The `name` prop is now removed in favor of the `of` property. [More info](#doc-blocks).

#### `createChannel` from `@storybook/postmessage` and `@storybook/channel-websocket`

The `createChannel` APIs from both `@storybook/channel-websocket` and `@storybook/postmessage` are now removed. Please use `createBrowserChannel` instead, from the `@storybook/channels` package.
Expand Down
1 change: 0 additions & 1 deletion code/lib/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@
"prompts": "^2.4.0",
"read-pkg-up": "^7.0.1",
"semver": "^7.3.7",
"simple-update-notifier": "^2.0.0",
"strip-json-comments": "^3.0.1",
"tempy": "^1.0.1",
"tiny-invariant": "^1.3.1",
Expand Down
9 changes: 9 additions & 0 deletions code/lib/cli/src/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import invariant from 'tiny-invariant';
import type { CommandOptions } from './generators/types';
import { initiate } from './initiate';
import { add } from './add';
import { remove } from './remove';
import { migrate } from './migrate';
import { upgrade, type UpgradeOptions } from './upgrade';
import { sandbox } from './sandbox';
Expand Down Expand Up @@ -66,6 +67,14 @@ command('add <addon>')
.option('-s --skip-postinstall', 'Skip package specific postinstall config modifications')
.action((addonName: string, options: any) => add(addonName, options));

command('remove <addon>')
.description('Remove an addon from your Storybook')
.option(
'--package-manager <npm|pnpm|yarn1|yarn2>',
'Force package manager for installing dependencies'
)
.action((addonName: string, options: any) => remove(addonName, options));

command('upgrade')
.description('Upgrade your Storybook packages to the latest')
.option(
Expand Down
2 changes: 1 addition & 1 deletion code/lib/cli/src/generators/NEXTJS/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const generator: Generator = async (packageManager, npmOptions, options) => {
'react',
{
staticDir,
extraAddons: ['@storybook/addon-onboarding'],
extraAddons: ['@storybook/addon-onboarding@^1.0.0'],
webpackCompiler: ({ builder }) => undefined,
},
'nextjs'
Expand Down
2 changes: 1 addition & 1 deletion code/lib/cli/src/generators/REACT/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const generator: Generator = async (packageManager, npmOptions, options) => {
await baseGenerator(packageManager, npmOptions, options, 'react', {
extraPackages,
webpackCompiler: ({ builder }) => (builder === CoreBuilder.Webpack5 ? 'swc' : undefined),
extraAddons: ['@storybook/addon-onboarding'],
extraAddons: ['@storybook/addon-onboarding@^1.0.0'],
});
};

Expand Down
4 changes: 2 additions & 2 deletions code/lib/cli/src/generators/REACT_NATIVE/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@ const generator = async (
'@storybook/addon-controls@^6.5.16',
];

const resolvedPackages = await packageManager.getVersionedPackages(packagesToResolve);
const versionedPackages = await packageManager.getVersionedPackages(packagesToResolve);

const babelDependencies = await getBabelDependencies(packageManager, packageJson);

const packages: string[] = [];
packages.push(...babelDependencies);
packages.push(...packagesWithFixedVersion);
packages.push(...resolvedPackages);
packages.push(...versionedPackages);
if (missingReactDom && reactVersion) {
packages.push(`react-dom@${reactVersion}`);
}
Expand Down
2 changes: 1 addition & 1 deletion code/lib/cli/src/generators/WEBPACK_REACT/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type { Generator } from '../types';

const generator: Generator = async (packageManager, npmOptions, options) => {
await baseGenerator(packageManager, npmOptions, options, 'react', {
extraAddons: ['@storybook/addon-onboarding'],
extraAddons: ['@storybook/addon-onboarding@^1.0.0'],
webpackCompiler: ({ builder }) => (builder === CoreBuilder.Webpack5 ? 'swc' : undefined),
});
};
Expand Down
9 changes: 4 additions & 5 deletions code/lib/cli/src/generators/baseGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -298,29 +298,28 @@ export async function baseGenerator(
const versionedPackages = await packageManager.getVersionedPackages(packages as string[]);
versionedPackagesSpinner.succeed();

const depsToInstall = [...versionedPackages];

try {
if (process.env.CI !== 'true') {
const { hasEslint, isStorybookPluginInstalled, eslintConfigFile } = await extractEslintInfo(
packageManager
);

if (hasEslint && !isStorybookPluginInstalled) {
depsToInstall.push('eslint-plugin-storybook');
versionedPackages.push('eslint-plugin-storybook');
await configureEslintPlugin(eslintConfigFile ?? undefined, packageManager);
}
}
} catch (err) {
// any failure regarding configuring the eslint plugin should not fail the whole generator
}

if (depsToInstall.length > 0) {
if (versionedPackages.length > 0) {
const addDependenciesSpinner = ora({
indent: 2,
text: 'Installing Storybook dependencies',
}).start();
await packageManager.addDependencies({ ...npmOptions, packageJson }, depsToInstall);

await packageManager.addDependencies({ ...npmOptions, packageJson }, versionedPackages);
addDependenciesSpinner.succeed();
}

Expand Down
6 changes: 5 additions & 1 deletion code/lib/cli/src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,11 @@ export async function adjustTemplate(templatePath: string, templateData: Record<
// Given a package.json, finds any official storybook package within it
// and if it exists, returns the version of that package from the specified package.json
export function getStorybookVersionSpecifier(packageJson: PackageJsonWithDepsAndDevDeps) {
const allDeps = { ...packageJson.dependencies, ...packageJson.devDependencies };
const allDeps = {
...packageJson.dependencies,
...packageJson.devDependencies,
...packageJson.optionalDependencies,
};
const storybookPackage = Object.keys(allDeps).find((name: string) => {
return storybookMonorepoPackages[name as keyof typeof storybookMonorepoPackages];
});
Expand Down
35 changes: 27 additions & 8 deletions code/lib/cli/src/initiate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { NxProjectDetectedError } from '@storybook/core-events/server-errors';

import dedent from 'ts-dedent';
import boxen from 'boxen';
import { lt, prerelease } from 'semver';
import type { Builder } from './project_types';
import { installableProjectTypes, ProjectType } from './project_types';
import { detect, isStorybookInstantiated, detectLanguage, detectPnp } from './detect';
Expand Down Expand Up @@ -241,15 +242,33 @@ async function doInitiate(
force: pkgMgr,
});

const welcomeMessage = 'storybook init - the simplest way to add a Storybook to your project.';
logger.log(chalk.inverse(`\n ${welcomeMessage} \n`));
const latestVersion = await packageManager.latestVersion('@storybook/cli');
const currentVersion = versions['@storybook/cli'];
const isPrerelease = prerelease(currentVersion);
const isOutdated = lt(currentVersion, latestVersion);
const borderColor = isOutdated ? '#FC521F' : '#F1618C';

const messages = {
welcome: `Adding Storybook version ${chalk.bold(currentVersion)} to your project..`,
notLatest: chalk.red(dedent`
This version is behind the latest release, which is: ${chalk.bold(latestVersion)}!
You likely ran the init command through npx, which can use a locally cached version, to get the latest please run:
${chalk.bold('npx storybook@latest init')}

You may want to CTRL+C to stop, and run with the latest version instead.
`),
prelease: chalk.yellow('This is a pre-release version.'),
};

// Update notify code.
const { default: updateNotifier } = await import('simple-update-notifier');
await updateNotifier({
pkg: pkg as any,
updateCheckInterval: 1000 * 60 * 60, // every hour (we could increase this later on.)
});
logger.log(
boxen(
[messages.welcome]
.concat(isOutdated && !isPrerelease ? [messages.notLatest] : [])
.concat(isPrerelease ? [messages.prelease] : [])
.join('\n'),
{ borderStyle: 'round', padding: 1, borderColor }
)
);

// Check if the current directory is empty.
if (options.force !== true && currentDirectoryIsEmpty(packageManager.type)) {
Expand Down
18 changes: 17 additions & 1 deletion code/lib/cli/src/js-package-manager/JsPackageManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -330,13 +330,29 @@ export abstract class JsPackageManager {
/**
* Return an array of strings matching following format: `<package_name>@<package_latest_version>`
*
* For packages in the storybook monorepo, when the latest version is equal to the version of the current CLI
* the version is not added to the string.
*
* When a package is in the monorepo, and the version is not equal to the CLI version, the version is taken from the versions.ts file and added to the string.
*
* @param packages
*/
public getVersionedPackages(packages: string[]): Promise<string[]> {
return Promise.all(
packages.map(async (pkg) => {
const [packageName, packageVersion] = getPackageDetails(pkg);
return `${packageName}@${await this.getVersion(packageName, packageVersion)}`;
const latestInRange = await this.latestVersion(packageName, packageVersion);

const k = packageName as keyof typeof storybookPackagesVersions;
const currentVersion = storybookPackagesVersions[k];

if (currentVersion === latestInRange) {
return `${packageName}`;
}
if (currentVersion) {
return `${packageName}@${currentVersion}`;
}
return `${packageName}@^${latestInRange}`;
})
);
}
Expand Down
46 changes: 46 additions & 0 deletions code/lib/cli/src/remove.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { getStorybookInfo } from '@storybook/core-common';
import { readConfig, writeConfig } from '@storybook/csf-tools';
import dedent from 'ts-dedent';

import { JsPackageManagerFactory, type PackageManagerName } from './js-package-manager';

const logger = console;

/**
* Remove the given addon package and remove it from main.js
*
* Usage:
* - sb remove @storybook/addon-links
*/
export async function remove(addon: string, options: { packageManager: PackageManagerName }) {
const { packageManager: pkgMgr } = options;

const packageManager = JsPackageManagerFactory.getPackageManager({ force: pkgMgr });
const packageJson = await packageManager.retrievePackageJson();
const { mainConfig, configDir } = getStorybookInfo(packageJson);

if (typeof configDir === 'undefined') {
throw new Error(dedent`
Unable to find storybook config directory
`);
}

if (!mainConfig) {
logger.error('Unable to find storybook main.js config');
return;
}
const main = await readConfig(mainConfig);

// remove from package.json
logger.log(`Uninstalling ${addon}`);
await packageManager.removeDependencies({ packageJson }, [addon]);

// add to main.js
logger.log(`Removing '${addon}' from main.js addons field.`);
try {
main.removeEntryFromArray(['addons'], addon);
await writeConfig(main);
} catch (err) {
logger.warn(`Failed to remove '${addon}' from main.js addons field.`);
}
}
70 changes: 70 additions & 0 deletions code/lib/csf-tools/src/ConfigFile.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1139,4 +1139,74 @@ describe('ConfigFile', () => {
`);
});
});

describe('removeEntryFromArray', () => {
it('removes a string literal entry', () => {
const source = dedent`
export default {
addons: ['a', 'b', 'c'],
}
`;
const config = loadConfig(source).parse();
config.removeEntryFromArray(['addons'], 'b');
expect(config.getFieldValue(['addons'])).toMatchInlineSnapshot(`a,c`);
});

it('removes a preset-style object entry', () => {
const source = dedent`
export default {
addons: ['a', { name: 'b', options: {} }, 'c'],
}
`;
const config = loadConfig(source).parse();
config.removeEntryFromArray(['addons'], 'b');
expect(config.getFieldValue(['addons'])).toMatchInlineSnapshot(`a,c`);
});

it('removes a pnp-wrapped string entry', () => {
const source = dedent`
export default {
addons: ['a', getAbsolutePath('b'), 'c'],
}
`;
const config = loadConfig(source).parse();
config.removeEntryFromArray(['addons'], 'b');
expect(config.getFieldValue(['addons'])).toMatchInlineSnapshot(`a,c`);
});

it('removes a pnp-wrapped object entry', () => {
const source = dedent`
export default {
addons: ['a', { name: getAbsolutePath('b'), options: {} }, 'c'],
}
`;
const config = loadConfig(source).parse();
config.removeEntryFromArray(['addons'], 'b');
expect(config.getFieldValue(['addons'])).toMatchInlineSnapshot(`a,c`);
});

it('throws when entry is missing', () => {
const source = dedent`
export default {
addons: ['a', { name: 'b', options: {} }, 'c'],
}
`;
const config = loadConfig(source).parse();
expect(() => config.removeEntryFromArray(['addons'], 'x')).toThrowErrorMatchingInlineSnapshot(
`Error: Could not find 'x' in array at 'addons'`
);
});

it('throws when target array is not an arral', () => {
const source = dedent`
export default {
addons: {},
}
`;
const config = loadConfig(source).parse();
expect(() => config.removeEntryFromArray(['addons'], 'x')).toThrowErrorMatchingInlineSnapshot(
`Error: Expected array at 'addons', got 'ObjectExpression'`
);
});
});
});
Loading