Skip to content

Commit

Permalink
Merge branch 'next' into new-sveltekit-modules
Browse files Browse the repository at this point in the history
  • Loading branch information
paoloricciuti committed Dec 18, 2023
2 parents 482ef84 + 9cd9f65 commit bd2cf8e
Show file tree
Hide file tree
Showing 47 changed files with 1,831 additions and 3,798 deletions.
7 changes: 7 additions & 0 deletions MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
- [Icons is deprecated](#icons-is-deprecated)
- [React-docgen component analysis by default](#react-docgen-component-analysis-by-default)
- [Removed postinstall](#removed-postinstall)
- [Removed stories.json](#removed-storiesjson)
- [Framework-specific changes](#framework-specific-changes)
- [Angular: Drop support for Angular \< 15](#angular-drop-support-for-angular--15)
- [Next.js: Drop support for version \< 13.5](#nextjs-drop-support-for-version--135)
Expand Down Expand Up @@ -473,6 +474,12 @@ For more information see: https://storybook.js.org/docs/react/api/main-config-ty

We removed the `@storybook/postinstall` package, which provided some utilities for addons to programmatically modify user configuration files on install. This package was years out of date, so this should be a non-disruptive change. If your addon used the package, you can view the old source code [here](https://github.com/storybookjs/storybook/tree/release-7-5/code/lib/postinstall) and adapt it into your addon.

#### Removed stories.json

In addition to the built storybook, `storybook build` generates two files, `index.json` and `stories.json`, that list out the contents of the Storybook. `stories.json` is a legacy format and we included it for backwards compatibility. As of 8.0 we no longer build `stories.json` by default, and we will remove it completely in 9.0.

In the meantime if you have code that relies on `stories.json`, you can find code that transforms the "v4" `index.json` to the "v3" `stories.json` format (and their respective TS types): https://github.com/storybookjs/storybook/blob/release-7-5/code/lib/core-server/src/utils/stories-json.ts#L71-L91

### Framework-specific changes

#### Angular: Drop support for Angular \< 15
Expand Down
8 changes: 2 additions & 6 deletions code/addons/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -112,21 +112,17 @@
"@storybook/theming": "workspace:*",
"@storybook/types": "workspace:*",
"fs-extra": "^11.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"remark-external-links": "^8.0.0",
"remark-slug": "^6.0.0",
"ts-dedent": "^2.0.0"
},
"devDependencies": {
"@rollup/pluginutils": "^5.0.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"typescript": "^5.3.2",
"vite": "^4.0.4"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
},
"publishConfig": {
"access": "public"
},
Expand Down
40 changes: 0 additions & 40 deletions code/addons/docs/src/ensure-react-peer-deps.ts

This file was deleted.

87 changes: 84 additions & 3 deletions code/addons/docs/src/preset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,26 @@ import type { JSXOptions, CompileOptions } from '@storybook/mdx2-csf';
import { global } from '@storybook/global';
import { loadCsf } from '@storybook/csf-tools';
import { logger } from '@storybook/node-logger';
import { ensureReactPeerDeps } from './ensure-react-peer-deps';

/**
* Get the resolvedReact preset, which points either to
* the user's react dependencies or the react dependencies shipped with addon-docs
* if the user has not installed react explicitly.
*/
const getResolvedReact = async (options: Options) => {
const resolvedReact = (await options.presets.apply('resolvedReact', {})) as any;
// resolvedReact should always be set by the time we get here, but just in case, we'll default to addon-docs's react dependencies
return {
react: resolvedReact.react ?? dirname(require.resolve('react/package.json')),
reactDom: resolvedReact.reactDom ?? dirname(require.resolve('react-dom/package.json')),
// In Webpack, symlinked MDX files will cause @mdx-js/react to not be resolvable if it is not hoisted
// This happens for the SB monorepo's template stories when a sandbox has a different react version than
// addon-docs, causing addon-docs's dependencies not to be hoisted.
// This might also affect regular users who have a similar setup.
// Explicitly alias @mdx-js/react to avoid this issue.
mdx: resolvedReact.mdx ?? dirname(require.resolve('@mdx-js/react/package.json')),
};
};

async function webpack(
webpackConfig: any = {},
Expand Down Expand Up @@ -90,6 +109,35 @@ async function webpack(
? require.resolve('@storybook/mdx1-csf/loader')
: require.resolve('@storybook/mdx2-csf/loader');

// Use the resolvedReact preset to alias react and react-dom to either the users version or the version shipped with addon-docs
const { react, reactDom, mdx } = await getResolvedReact(options);

let alias;
if (Array.isArray(webpackConfig.resolve?.alias)) {
alias = [...webpackConfig.resolve?.alias];
alias.push(
{
name: 'react',
alias: react,
},
{
name: 'react-dom',
alias: reactDom,
},
{
name: '@mdx-js/react',
alias: mdx,
}
);
} else {
alias = {
...webpackConfig.resolve?.alias,
react,
'react-dom': reactDom,
'@mdx-js/react': mdx,
};
}

const result = {
...webpackConfig,
plugins: [
Expand All @@ -99,7 +147,10 @@ async function webpack(
? [(await import('@storybook/csf-plugin')).webpack(csfPluginOptions)]
: []),
],

resolve: {
...webpackConfig.resolve,
alias,
},
module: {
...module,
rules: [
Expand Down Expand Up @@ -179,6 +230,25 @@ export const viteFinal = async (config: any, options: Options) => {
const { plugins = [] } = config;
const { mdxPlugin } = await import('./plugins/mdx-plugin');

// Use the resolvedReact preset to alias react and react-dom to either the users version or the version shipped with addon-docs
const { react, reactDom } = await getResolvedReact(options);

const reactAliasPlugin = {
name: 'storybook:react-alias',
enforce: 'pre',
config: () => ({
resolve: {
alias: {
react,
'react-dom': reactDom,
},
},
}),
};

// add alias plugin early to ensure any other plugins that also add the aliases will override this
// eg. the preact vite plugin adds its own aliases
plugins.unshift(reactAliasPlugin);
plugins.push(mdxPlugin(options));

return config;
Expand All @@ -192,7 +262,18 @@ const webpackX = webpack as any;
const indexersX = indexers as any;
const docsX = docs as any;

ensureReactPeerDeps();
/**
* If the user has not installed react explicitly in their project,
* the resolvedReact preset will not be set.
* We then set it here in addon-docs to use addon-docs's react version that always exists.
* This is just a fallback that never overrides the existing preset,
* but ensures that there is always a resolved react.
*/
export const resolvedReact = async (existing: any) => ({
react: existing?.react ?? dirname(require.resolve('react/package.json')),
reactDom: existing?.reactDom ?? dirname(require.resolve('react-dom/package.json')),
mdx: existing?.mdx ?? dirname(require.resolve('@mdx-js/react/package.json')),
});

const optimizeViteDeps = [
'@mdx-js/react',
Expand Down
13 changes: 13 additions & 0 deletions code/addons/docs/template/stories/docs2/ResolvedReact.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { version as reactVersion } from 'react';
import { version as reactDomVersion } from 'react-dom';
import { ResolvedReactVersion } from './ResolvedReactVersion';

## In MDX

<code>react</code>: <code data-testid="mdx-react">{reactVersion}</code>

<code>react-dom</code>: <code data-testid="mdx-react-dom">{reactDomVersion}</code>

## In `ResolvedReactVersion` component

<ResolvedReactVersion />
15 changes: 15 additions & 0 deletions code/addons/docs/template/stories/docs2/ResolvedReactVersion.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React, { version as reactVersion } from 'react';
import { version as reactDomVersion } from 'react-dom';

export const ResolvedReactVersion = () => {
return (
<>
<p>
<code>react</code>: <code data-testid="component-react">{reactVersion}</code>
</p>
<p>
<code>react-dom</code>: <code data-testid="component-react-dom">{reactDomVersion}</code>
</p>
</>
);
};
4 changes: 0 additions & 4 deletions code/addons/essentials/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,6 @@
"devDependencies": {
"typescript": "^5.3.2"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
},
"publishConfig": {
"access": "public"
},
Expand Down
27 changes: 27 additions & 0 deletions code/e2e-tests/addon-docs.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,4 +186,31 @@ test.describe('addon-docs', () => {
await expect(stories.nth(1)).toHaveText('Basic');
await expect(stories.last()).toHaveText('Another');
});

test('should resolve react to the correct version', async ({ page }) => {
const sbPage = new SbPage(page);
await sbPage.navigateToUnattachedDocs('addons/docs/docs2', 'ResolvedReact');
const root = sbPage.previewRoot();

let expectedReactVersion = /^18/;
if (
templateName.includes('preact') ||
templateName.includes('react-webpack/17') ||
templateName.includes('react-vite/17')
) {
expectedReactVersion = /^17/;
} else if (templateName.includes('react16')) {
expectedReactVersion = /^16/;
}

const mdxReactVersion = await root.getByTestId('mdx-react');
const mdxReactDomVersion = await root.getByTestId('mdx-react-dom');
const componentReactVersion = await root.getByTestId('component-react');
const componentReactDomVersion = await root.getByTestId('component-react-dom');

await expect(mdxReactVersion).toHaveText(expectedReactVersion);
await expect(mdxReactDomVersion).toHaveText(expectedReactVersion);
await expect(componentReactVersion).toHaveText(expectedReactVersion);
await expect(componentReactDomVersion).toHaveText(expectedReactVersion);
});
});
20 changes: 20 additions & 0 deletions code/e2e-tests/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,26 @@ export class SbPage {
await this.previewRoot();
}

async navigateToUnattachedDocs(title: string, name = 'docs') {
await this.openComponent(title);

const titleId = toId(title);
const storyId = toId(name);
const storyLinkId = `#${titleId}-${storyId}--docs`;
await this.page.waitForSelector(storyLinkId);
const storyLink = this.page.locator('*', { has: this.page.locator(`> ${storyLinkId}`) });
await storyLink.click({ force: true });

await this.page.waitForURL((url) =>
url.search.includes(`path=/docs/${titleId}-${storyId}--docs`)
);

const selected = await storyLink.getAttribute('data-selected');
await expect(selected).toBe('true');

await this.previewRoot();
}

async waitUntilLoaded() {
// make sure we start every test with clean state – to avoid possible flakyness
await this.page.context().addInitScript(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ function Component() {
name: 'Prefetch',
},
{
// @ts-expect-error (a legacy nextjs api?)
cb: () => router.push('/push-html', { forceOptimisticNavigation: true }),
name: 'Push HTML',
},
Expand All @@ -32,6 +33,7 @@ function Component() {
name: 'Refresh',
},
{
// @ts-expect-error (a legacy nextjs api?)
cb: () => router.replace('/replaced-html', { forceOptimisticNavigation: true }),
name: 'Replace',
},
Expand Down
66 changes: 0 additions & 66 deletions code/lib/cli/src/automigrate/fixes/add-react.test.ts

This file was deleted.

0 comments on commit bd2cf8e

Please sign in to comment.