mirror of
https://github.com/storybookjs/storybook.git
synced 2025-04-07 07:21:17 +08:00
Merge pull request #29585 from storybookjs/version-non-patch-from-8.5.0-alpha.3
Release: Prerelease 8.5.0-alpha.4
This commit is contained in:
commit
4a75d13e4c
@ -211,6 +211,57 @@ jobs:
|
||||
yarn knip --no-exit-code
|
||||
- report-workflow-on-failure
|
||||
- cancel-workflow-on-failure
|
||||
bench-packages:
|
||||
executor:
|
||||
class: medium
|
||||
name: sb_node_22_classic
|
||||
steps:
|
||||
- git-shallow-clone/checkout_advanced:
|
||||
clone_options: "--depth 1 --verbose"
|
||||
- attach_workspace:
|
||||
at: .
|
||||
# if there is a base branch AND a PR number in parameters, benchmark packages against those
|
||||
# this happens when run against a PR
|
||||
- when:
|
||||
condition:
|
||||
and:
|
||||
- << pipeline.parameters.ghBaseBranch >>
|
||||
- << pipeline.parameters.ghPrNumber >>
|
||||
steps:
|
||||
- run:
|
||||
name: Benchmarking packages against base branch
|
||||
working_directory: scripts
|
||||
command: |
|
||||
yarn local-registry --open &
|
||||
until curl -s http://localhost:6001 > /dev/null; do
|
||||
echo 'Waiting for local registry to be available...'
|
||||
sleep 2
|
||||
done
|
||||
yarn bench-packages --base-branch << pipeline.parameters.ghBaseBranch >> --pull-request << pipeline.parameters.ghPrNumber >> --upload
|
||||
# if there is a NOT a base branch OR NOT a PR number in parameters, just upload benchmarks for the branch
|
||||
# this happens when runned directly on branches, like next or main
|
||||
- when:
|
||||
condition:
|
||||
or:
|
||||
- not: << pipeline.parameters.ghBaseBranch >>
|
||||
- not: << pipeline.parameters.ghPrNumber >>
|
||||
steps:
|
||||
- run:
|
||||
name: Uploading package benchmarks for branch
|
||||
working_directory: scripts
|
||||
command: |
|
||||
yarn local-registry --open &
|
||||
until curl -s http://localhost:6001 > /dev/null; do
|
||||
echo 'Waiting for local registry to be available...'
|
||||
sleep 2
|
||||
done
|
||||
yarn bench-packages --upload
|
||||
- store_artifacts:
|
||||
path: bench/packages/results.json
|
||||
- store_artifacts:
|
||||
path: bench/packages/compare-with-<< pipeline.parameters.ghBaseBranch >>.json
|
||||
- report-workflow-on-failure
|
||||
- cancel-workflow-on-failure
|
||||
check:
|
||||
executor:
|
||||
class: xlarge
|
||||
@ -543,7 +594,7 @@ jobs:
|
||||
- store_artifacts: # this is where playwright puts more complex stuff
|
||||
path: code/playwright-results/
|
||||
destination: playwright
|
||||
bench:
|
||||
bench-sandboxes:
|
||||
parameters:
|
||||
parallelism:
|
||||
type: integer
|
||||
@ -753,6 +804,9 @@ workflows:
|
||||
- knip:
|
||||
requires:
|
||||
- build
|
||||
- bench-packages:
|
||||
requires:
|
||||
- build
|
||||
- check:
|
||||
requires:
|
||||
- build
|
||||
@ -799,7 +853,7 @@ workflows:
|
||||
parallelism: 5
|
||||
requires:
|
||||
- create-sandboxes
|
||||
- bench:
|
||||
- bench-sandboxes:
|
||||
parallelism: 5
|
||||
requires:
|
||||
- build-sandboxes
|
||||
@ -828,6 +882,9 @@ workflows:
|
||||
- knip:
|
||||
requires:
|
||||
- build
|
||||
- bench-packages:
|
||||
requires:
|
||||
- build
|
||||
- check:
|
||||
requires:
|
||||
- build
|
||||
@ -883,7 +940,7 @@ workflows:
|
||||
- test-ui-testing-module:
|
||||
requires:
|
||||
- build
|
||||
- bench:
|
||||
- bench-sandboxes:
|
||||
parallelism: 5
|
||||
requires:
|
||||
- build-sandboxes
|
||||
@ -904,6 +961,9 @@ workflows:
|
||||
- knip:
|
||||
requires:
|
||||
- build
|
||||
- bench-packages:
|
||||
requires:
|
||||
- build
|
||||
- check:
|
||||
requires:
|
||||
- build
|
||||
@ -920,22 +980,22 @@ workflows:
|
||||
requires:
|
||||
- build
|
||||
- create-sandboxes:
|
||||
parallelism: 38
|
||||
parallelism: 37
|
||||
requires:
|
||||
- build
|
||||
# - smoke-test-sandboxes: # disabled for now
|
||||
# requires:
|
||||
# - create-sandboxes
|
||||
- build-sandboxes:
|
||||
parallelism: 38
|
||||
parallelism: 37
|
||||
requires:
|
||||
- create-sandboxes
|
||||
- chromatic-sandboxes:
|
||||
parallelism: 35
|
||||
parallelism: 34
|
||||
requires:
|
||||
- build-sandboxes
|
||||
- e2e-production:
|
||||
parallelism: 33
|
||||
parallelism: 32
|
||||
requires:
|
||||
- build-sandboxes
|
||||
- e2e-dev:
|
||||
@ -943,7 +1003,7 @@ workflows:
|
||||
requires:
|
||||
- create-sandboxes
|
||||
- test-runner-production:
|
||||
parallelism: 33
|
||||
parallelism: 32
|
||||
requires:
|
||||
- build-sandboxes
|
||||
- vitest-integration:
|
||||
@ -977,7 +1037,7 @@ workflows:
|
||||
# --smoke-test is not supported for the angular builder right now
|
||||
# - "angular-cli"
|
||||
- "lit-vite-ts"
|
||||
- bench:
|
||||
- bench-sandboxes:
|
||||
parallelism: 5
|
||||
requires:
|
||||
- build-sandboxes
|
||||
|
@ -1,3 +1,11 @@
|
||||
## 8.4.2
|
||||
|
||||
- Addon Test: Fix post-install logic for Next.js Vite framework support - [#29524](https://github.com/storybookjs/storybook/pull/29524), thanks @valentinpalkovic!
|
||||
- Addon Test: Only render the TestingModule component in development mode - [#29501](https://github.com/storybookjs/storybook/pull/29501), thanks @yannbf!
|
||||
- CLI: Fix Solid init by installing `@storybook/test` - [#29514](https://github.com/storybookjs/storybook/pull/29514), thanks @shilman!
|
||||
- Core: Shim CJS-only globals in ESM output - [#29157](https://github.com/storybookjs/storybook/pull/29157), thanks @valentinpalkovic!
|
||||
- Next.js: Fix bundled react and react-dom in monorepos - [#29444](https://github.com/storybookjs/storybook/pull/29444), thanks @sentience!
|
||||
|
||||
## 8.4.1
|
||||
|
||||
- Core: Relax peer dep constraint of shim packages - [#29503](https://github.com/storybookjs/storybook/pull/29503), thanks @kasperpeulen!
|
||||
|
@ -1,3 +1,8 @@
|
||||
## 8.5.0-alpha.4
|
||||
|
||||
- Next.js: Add support for Next 15 - [#29587](https://github.com/storybookjs/storybook/pull/29587), thanks @yannbf!
|
||||
- UI: Add Yarn to About Section - [#29225](https://github.com/storybookjs/storybook/pull/29225), thanks @grantwforsythe!
|
||||
|
||||
## 8.5.0-alpha.3
|
||||
|
||||
- Addon Test: Fix post-install logic for Next.js Vite framework support - [#29524](https://github.com/storybookjs/storybook/pull/29524), thanks @valentinpalkovic!
|
||||
|
@ -5,6 +5,7 @@ Storybook is developed against a specific node version which is defined in an `.
|
||||
## Ensure you have the required system utilities
|
||||
|
||||
You will need to have the following installed:
|
||||
|
||||
- git
|
||||
- node
|
||||
- yarn
|
||||
@ -20,7 +21,7 @@ You will need to have the following installed:
|
||||
|
||||
## Running the local development environment
|
||||
|
||||
- Ensure if you are using Windows to use the Windows Subsystem for Linux (WSL).
|
||||
- All commands should be run in a terminal with administrator privileges in Windows environments.
|
||||
- Run `yarn start` in the root directory to run a basic test Storybook "sandbox".
|
||||
|
||||
The `yarn start` script will generate a React Vite TypeScript sandbox with a set of test stories inside it, as well as taking all steps required to get it running (building the various packages we need etc). There is no need to run `yarn` or `yarn install` as `yarn start` will do this for you.
|
||||
|
@ -19,6 +19,7 @@
|
||||
- [5. Make Manual Changes](#5-make-manual-changes)
|
||||
- [6. Merge](#6-merge)
|
||||
- [7. See the "Publish" Workflow Finish](#7-see-the-publish-workflow-finish)
|
||||
- [Releasing changes to older minor versions](#releasing-changes-to-older-minor-versions)
|
||||
- [Releasing Locally in an Emergency 🚨](#releasing-locally-in-an-emergency-)
|
||||
- [Canary Releases](#canary-releases)
|
||||
- [With GitHub UI](#with-github-ui)
|
||||
@ -330,6 +331,59 @@ Merging the pull request will trigger [the publish workflow](https://github.com/
|
||||
|
||||
Done! 🚀
|
||||
|
||||
## Releasing changes to older minor versions
|
||||
|
||||
If you need to release a change to an older minor version that is not the latest, you have to do it manually, locally. The process is described below, with an example of releasing a new `v8.3.7` in a situation where `8.4.0` is currently the latest version.
|
||||
|
||||
1. Checkout the _existing_ tag that matches the latest minor release you want to bump, and create a new branch from it. In this case, we want to do:
|
||||
1. `git fetch --all --tags`
|
||||
2. `git checkout tags/v8.3.6 -b patch-8-3-7`
|
||||
2. Make the changes you need to, most likely cherry-picking commits from the fix you need to back-port.
|
||||
3. Run `yarn install` in `scripts` and `code`
|
||||
4. Build all packages in `code` with `yarn task --task compile --no-link`
|
||||
5. Commit and push your changes.
|
||||
6. Trigger _daily_ CI manually on your branch:
|
||||
1. Open [CircleCI](https://app.circleci.com/pipelines/github/storybookjs/storybook) and click "Trigger Pipeline" on the top right corner of the page.
|
||||
2. Set the following configuration options:
|
||||
- Pipeline: _"storybook default"_
|
||||
- Config Source: _"storybook"_
|
||||
- Branch: Your branch, eg. `patch-8-3-7`
|
||||
3. Add a parameter, with _"name"_ `workflow`, _"value"_ `daily`
|
||||
7. Wait for CI to finish successfully.
|
||||
8. Bump all package versions:
|
||||
1. `cd scripts`
|
||||
2. `yarn release:version --release-type patch`
|
||||
9. Commit with `git commit -m "Bump version from <CURRENT_VERSION> to <NEXT_VERSION> MANUALLY"`
|
||||
10. Add a new entry to `CHANGELOG.md`, describing your changes
|
||||
11. Commit with `git commit -m "Update CHANGELOG.md with <NEXT_VERSION> MANUALLY"`
|
||||
12. Ensure you have the correct write permissions for all the Storybook npm packages. You need to be an admin of the _storybook_ org, and the packages that are not in the org. The simplest way to check this is to ensure you can see the _"Settings"_ tab in the following packages:
|
||||
1. [`@storybook/react-vite`](https://www.npmjs.com/package/@storybook/react-vite/access)
|
||||
2. [`storybook`](https://www.npmjs.com/package/storybook/access)
|
||||
3. [`sb`](https://www.npmjs.com/package/sb/access)
|
||||
4. [`create-storybook`](https://www.npmjs.com/package/create-storybook/access)
|
||||
13. Get your npm access token or generate a new one at https://www.npmjs.com/settings/your-username/tokens. Remember to give it access to the `storybook` org and the packages not in the org, as listed above.
|
||||
14. Publish all packages with `YARN_NPM_AUTH_TOKEN=<NPM_TOKEN> yarn release:publish --tag tag-for-publishing-older-releases --verbose`
|
||||
- It goes through all packages and publishes them. If any number of packages fails to publish, it will retry 5 times, skipping those that have already been published.
|
||||
15. Confirm the new version has been released on npm with the tag `tag-for-publishing-older-releases`:
|
||||
1. [`@storybook/react-vite`](https://www.npmjs.com/package/@storybook/react-vite?activeTab=versions)
|
||||
2. [`storybook`](https://www.npmjs.com/package/storybook?activeTab=versions)
|
||||
3. [`sb`](https://www.npmjs.com/package/sb?activeTab=versions)
|
||||
4. [`create-storybook`](https://www.npmjs.com/package/create-storybook?activeTab=versions)
|
||||
16. Push
|
||||
17. Manually create a GitHub Release at https://github.com/storybookjs/storybook/releases/new with:
|
||||
1. Create new tag: `v<VERSION>` (e.g., `v8.3.7`)
|
||||
2. Target: your branch (e.g., `patch-8-3-7`)
|
||||
3. Previous tag: `v<PREVIOUS_VERSION>` (e.g., `v8.3.6`)
|
||||
4. Title: `v<VERSION>` (e.g., `v8.3.7`)
|
||||
5. Description: The content you added to `CHANGELOG.md`
|
||||
6. Untick _"Set as the latest release"_
|
||||
18. Cherry-pick your changelog changes into `next`, so they are actually visible
|
||||
1. Checkout the `next` branch
|
||||
2. Cherry-pick the commit you created with your changelog modifications
|
||||
3. Push
|
||||
|
||||
Done. 🎉
|
||||
|
||||
## Releasing Locally in an Emergency 🚨
|
||||
|
||||
Things can fail, code can break, and bugs can exist. When automation is broken, there may be a need for an emergency escape hatch to release new fixes. In such a situation, it's valid to run the whole release process locally instead of relying on pull requests and workflows. You don't need to create pull requests or split preparation and publishing; you can do it all at once, but make sure you still follow the correct branching strategy.
|
||||
|
@ -124,7 +124,7 @@ const Pure = memo(function PureTool(props: PureProps) {
|
||||
onHide();
|
||||
},
|
||||
})),
|
||||
]}
|
||||
].flat()}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
|
@ -36,7 +36,7 @@ Don't see your favorite tool listed? Don't worry! That doesn't mean this addon i
|
||||
|
||||
### ❗️ Overriding theme
|
||||
|
||||
If you want to override your theme for a particular component or story, you can use the `themes.themeOverride` parameter.
|
||||
If you want to override your theme for a particular component or story, you can use the `globals.theme` parameter.
|
||||
|
||||
```js
|
||||
import React from 'react';
|
||||
|
@ -139,7 +139,7 @@ const Pure = React.memo(function PureTool(props: PureProps) {
|
||||
onHide();
|
||||
},
|
||||
})),
|
||||
]}
|
||||
].flat()}
|
||||
/>
|
||||
)}
|
||||
closeOnOutsideClick
|
||||
|
@ -14,7 +14,7 @@ interface UpgradeBlockProps {
|
||||
|
||||
export const UpgradeBlock: FC<UpgradeBlockProps> = ({ onNavigateToWhatsNew }) => {
|
||||
const api = useStorybookApi();
|
||||
const [activeTab, setActiveTab] = useState<'npm' | 'pnpm'>('npm');
|
||||
const [activeTab, setActiveTab] = useState<'npm' | 'yarn' | 'pnpm'>('npm');
|
||||
|
||||
return (
|
||||
<Container>
|
||||
@ -24,12 +24,17 @@ export const UpgradeBlock: FC<UpgradeBlockProps> = ({ onNavigateToWhatsNew }) =>
|
||||
<ButtonTab active={activeTab === 'npm'} onClick={() => setActiveTab('npm')}>
|
||||
npm
|
||||
</ButtonTab>
|
||||
<ButtonTab active={activeTab === 'yarn'} onClick={() => setActiveTab('yarn')}>
|
||||
yarn
|
||||
</ButtonTab>
|
||||
<ButtonTab active={activeTab === 'pnpm'} onClick={() => setActiveTab('pnpm')}>
|
||||
pnpm
|
||||
</ButtonTab>
|
||||
</Tabs>
|
||||
<Code>
|
||||
{activeTab === 'npm' ? 'npx storybook@latest upgrade' : 'pnpm dlx storybook@latest upgrade'}
|
||||
{activeTab === 'npm'
|
||||
? 'npx storybook@latest upgrade'
|
||||
: `${activeTab} dlx storybook@latest upgrade`}
|
||||
</Code>
|
||||
{onNavigateToWhatsNew && (
|
||||
// eslint-disable-next-line jsx-a11y/anchor-is-valid
|
||||
|
@ -189,6 +189,10 @@ test.describe('addon-docs', () => {
|
||||
});
|
||||
|
||||
test('should resolve react to the correct version', async ({ page }) => {
|
||||
test.skip(
|
||||
templateName?.includes('nextjs'),
|
||||
'TODO: remove this once sandboxes are synced (SOON!!)'
|
||||
);
|
||||
// Arrange - Navigate to MDX docs
|
||||
const sbPage = new SbPage(page, expect);
|
||||
await sbPage.navigateToStory('addons/docs/docs2/resolvedreact', 'mdx', 'docs');
|
||||
@ -201,6 +205,7 @@ test.describe('addon-docs', () => {
|
||||
} else if (templateName.includes('react16')) {
|
||||
expectedReactVersionRange = /^16/;
|
||||
} else if (
|
||||
templateName.includes('nextjs/default-ts') ||
|
||||
templateName.includes('nextjs/prerelease') ||
|
||||
templateName.includes('react-vite/prerelease') ||
|
||||
templateName.includes('react-webpack/prerelease')
|
||||
|
@ -53,10 +53,7 @@ test.describe('Next.js', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
sbPage = new SbPage(page, expect);
|
||||
|
||||
await sbPage.navigateToStory(
|
||||
'stories/frameworks/nextjs-nextjs-default-ts/Navigation',
|
||||
'default'
|
||||
);
|
||||
await sbPage.navigateToStory('stories/frameworks/nextjs/Navigation', 'default');
|
||||
root = sbPage.previewRoot();
|
||||
});
|
||||
|
||||
@ -88,7 +85,7 @@ test.describe('Next.js', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
sbPage = new SbPage(page, expect);
|
||||
|
||||
await sbPage.navigateToStory('stories/frameworks/nextjs-nextjs-default-ts/Router', 'default');
|
||||
await sbPage.navigateToStory('stories/frameworks/nextjs/Router', 'default');
|
||||
root = sbPage.previewRoot();
|
||||
});
|
||||
|
||||
|
@ -57,6 +57,11 @@
|
||||
"import": "./dist/compatibility/redirect-status-code.compat.mjs",
|
||||
"require": "./dist/compatibility/redirect-status-code.compat.js"
|
||||
},
|
||||
"./dist/compatibility/draft-mode.compat": {
|
||||
"types": "./dist/compatibility/draft-mode.compat.d.ts",
|
||||
"import": "./dist/compatibility/draft-mode.compat.mjs",
|
||||
"require": "./dist/compatibility/draft-mode.compat.js"
|
||||
},
|
||||
"./export-mocks": {
|
||||
"types": "./dist/export-mocks/index.d.ts",
|
||||
"import": "./dist/export-mocks/index.mjs",
|
||||
@ -171,12 +176,12 @@
|
||||
"@types/babel__preset-env": "^7",
|
||||
"@types/loader-utils": "^2.0.5",
|
||||
"@types/react-refresh": "^0",
|
||||
"next": "^14.1.0",
|
||||
"next": "^15.0.3",
|
||||
"typescript": "^5.3.2",
|
||||
"webpack": "^5.65.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"next": "^13.5.0 || ^14.0.0",
|
||||
"next": "^13.5.0 || ^14.0.0 || ^15.0.0",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta",
|
||||
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta",
|
||||
"storybook": "workspace:^",
|
||||
@ -212,6 +217,7 @@
|
||||
"./src/export-mocks/navigation/index.ts",
|
||||
"./src/compatibility/segment.compat.ts",
|
||||
"./src/compatibility/redirect-status-code.compat.ts",
|
||||
"./src/compatibility/draft-mode.compat.ts",
|
||||
"./src/next-image-loader-stub.ts",
|
||||
"./src/images/decorator.tsx",
|
||||
"./src/images/next-legacy-image.tsx",
|
||||
|
@ -1,6 +1,12 @@
|
||||
import type { Configuration as WebpackConfig } from 'webpack';
|
||||
|
||||
import { configureCompatibilityAliases } from '../compatibility/compatibility-map';
|
||||
import { configureNextExportMocks } from '../export-mocks/webpack';
|
||||
|
||||
export const configureAliases = (baseConfig: WebpackConfig): void => {
|
||||
configureNextExportMocks(baseConfig);
|
||||
configureCompatibilityAliases(baseConfig);
|
||||
|
||||
baseConfig.resolve = {
|
||||
...(baseConfig.resolve ?? {}),
|
||||
alias: {
|
||||
@ -8,4 +14,12 @@ export const configureAliases = (baseConfig: WebpackConfig): void => {
|
||||
'@opentelemetry/api': 'next/dist/compiled/@opentelemetry/api',
|
||||
},
|
||||
};
|
||||
|
||||
// remove warnings regarding compatibility paths
|
||||
baseConfig.ignoreWarnings = [
|
||||
...(baseConfig.ignoreWarnings ?? []),
|
||||
(warning) =>
|
||||
warning.message.includes("export 'draftMode'") &&
|
||||
warning.message.includes('next/dist/server/request/headers'),
|
||||
];
|
||||
};
|
||||
|
@ -1,9 +1,9 @@
|
||||
import semver from 'semver';
|
||||
import type { Configuration as WebpackConfig } from 'webpack';
|
||||
|
||||
import { addScopedAlias, getNextjsVersion } from '../utils';
|
||||
import { addScopedAlias, getNextjsVersion, setAlias } from '../utils';
|
||||
|
||||
const mapping: Record<string, Record<string, string>> = {
|
||||
const mapping: Record<string, Record<string, string | boolean>> = {
|
||||
'<14.1.0': {
|
||||
// https://github.com/vercel/next.js/blob/v14.1.0/packages/next/src/shared/lib/segment.ts
|
||||
'next/dist/shared/lib/segment': '@storybook/nextjs/dist/compatibility/segment.compat',
|
||||
@ -13,6 +13,11 @@ const mapping: Record<string, Record<string, string>> = {
|
||||
'next/dist/client/components/redirect-status-code':
|
||||
'@storybook/nextjs/dist/compatibility/redirect-status-code.compat',
|
||||
},
|
||||
'<15.0.0': {
|
||||
'next/dist/server/request/headers': 'next/dist/client/components/headers',
|
||||
// this path only exists from Next 15 onwards
|
||||
'next/dist/server/request/draft-mode': '@storybook/nextjs/dist/compatibility/draft-mode.compat',
|
||||
},
|
||||
};
|
||||
|
||||
export const getCompatibilityAliases = () => {
|
||||
@ -32,6 +37,10 @@ export const configureCompatibilityAliases = (baseConfig: WebpackConfig): void =
|
||||
const aliases = getCompatibilityAliases();
|
||||
|
||||
Object.entries(aliases).forEach(([name, alias]) => {
|
||||
addScopedAlias(baseConfig, name, alias);
|
||||
if (typeof alias === 'string') {
|
||||
addScopedAlias(baseConfig, name, alias);
|
||||
} else {
|
||||
setAlias(baseConfig, name, alias);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -0,0 +1,2 @@
|
||||
// Compatibility for Next 14
|
||||
export { draftMode } from 'next/dist/client/components/headers';
|
@ -1,14 +1,16 @@
|
||||
import { fn } from '@storybook/test';
|
||||
|
||||
import * as originalHeaders from 'next/dist/client/components/headers';
|
||||
// This export won't exist in Next.js 14 but it's safe because we ignore it in Webpack when applicable
|
||||
import { draftMode as originalDraftMode } from 'next/dist/server/request/draft-mode';
|
||||
import * as headers from 'next/dist/server/request/headers';
|
||||
|
||||
// re-exports of the actual module
|
||||
export * from 'next/dist/client/components/headers';
|
||||
export * from 'next/dist/server/request/headers';
|
||||
|
||||
// mock utilities/overrides (as of Next v14.2.0)
|
||||
export { headers } from './headers';
|
||||
export { cookies } from './cookies';
|
||||
|
||||
// passthrough mocks - keep original implementation but allow for spying
|
||||
const draftMode = fn(originalHeaders.draftMode).mockName('draftMode');
|
||||
const draftMode = fn(originalDraftMode ?? (headers as any).draftMode).mockName('draftMode');
|
||||
export { draftMode };
|
||||
|
@ -23,14 +23,14 @@ export const getPackageAliases = ({ useESM = false }: { useESM?: boolean } = {})
|
||||
const packageLocation = dirname(require.resolve('@storybook/nextjs/package.json'));
|
||||
|
||||
const getFullPath = (path: string) =>
|
||||
join(packageLocation, path.replace('@storybook/nextjs', ''));
|
||||
path.startsWith('next') ? path : join(packageLocation, path.replace('@storybook/nextjs', ''));
|
||||
|
||||
const aliases = Object.fromEntries(
|
||||
Object.entries(mapping).map(([originalPath, aliasedPath]) => [
|
||||
originalPath,
|
||||
// Use paths for both next/xyz and @storybook/nextjs/xyz imports
|
||||
// to make sure they all serve the MJS/CJS version of the file
|
||||
getFullPath(`${aliasedPath}.${extension}`),
|
||||
typeof aliasedPath === 'string' ? getFullPath(`${aliasedPath}.${extension}`) : aliasedPath,
|
||||
])
|
||||
);
|
||||
|
||||
|
@ -162,8 +162,6 @@ export const webpackFinal: StorybookConfig['webpackFinal'] = async (baseConfig,
|
||||
configureStyledJsx(baseConfig);
|
||||
configureNodePolyfills(baseConfig);
|
||||
configureAliases(baseConfig);
|
||||
configureCompatibilityAliases(baseConfig);
|
||||
configureNextExportMocks(baseConfig);
|
||||
|
||||
if (isDevelopment) {
|
||||
configureFastRefresh(baseConfig);
|
||||
|
@ -18,11 +18,14 @@ import {
|
||||
PathnameContext,
|
||||
SearchParamsContext,
|
||||
} from 'next/dist/shared/lib/hooks-client-context.shared-runtime';
|
||||
import { type Params } from 'next/dist/shared/lib/router/utils/route-matcher';
|
||||
import { PAGE_SEGMENT_KEY } from 'next/dist/shared/lib/segment';
|
||||
|
||||
import type { RouteParams } from './types';
|
||||
|
||||
// Using an inline type so we can support Next 14 and lower
|
||||
// from https://github.com/vercel/next.js/blob/v15.0.3/packages/next/src/server/request/params.ts#L25
|
||||
type Params = Record<string, string | Array<string> | undefined>;
|
||||
|
||||
type AppRouterProviderProps = {
|
||||
routeParams: RouteParams;
|
||||
};
|
||||
|
@ -1,5 +1,7 @@
|
||||
import React, { Suspense } from 'react';
|
||||
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
import dynamic from 'next/dynamic';
|
||||
|
||||
const DynamicComponent = dynamic(() => import('./dynamic-component'), {
|
||||
@ -16,6 +18,6 @@ function Component() {
|
||||
|
||||
export default {
|
||||
component: Component,
|
||||
};
|
||||
} as Meta<typeof Component>;
|
||||
|
||||
export const Default = {};
|
||||
export const Default: StoryObj<typeof Component> = {};
|
27
code/frameworks/nextjs/template/stories/Font.stories.tsx
Normal file
27
code/frameworks/nextjs/template/stories/Font.stories.tsx
Normal file
@ -0,0 +1,27 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
import Font from './Font';
|
||||
|
||||
export default {
|
||||
component: Font,
|
||||
} as Meta<typeof Font>;
|
||||
|
||||
type Story = StoryObj<typeof Font>;
|
||||
|
||||
export const WithClassName: Story = {
|
||||
args: {
|
||||
variant: 'className',
|
||||
},
|
||||
};
|
||||
|
||||
export const WithStyle: Story = {
|
||||
args: {
|
||||
variant: 'style',
|
||||
},
|
||||
};
|
||||
|
||||
export const WithVariable: Story = {
|
||||
args: {
|
||||
variant: 'variable',
|
||||
},
|
||||
};
|
@ -1,4 +1,3 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import React from 'react';
|
||||
|
||||
import { Rubik_Puddles } from 'next/font/google';
|
||||
@ -15,7 +14,7 @@ export const localRubikStorm = localFont({
|
||||
variable: '--font-rubik-storm',
|
||||
});
|
||||
|
||||
export default function Font({ variant }) {
|
||||
export default function Font({ variant }: { variant: 'className' | 'style' | 'variable' }) {
|
||||
switch (variant) {
|
||||
case 'className':
|
||||
return (
|
@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { expect, waitFor } from '@storybook/test';
|
||||
|
||||
import Head from 'next/head';
|
||||
@ -21,14 +22,14 @@ function Component() {
|
||||
|
||||
export default {
|
||||
component: Component,
|
||||
};
|
||||
} as Meta<typeof Component>;
|
||||
|
||||
export const Default = {
|
||||
export const Default: StoryObj<typeof Component> = {
|
||||
play: async () => {
|
||||
await waitFor(() => expect(document.title).toEqual('Next.js Head Title'));
|
||||
await expect(document.querySelectorAll('meta[property="og:title"]')).toHaveLength(1);
|
||||
await expect(document.querySelector('meta[property="og:title"]').content).toEqual(
|
||||
'My new title'
|
||||
);
|
||||
await expect(
|
||||
(document.querySelector('meta[property="og:title"]') as HTMLMetaElement)?.content
|
||||
).toEqual('My new title');
|
||||
},
|
||||
};
|
@ -1,4 +1,6 @@
|
||||
import React, { useRef, useState } from 'react';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
import Image from 'next/image';
|
||||
|
||||
@ -11,24 +13,26 @@ export default {
|
||||
src: Accessibility,
|
||||
alt: 'Accessibility',
|
||||
},
|
||||
};
|
||||
} as Meta<typeof Image>;
|
||||
|
||||
export const Default = {};
|
||||
type Story = StoryObj<typeof Image>;
|
||||
|
||||
export const Avif = {
|
||||
export const Default: Story = {};
|
||||
|
||||
export const Avif: Story = {
|
||||
args: {
|
||||
src: AvifImage,
|
||||
alt: 'Avif Test Image',
|
||||
},
|
||||
};
|
||||
|
||||
export const BlurredPlaceholder = {
|
||||
export const BlurredPlaceholder: Story = {
|
||||
args: {
|
||||
placeholder: 'blur',
|
||||
},
|
||||
};
|
||||
|
||||
export const BlurredAbsolutePlaceholder = {
|
||||
export const BlurredAbsolutePlaceholder: Story = {
|
||||
args: {
|
||||
src: 'https://storybook.js.org/images/placeholders/50x50.png',
|
||||
width: 50,
|
||||
@ -44,26 +48,26 @@ export const BlurredAbsolutePlaceholder = {
|
||||
},
|
||||
};
|
||||
|
||||
export const FilledParent = {
|
||||
export const FilledParent: Story = {
|
||||
args: {
|
||||
fill: true,
|
||||
},
|
||||
decorator: [
|
||||
decorators: [
|
||||
(Story) => <div style={{ width: 500, height: 500, position: 'relative' }}>{Story()}</div>,
|
||||
],
|
||||
};
|
||||
|
||||
export const Sized = {
|
||||
export const Sized: Story = {
|
||||
args: {
|
||||
fill: true,
|
||||
sizes: '(max-width: 600px) 100vw, 600px',
|
||||
decorator: [
|
||||
(Story) => <div style={{ width: 800, height: 800, position: 'relative' }}>{Story()}</div>,
|
||||
],
|
||||
},
|
||||
decorators: [
|
||||
(Story) => <div style={{ width: 800, height: 800, position: 'relative' }}>{Story()}</div>,
|
||||
],
|
||||
};
|
||||
|
||||
export const Lazy = {
|
||||
export const Lazy: Story = {
|
||||
args: {
|
||||
src: 'https://storybook.js.org/images/placeholders/50x50.png',
|
||||
width: 50,
|
||||
@ -79,7 +83,7 @@ export const Lazy = {
|
||||
],
|
||||
};
|
||||
|
||||
export const Eager = {
|
||||
export const Eager: Story = {
|
||||
...Lazy,
|
||||
parameters: {
|
||||
nextjs: {
|
||||
@ -90,9 +94,9 @@ export const Eager = {
|
||||
},
|
||||
};
|
||||
|
||||
export const WithRef = {
|
||||
export const WithRef: Story = {
|
||||
render() {
|
||||
const [ref, setRef] = useState(null);
|
||||
const [ref, setRef] = useState<HTMLImageElement | null>(null);
|
||||
|
||||
return (
|
||||
<div>
|
@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
import Image from 'next/legacy/image';
|
||||
|
||||
@ -10,17 +10,19 @@ export default {
|
||||
src: Accessibility,
|
||||
alt: 'Accessibility',
|
||||
},
|
||||
};
|
||||
} as Meta<typeof Image>;
|
||||
|
||||
export const Default = {};
|
||||
type Story = StoryObj<typeof Image>;
|
||||
|
||||
export const BlurredPlaceholder = {
|
||||
export const Default: Story = {};
|
||||
|
||||
export const BlurredPlaceholder: Story = {
|
||||
args: {
|
||||
placeholder: 'blur',
|
||||
},
|
||||
};
|
||||
|
||||
export const BlurredAbsolutePlaceholder = {
|
||||
export const BlurredAbsolutePlaceholder: Story = {
|
||||
args: {
|
||||
src: 'https://storybook.js.org/images/placeholders/50x50.png',
|
||||
width: 50,
|
@ -76,9 +76,11 @@ export default {
|
||||
component: Component,
|
||||
} as Meta<typeof Component>;
|
||||
|
||||
export const Default: StoryObj<typeof Component> = {};
|
||||
type Story = StoryObj<typeof Component>;
|
||||
|
||||
export const InAppDir: StoryObj<typeof Component> = {
|
||||
export const Default: Story = {};
|
||||
|
||||
export const InAppDir: Story = {
|
||||
parameters: {
|
||||
nextjs: {
|
||||
appDirectory: true,
|
@ -108,7 +108,7 @@ export default {
|
||||
},
|
||||
} as Meta<typeof Component>;
|
||||
|
||||
export const Default: StoryObj<typeof Component> = {
|
||||
export const Default: Story = {
|
||||
play: async ({ canvasElement, step }) => {
|
||||
const canvas = within(canvasElement);
|
||||
const routerMock = getRouter();
|
@ -1,7 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import 'server-only';
|
||||
|
||||
export const RSC = async ({ label }) => <>RSC {label}</>;
|
||||
|
||||
export const Nested = async ({ children }) => <>Nested {children}</>;
|
@ -1,5 +1,8 @@
|
||||
/* eslint-disable local-rules/no-uncategorized-errors */
|
||||
import React from 'react';
|
||||
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
import { Nested, RSC } from './RSC';
|
||||
|
||||
export default {
|
||||
@ -10,11 +13,13 @@ export default {
|
||||
rsc: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
} as Meta<typeof RSC>;
|
||||
|
||||
export const Default = {};
|
||||
type Story = StoryObj<typeof RSC>;
|
||||
|
||||
export const DisableRSC = {
|
||||
export const Default: Story = {};
|
||||
|
||||
export const DisableRSC: Story = {
|
||||
tags: ['!test'],
|
||||
parameters: {
|
||||
chromatic: { disable: true },
|
||||
@ -22,7 +27,7 @@ export const DisableRSC = {
|
||||
},
|
||||
};
|
||||
|
||||
export const Error = {
|
||||
export const Errored: Story = {
|
||||
tags: ['!test'],
|
||||
parameters: {
|
||||
chromatic: { disable: true },
|
||||
@ -32,7 +37,7 @@ export const Error = {
|
||||
},
|
||||
};
|
||||
|
||||
export const NestedRSC = {
|
||||
export const NestedRSC: Story = {
|
||||
render: (args) => (
|
||||
<Nested>
|
||||
<RSC {...args} />
|
7
code/frameworks/nextjs/template/stories/RSC.tsx
Normal file
7
code/frameworks/nextjs/template/stories/RSC.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
import React from 'react';
|
||||
|
||||
import 'server-only';
|
||||
|
||||
export const RSC = async ({ label }: { label: string }) => <>RSC {label}</>;
|
||||
|
||||
export const Nested = async ({ children }: any) => <>Nested {children}</>;
|
@ -1,5 +1,7 @@
|
||||
import React from 'react';
|
||||
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
const Component = () => (
|
||||
<div>
|
||||
<style jsx>{`
|
||||
@ -15,6 +17,6 @@ const Component = () => (
|
||||
|
||||
export default {
|
||||
component: Component,
|
||||
};
|
||||
} as Meta<typeof Component>;
|
||||
|
||||
export const Default = {};
|
||||
export const Default: StoryObj<typeof Component> = {};
|
@ -1,23 +0,0 @@
|
||||
import Font from './Font';
|
||||
|
||||
export default {
|
||||
component: Font,
|
||||
};
|
||||
|
||||
export const WithClassName = {
|
||||
args: {
|
||||
variant: 'className',
|
||||
},
|
||||
};
|
||||
|
||||
export const WithStyle = {
|
||||
args: {
|
||||
variant: 'style',
|
||||
},
|
||||
};
|
||||
|
||||
export const WithVariable = {
|
||||
args: {
|
||||
variant: 'variable',
|
||||
},
|
||||
};
|
@ -1,83 +0,0 @@
|
||||
/* eslint-disable react/prop-types */
|
||||
import React from 'react';
|
||||
|
||||
import Link from 'next/link';
|
||||
|
||||
import style from './Link.stories.module.css';
|
||||
|
||||
// `onClick`, `href`, and `ref` need to be passed to the DOM element
|
||||
// for proper handling
|
||||
const MyButton = React.forwardRef(function Button({ onClick, href, children }, ref) {
|
||||
return (
|
||||
<a href={href} onClick={onClick} ref={ref}>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
});
|
||||
|
||||
const Component = () => (
|
||||
<ul>
|
||||
<li>
|
||||
<Link href="/">Normal Link</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link
|
||||
href={{
|
||||
pathname: '/with-url-object',
|
||||
query: { name: 'test' },
|
||||
}}
|
||||
>
|
||||
With URL Object
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href="/replace-url" replace>
|
||||
Replace the URL instead of push
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href="/legacy-behaviour" legacyBehavior>
|
||||
<a>Legacy behavior</a>
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href="/child-is-functional-component" passHref legacyBehavior>
|
||||
<MyButton>child is a functional component</MyButton>
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href="/#hashid" scroll={false}>
|
||||
Disables scrolling to the top
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href="/no-prefetch" prefetch={false}>
|
||||
No Prefetching
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link style={{ color: 'red' }} href="/with-style">
|
||||
With style
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link className={style.link} href="/with-classname">
|
||||
With className
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
);
|
||||
|
||||
export default {
|
||||
component: Component,
|
||||
};
|
||||
|
||||
export const Default = {};
|
||||
|
||||
export const InAppDir = {
|
||||
parameters: {
|
||||
nextjs: {
|
||||
appDirectory: true,
|
||||
},
|
||||
},
|
||||
};
|
@ -1,12 +1,14 @@
|
||||
import React from 'react';
|
||||
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
import { getImageProps } from 'next/image';
|
||||
|
||||
import Accessibility from '../../assets/accessibility.svg';
|
||||
import Testing from '../../assets/testing.png';
|
||||
|
||||
// referenced from https://nextjs.org/docs/pages/api-reference/components/image#theme-detection-picture
|
||||
const Component = (props) => {
|
||||
const Component = (props: any) => {
|
||||
const {
|
||||
props: { srcSet: dark },
|
||||
} = getImageProps({ src: Accessibility, ...props });
|
||||
@ -29,6 +31,6 @@ export default {
|
||||
args: {
|
||||
alt: 'getImageProps Example',
|
||||
},
|
||||
};
|
||||
} as Meta<typeof Component>;
|
||||
|
||||
export const Default = {};
|
||||
export const Default: StoryObj<typeof Component> = {};
|
@ -1,3 +0,0 @@
|
||||
.link {
|
||||
color: green;
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
import { cookies, headers } from '@storybook/nextjs/headers.mock';
|
||||
import type { Meta } from '@storybook/react';
|
||||
import type { StoryObj } from '@storybook/react';
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { expect, userEvent, within } from '@storybook/test';
|
||||
|
||||
import NextHeader from './NextHeader';
|
||||
|
@ -5,25 +5,23 @@ import { cookies, headers } from 'next/headers';
|
||||
export default async function Component() {
|
||||
async function handleClick() {
|
||||
'use server';
|
||||
cookies().set('user-id', 'encrypted-id');
|
||||
(await cookies()).set('user-id', 'encrypted-id');
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<h3>Cookies:</h3>
|
||||
{cookies()
|
||||
.getAll()
|
||||
.map(({ name, value }) => {
|
||||
return (
|
||||
<p key={name} style={{ display: 'flex', flexDirection: 'row', gap: 8 }}>
|
||||
<strong>Name:</strong> <span>{name}</span>
|
||||
<strong>Value:</strong> <span>{value}</span>
|
||||
</p>
|
||||
);
|
||||
})}
|
||||
{(await cookies()).getAll().map(({ name, value }) => {
|
||||
return (
|
||||
<p key={name} style={{ display: 'flex', flexDirection: 'row', gap: 8 }}>
|
||||
<strong>Name:</strong> <span>{name}</span>
|
||||
<strong>Value:</strong> <span>{value}</span>
|
||||
</p>
|
||||
);
|
||||
})}
|
||||
|
||||
<h3>Headers:</h3>
|
||||
{Array.from(headers().entries()).map(([name, value]: [string, string]) => {
|
||||
{Array.from((await headers()).entries()).map(([name, value]: [string, string]) => {
|
||||
return (
|
||||
<p key={name} style={{ display: 'flex', flexDirection: 'row', gap: 8 }}>
|
||||
<strong>Name:</strong> <span>{name}</span>
|
||||
|
@ -58,7 +58,9 @@ export default {
|
||||
},
|
||||
} as Meta<typeof Component>;
|
||||
|
||||
export const ProtectedWhileLoggedOut: StoryObj<typeof Component> = {
|
||||
type Story = StoryObj<typeof Component>;
|
||||
|
||||
export const ProtectedWhileLoggedOut: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
await userEvent.click(canvas.getByText('Access protected route'));
|
||||
@ -70,7 +72,7 @@ export const ProtectedWhileLoggedOut: StoryObj<typeof Component> = {
|
||||
},
|
||||
};
|
||||
|
||||
export const ProtectedWhileLoggedIn: StoryObj<typeof Component> = {
|
||||
export const ProtectedWhileLoggedIn: Story = {
|
||||
beforeEach() {
|
||||
cookies().set('user', 'storybookjs');
|
||||
},
|
||||
@ -86,7 +88,7 @@ export const ProtectedWhileLoggedIn: StoryObj<typeof Component> = {
|
||||
},
|
||||
};
|
||||
|
||||
export const Logout: StoryObj<typeof Component> = {
|
||||
export const Logout: Story = {
|
||||
beforeEach() {
|
||||
cookies().set('user', 'storybookjs');
|
||||
},
|
||||
@ -102,7 +104,7 @@ export const Logout: StoryObj<typeof Component> = {
|
||||
},
|
||||
};
|
||||
|
||||
export const Login: StoryObj<typeof Component> = {
|
||||
export const Login: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
await userEvent.click(canvas.getByText('Login'));
|
||||
|
@ -5,7 +5,7 @@ import { cookies } from 'next/headers';
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
export async function accessRoute() {
|
||||
const user = cookies().get('user');
|
||||
const user = (await cookies()).get('user');
|
||||
|
||||
if (!user) {
|
||||
redirect('/');
|
||||
@ -16,13 +16,13 @@ export async function accessRoute() {
|
||||
}
|
||||
|
||||
export async function logout() {
|
||||
cookies().delete('user');
|
||||
(await cookies()).delete('user');
|
||||
revalidatePath('/');
|
||||
redirect('/');
|
||||
}
|
||||
|
||||
export async function login() {
|
||||
cookies().set('user', 'storybookjs');
|
||||
(await cookies()).set('user', 'storybookjs');
|
||||
revalidatePath('/');
|
||||
redirect('/');
|
||||
}
|
||||
|
@ -0,0 +1,36 @@
|
||||
import React from 'react';
|
||||
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
import { getImageProps } from 'next/image';
|
||||
|
||||
import Accessibility from '../../assets/accessibility.svg';
|
||||
import Testing from '../../assets/testing.png';
|
||||
|
||||
// referenced from https://nextjs.org/docs/pages/api-reference/components/image#theme-detection-picture
|
||||
const Component = (props: any) => {
|
||||
const {
|
||||
props: { srcSet: dark },
|
||||
} = getImageProps({ src: Accessibility, ...props });
|
||||
const {
|
||||
// capture rest on one to spread to img as default; it doesn't matter which barring art direction
|
||||
props: { srcSet: light, ...rest },
|
||||
} = getImageProps({ src: Testing, ...props });
|
||||
|
||||
return (
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcSet={dark} />
|
||||
<source media="(prefers-color-scheme: light)" srcSet={light} />
|
||||
<img {...rest} />
|
||||
</picture>
|
||||
);
|
||||
};
|
||||
|
||||
export default {
|
||||
component: Component,
|
||||
args: {
|
||||
alt: 'getImageProps Example',
|
||||
},
|
||||
} as Meta<typeof Component>;
|
||||
|
||||
export const Default: StoryObj<typeof Component> = {};
|
@ -0,0 +1,51 @@
|
||||
import { cookies, headers } from '@storybook/nextjs/headers.mock';
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { expect, userEvent, within } from '@storybook/test';
|
||||
|
||||
import NextHeader from './NextHeader';
|
||||
|
||||
export default {
|
||||
component: NextHeader,
|
||||
parameters: {
|
||||
react: {
|
||||
rsc: true,
|
||||
},
|
||||
},
|
||||
} as Meta<typeof NextHeader>;
|
||||
|
||||
type Story = StoryObj<typeof NextHeader>;
|
||||
|
||||
export const Default: Story = {
|
||||
loaders: async () => {
|
||||
cookies().set('firstName', 'Jane');
|
||||
cookies().set({
|
||||
name: 'lastName',
|
||||
value: 'Doe',
|
||||
});
|
||||
headers().set('timezone', 'Central European Summer Time');
|
||||
},
|
||||
play: async ({ canvasElement, step }) => {
|
||||
const canvas = within(canvasElement);
|
||||
const headersMock = headers();
|
||||
const cookiesMock = cookies();
|
||||
await step('Cookie and header store apis are called upon rendering', async () => {
|
||||
await expect(cookiesMock.getAll).toHaveBeenCalled();
|
||||
await expect(headersMock.entries).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
await step('Upon clicking on submit, the user-id cookie is set', async () => {
|
||||
const submitButton = await canvas.findByRole('button');
|
||||
await userEvent.click(submitButton);
|
||||
|
||||
await expect(cookiesMock.set).toHaveBeenCalledWith('user-id', 'encrypted-id');
|
||||
});
|
||||
|
||||
await step('The user-id cookie is available in cookie and header stores', async () => {
|
||||
await expect(headersMock.get('cookie')).toContain('user-id=encrypted-id');
|
||||
await expect(cookiesMock.get('user-id')).toEqual({
|
||||
name: 'user-id',
|
||||
value: 'encrypted-id',
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
@ -0,0 +1,38 @@
|
||||
import React from 'react';
|
||||
|
||||
import { cookies, headers } from 'next/headers';
|
||||
|
||||
export default async function Component() {
|
||||
async function handleClick() {
|
||||
'use server';
|
||||
(await cookies()).set('user-id', 'encrypted-id');
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<h3>Cookies:</h3>
|
||||
{(await cookies()).getAll().map(({ name, value }) => {
|
||||
return (
|
||||
<p key={name} style={{ display: 'flex', flexDirection: 'row', gap: 8 }}>
|
||||
<strong>Name:</strong> <span>{name}</span>
|
||||
<strong>Value:</strong> <span>{value}</span>
|
||||
</p>
|
||||
);
|
||||
})}
|
||||
|
||||
<h3>Headers:</h3>
|
||||
{Array.from((await headers()).entries()).map(([name, value]: [string, string]) => {
|
||||
return (
|
||||
<p key={name} style={{ display: 'flex', flexDirection: 'row', gap: 8 }}>
|
||||
<strong>Name:</strong> <span>{name}</span>
|
||||
<strong>Value:</strong> <span>{value}</span>
|
||||
</p>
|
||||
);
|
||||
})}
|
||||
|
||||
<form action={handleClick}>
|
||||
<button>add user-id cookie</button>
|
||||
</form>
|
||||
</>
|
||||
);
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
import React from 'react';
|
||||
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { userEvent, within } from '@storybook/test';
|
||||
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
let state = 'Bug! Not invalidated';
|
||||
|
||||
export default {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<div>{state}</div>
|
||||
<form
|
||||
action={() => {
|
||||
state = 'State is invalidated successfully.';
|
||||
redirect('/');
|
||||
}}
|
||||
>
|
||||
<button>Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
parameters: {
|
||||
test: {
|
||||
// This is needed until Next will update to the React 19 beta: https://github.com/vercel/next.js/pull/65058
|
||||
// In the React 19 beta ErrorBoundary errors (such as redirect) are only logged, and not thrown.
|
||||
// We will also suspress console.error logs for re the console.error logs for redirect in the next framework.
|
||||
// Using the onCaughtError react root option:
|
||||
// react: {
|
||||
// rootOptions: {
|
||||
// onCaughtError(error: unknown) {
|
||||
// if (isNextRouterError(error)) return;
|
||||
// console.error(error);
|
||||
// },
|
||||
// },
|
||||
// See: code/frameworks/nextjs/src/preview.tsx
|
||||
dangerouslyIgnoreUnhandledErrors: true,
|
||||
},
|
||||
nextjs: {
|
||||
appDirectory: true,
|
||||
navigation: {
|
||||
pathname: '/',
|
||||
},
|
||||
},
|
||||
},
|
||||
tags: ['!test'],
|
||||
} as Meta;
|
||||
|
||||
export const SingletonStateGetsInvalidatedAfterRedirecting: StoryObj = {
|
||||
play: async ({ canvasElement, step }) => {
|
||||
const canvas = within(canvasElement);
|
||||
await userEvent.click(canvas.getByRole('button'));
|
||||
},
|
||||
};
|
@ -0,0 +1,118 @@
|
||||
import React from 'react';
|
||||
|
||||
import { revalidatePath } from '@storybook/nextjs/cache.mock';
|
||||
import { cookies } from '@storybook/nextjs/headers.mock';
|
||||
import { getRouter, redirect } from '@storybook/nextjs/navigation.mock';
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { expect, userEvent, waitFor, within } from '@storybook/test';
|
||||
|
||||
import { accessRoute, login, logout } from './server-actions';
|
||||
|
||||
function Component() {
|
||||
return (
|
||||
<div style={{ display: 'flex', gap: 8 }}>
|
||||
<form>
|
||||
<button type="submit" formAction={login}>
|
||||
Login
|
||||
</button>
|
||||
</form>
|
||||
<form>
|
||||
<button type="submit" formAction={logout}>
|
||||
Logout
|
||||
</button>
|
||||
</form>
|
||||
<form>
|
||||
<button type="submit" formAction={accessRoute}>
|
||||
Access protected route
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default {
|
||||
component: Component,
|
||||
tags: ['!test'],
|
||||
parameters: {
|
||||
nextjs: {
|
||||
appDirectory: true,
|
||||
navigation: {
|
||||
pathname: '/',
|
||||
},
|
||||
},
|
||||
test: {
|
||||
// This is needed until Next will update to the React 19 beta: https://github.com/vercel/next.js/pull/65058
|
||||
// In the React 19 beta ErrorBoundary errors (such as redirect) are only logged, and not thrown.
|
||||
// We will also suspress console.error logs for re the console.error logs for redirect in the next framework.
|
||||
// Using the onCaughtError react root option:
|
||||
// react: {
|
||||
// rootOptions: {
|
||||
// onCaughtError(error: unknown) {
|
||||
// if (isNextRouterError(error)) return;
|
||||
// console.error(error);
|
||||
// },
|
||||
// },
|
||||
// See: code/frameworks/nextjs/src/preview.tsx
|
||||
dangerouslyIgnoreUnhandledErrors: true,
|
||||
},
|
||||
},
|
||||
} as Meta<typeof Component>;
|
||||
|
||||
type Story = StoryObj<typeof Component>;
|
||||
|
||||
export const ProtectedWhileLoggedOut: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
await userEvent.click(canvas.getByText('Access protected route'));
|
||||
|
||||
await expect(cookies().get).toHaveBeenCalledWith('user');
|
||||
await expect(redirect).toHaveBeenCalledWith('/');
|
||||
|
||||
await waitFor(() => expect(getRouter().push).toHaveBeenCalled());
|
||||
},
|
||||
};
|
||||
|
||||
export const ProtectedWhileLoggedIn: Story = {
|
||||
beforeEach() {
|
||||
cookies().set('user', 'storybookjs');
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
await userEvent.click(canvas.getByText('Access protected route'));
|
||||
|
||||
await expect(cookies().get).toHaveBeenLastCalledWith('user');
|
||||
await expect(revalidatePath).toHaveBeenLastCalledWith('/');
|
||||
await expect(redirect).toHaveBeenLastCalledWith('/protected');
|
||||
|
||||
await waitFor(() => expect(getRouter().push).toHaveBeenCalled());
|
||||
},
|
||||
};
|
||||
|
||||
export const Logout: Story = {
|
||||
beforeEach() {
|
||||
cookies().set('user', 'storybookjs');
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
await userEvent.click(canvas.getByText('Logout'));
|
||||
await expect(cookies().delete).toHaveBeenCalled();
|
||||
await expect(revalidatePath).toHaveBeenCalledWith('/');
|
||||
await expect(redirect).toHaveBeenCalledWith('/');
|
||||
|
||||
await waitFor(() => expect(getRouter().push).toHaveBeenCalled());
|
||||
},
|
||||
};
|
||||
|
||||
export const Login: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
await userEvent.click(canvas.getByText('Login'));
|
||||
|
||||
await expect(cookies().set).toHaveBeenCalledWith('user', 'storybookjs');
|
||||
await expect(revalidatePath).toHaveBeenCalledWith('/');
|
||||
await expect(redirect).toHaveBeenCalledWith('/');
|
||||
|
||||
await waitFor(() => expect(getRouter().push).toHaveBeenCalled());
|
||||
},
|
||||
};
|
@ -0,0 +1,28 @@
|
||||
'use server';
|
||||
|
||||
import { revalidatePath } from 'next/cache';
|
||||
import { cookies } from 'next/headers';
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
export async function accessRoute() {
|
||||
const user = (await cookies()).get('user');
|
||||
|
||||
if (!user) {
|
||||
redirect('/');
|
||||
}
|
||||
|
||||
revalidatePath('/');
|
||||
redirect(`/protected`);
|
||||
}
|
||||
|
||||
export async function logout() {
|
||||
(await cookies()).delete('user');
|
||||
revalidatePath('/');
|
||||
redirect('/');
|
||||
}
|
||||
|
||||
export async function login() {
|
||||
(await cookies()).set('user', 'storybookjs');
|
||||
revalidatePath('/');
|
||||
redirect('/');
|
||||
}
|
14
code/frameworks/nextjs/template/typings.d.ts
vendored
Normal file
14
code/frameworks/nextjs/template/typings.d.ts
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
declare module '*.svg' {
|
||||
const content: string;
|
||||
export default content;
|
||||
}
|
||||
|
||||
declare module '*.avif' {
|
||||
const content: string;
|
||||
export default content;
|
||||
}
|
||||
|
||||
declare module '*.png' {
|
||||
const content: string;
|
||||
export default content;
|
||||
}
|
@ -156,10 +156,10 @@ const baseTemplates = {
|
||||
},
|
||||
skipTasks: ['e2e-tests-dev', 'bench', 'vitest-integration'],
|
||||
},
|
||||
'nextjs/default-js': {
|
||||
name: 'Next.js Latest (Webpack | JavaScript)',
|
||||
'nextjs/14-ts': {
|
||||
name: 'Next.js v14.2 (Webpack | TypeScript)',
|
||||
script:
|
||||
'npx create-next-app@^14 {{beforeDir}} --eslint --tailwind --app --import-alias="@/*" --src-dir',
|
||||
'yarn create next-app {{beforeDir}} -e https://github.com/vercel/next.js/tree/v14.2.17/examples/hello-world && cd {{beforeDir}} && npm pkg set "dependencies.next"="^14.2.17" && yarn && git add . && git commit --amend --no-edit && cd ..',
|
||||
expected: {
|
||||
framework: '@storybook/nextjs',
|
||||
renderer: '@storybook/react',
|
||||
@ -172,11 +172,12 @@ const baseTemplates = {
|
||||
extraDependencies: ['server-only', 'prop-types'],
|
||||
},
|
||||
skipTasks: ['e2e-tests-dev', 'bench', 'vitest-integration'],
|
||||
inDevelopment: true,
|
||||
},
|
||||
'nextjs/default-ts': {
|
||||
name: 'Next.js Latest (Webpack | TypeScript)',
|
||||
script:
|
||||
'npx create-next-app@^14 {{beforeDir}} --typescript --eslint --tailwind --app --import-alias="@/*" --src-dir',
|
||||
'npx create-next-app {{beforeDir}} --eslint --tailwind --app --import-alias="@/*" --src-dir',
|
||||
expected: {
|
||||
framework: '@storybook/nextjs',
|
||||
renderer: '@storybook/react',
|
||||
@ -193,7 +194,7 @@ const baseTemplates = {
|
||||
'nextjs/prerelease': {
|
||||
name: 'Next.js Prerelease (Webpack | TypeScript)',
|
||||
script:
|
||||
'npx create-next-app@canary {{beforeDir}} --typescript --eslint --tailwind --app --import-alias="@/*" --src-dir',
|
||||
'npx create-next-app@canary {{beforeDir}} --eslint --tailwind --app --import-alias="@/*" --src-dir',
|
||||
expected: {
|
||||
framework: '@storybook/nextjs',
|
||||
renderer: '@storybook/react',
|
||||
@ -210,7 +211,7 @@ const baseTemplates = {
|
||||
'experimental-nextjs-vite/default-ts': {
|
||||
name: 'Next.js Latest (Vite | TypeScript)',
|
||||
script:
|
||||
'npx create-next-app@^14 {{beforeDir}} --typescript --eslint --tailwind --app --import-alias="@/*" --src-dir',
|
||||
'npx create-next-app@^14 {{beforeDir}} --eslint --tailwind --app --import-alias="@/*" --src-dir',
|
||||
expected: {
|
||||
framework: '@storybook/experimental-nextjs-vite',
|
||||
renderer: '@storybook/react',
|
||||
@ -785,7 +786,6 @@ export const daily: TemplateKey[] = [
|
||||
'svelte-kit/prerelease-ts',
|
||||
'svelte-vite/default-js',
|
||||
'nextjs/13-ts',
|
||||
'nextjs/default-js',
|
||||
'nextjs/prerelease',
|
||||
'qwik-vite/default-ts',
|
||||
'preact-vite/default-js',
|
||||
|
@ -293,5 +293,6 @@
|
||||
"Dependency Upgrades"
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"deferredNextVersion": "8.5.0-alpha.4"
|
||||
}
|
||||
|
483
code/yarn.lock
483
code/yarn.lock
@ -2504,6 +2504,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@emnapi/runtime@npm:^1.2.0":
|
||||
version: 1.3.1
|
||||
resolution: "@emnapi/runtime@npm:1.3.1"
|
||||
dependencies:
|
||||
tslib: "npm:^2.4.0"
|
||||
checksum: 10c0/060ffede50f1b619c15083312b80a9e62a5b0c87aa8c1b54854c49766c9d69f8d1d3d87bd963a647071263a320db41b25eaa50b74d6a80dcc763c23dbeaafd6c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@emotion/babel-plugin@npm:^11.11.0":
|
||||
version: 11.11.0
|
||||
resolution: "@emotion/babel-plugin@npm:11.11.0"
|
||||
@ -3429,6 +3438,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-darwin-arm64@npm:0.33.5":
|
||||
version: 0.33.5
|
||||
resolution: "@img/sharp-darwin-arm64@npm:0.33.5"
|
||||
dependencies:
|
||||
"@img/sharp-libvips-darwin-arm64": "npm:1.0.4"
|
||||
dependenciesMeta:
|
||||
"@img/sharp-libvips-darwin-arm64":
|
||||
optional: true
|
||||
conditions: os=darwin & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-darwin-x64@npm:0.33.4":
|
||||
version: 0.33.4
|
||||
resolution: "@img/sharp-darwin-x64@npm:0.33.4"
|
||||
@ -3441,6 +3462,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-darwin-x64@npm:0.33.5":
|
||||
version: 0.33.5
|
||||
resolution: "@img/sharp-darwin-x64@npm:0.33.5"
|
||||
dependencies:
|
||||
"@img/sharp-libvips-darwin-x64": "npm:1.0.4"
|
||||
dependenciesMeta:
|
||||
"@img/sharp-libvips-darwin-x64":
|
||||
optional: true
|
||||
conditions: os=darwin & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-libvips-darwin-arm64@npm:1.0.2":
|
||||
version: 1.0.2
|
||||
resolution: "@img/sharp-libvips-darwin-arm64@npm:1.0.2"
|
||||
@ -3448,6 +3481,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-libvips-darwin-arm64@npm:1.0.4":
|
||||
version: 1.0.4
|
||||
resolution: "@img/sharp-libvips-darwin-arm64@npm:1.0.4"
|
||||
conditions: os=darwin & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-libvips-darwin-x64@npm:1.0.2":
|
||||
version: 1.0.2
|
||||
resolution: "@img/sharp-libvips-darwin-x64@npm:1.0.2"
|
||||
@ -3455,6 +3495,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-libvips-darwin-x64@npm:1.0.4":
|
||||
version: 1.0.4
|
||||
resolution: "@img/sharp-libvips-darwin-x64@npm:1.0.4"
|
||||
conditions: os=darwin & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-libvips-linux-arm64@npm:1.0.2":
|
||||
version: 1.0.2
|
||||
resolution: "@img/sharp-libvips-linux-arm64@npm:1.0.2"
|
||||
@ -3462,6 +3509,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-libvips-linux-arm64@npm:1.0.4":
|
||||
version: 1.0.4
|
||||
resolution: "@img/sharp-libvips-linux-arm64@npm:1.0.4"
|
||||
conditions: os=linux & cpu=arm64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-libvips-linux-arm@npm:1.0.2":
|
||||
version: 1.0.2
|
||||
resolution: "@img/sharp-libvips-linux-arm@npm:1.0.2"
|
||||
@ -3469,6 +3523,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-libvips-linux-arm@npm:1.0.5":
|
||||
version: 1.0.5
|
||||
resolution: "@img/sharp-libvips-linux-arm@npm:1.0.5"
|
||||
conditions: os=linux & cpu=arm & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-libvips-linux-s390x@npm:1.0.2":
|
||||
version: 1.0.2
|
||||
resolution: "@img/sharp-libvips-linux-s390x@npm:1.0.2"
|
||||
@ -3476,6 +3537,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-libvips-linux-s390x@npm:1.0.4":
|
||||
version: 1.0.4
|
||||
resolution: "@img/sharp-libvips-linux-s390x@npm:1.0.4"
|
||||
conditions: os=linux & cpu=s390x & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-libvips-linux-x64@npm:1.0.2":
|
||||
version: 1.0.2
|
||||
resolution: "@img/sharp-libvips-linux-x64@npm:1.0.2"
|
||||
@ -3483,6 +3551,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-libvips-linux-x64@npm:1.0.4":
|
||||
version: 1.0.4
|
||||
resolution: "@img/sharp-libvips-linux-x64@npm:1.0.4"
|
||||
conditions: os=linux & cpu=x64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-libvips-linuxmusl-arm64@npm:1.0.2":
|
||||
version: 1.0.2
|
||||
resolution: "@img/sharp-libvips-linuxmusl-arm64@npm:1.0.2"
|
||||
@ -3490,6 +3565,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-libvips-linuxmusl-arm64@npm:1.0.4":
|
||||
version: 1.0.4
|
||||
resolution: "@img/sharp-libvips-linuxmusl-arm64@npm:1.0.4"
|
||||
conditions: os=linux & cpu=arm64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-libvips-linuxmusl-x64@npm:1.0.2":
|
||||
version: 1.0.2
|
||||
resolution: "@img/sharp-libvips-linuxmusl-x64@npm:1.0.2"
|
||||
@ -3497,6 +3579,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-libvips-linuxmusl-x64@npm:1.0.4":
|
||||
version: 1.0.4
|
||||
resolution: "@img/sharp-libvips-linuxmusl-x64@npm:1.0.4"
|
||||
conditions: os=linux & cpu=x64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-linux-arm64@npm:0.33.4":
|
||||
version: 0.33.4
|
||||
resolution: "@img/sharp-linux-arm64@npm:0.33.4"
|
||||
@ -3509,6 +3598,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-linux-arm64@npm:0.33.5":
|
||||
version: 0.33.5
|
||||
resolution: "@img/sharp-linux-arm64@npm:0.33.5"
|
||||
dependencies:
|
||||
"@img/sharp-libvips-linux-arm64": "npm:1.0.4"
|
||||
dependenciesMeta:
|
||||
"@img/sharp-libvips-linux-arm64":
|
||||
optional: true
|
||||
conditions: os=linux & cpu=arm64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-linux-arm@npm:0.33.4":
|
||||
version: 0.33.4
|
||||
resolution: "@img/sharp-linux-arm@npm:0.33.4"
|
||||
@ -3521,6 +3622,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-linux-arm@npm:0.33.5":
|
||||
version: 0.33.5
|
||||
resolution: "@img/sharp-linux-arm@npm:0.33.5"
|
||||
dependencies:
|
||||
"@img/sharp-libvips-linux-arm": "npm:1.0.5"
|
||||
dependenciesMeta:
|
||||
"@img/sharp-libvips-linux-arm":
|
||||
optional: true
|
||||
conditions: os=linux & cpu=arm & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-linux-s390x@npm:0.33.4":
|
||||
version: 0.33.4
|
||||
resolution: "@img/sharp-linux-s390x@npm:0.33.4"
|
||||
@ -3533,6 +3646,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-linux-s390x@npm:0.33.5":
|
||||
version: 0.33.5
|
||||
resolution: "@img/sharp-linux-s390x@npm:0.33.5"
|
||||
dependencies:
|
||||
"@img/sharp-libvips-linux-s390x": "npm:1.0.4"
|
||||
dependenciesMeta:
|
||||
"@img/sharp-libvips-linux-s390x":
|
||||
optional: true
|
||||
conditions: os=linux & cpu=s390x & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-linux-x64@npm:0.33.4":
|
||||
version: 0.33.4
|
||||
resolution: "@img/sharp-linux-x64@npm:0.33.4"
|
||||
@ -3545,6 +3670,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-linux-x64@npm:0.33.5":
|
||||
version: 0.33.5
|
||||
resolution: "@img/sharp-linux-x64@npm:0.33.5"
|
||||
dependencies:
|
||||
"@img/sharp-libvips-linux-x64": "npm:1.0.4"
|
||||
dependenciesMeta:
|
||||
"@img/sharp-libvips-linux-x64":
|
||||
optional: true
|
||||
conditions: os=linux & cpu=x64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-linuxmusl-arm64@npm:0.33.4":
|
||||
version: 0.33.4
|
||||
resolution: "@img/sharp-linuxmusl-arm64@npm:0.33.4"
|
||||
@ -3557,6 +3694,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-linuxmusl-arm64@npm:0.33.5":
|
||||
version: 0.33.5
|
||||
resolution: "@img/sharp-linuxmusl-arm64@npm:0.33.5"
|
||||
dependencies:
|
||||
"@img/sharp-libvips-linuxmusl-arm64": "npm:1.0.4"
|
||||
dependenciesMeta:
|
||||
"@img/sharp-libvips-linuxmusl-arm64":
|
||||
optional: true
|
||||
conditions: os=linux & cpu=arm64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-linuxmusl-x64@npm:0.33.4":
|
||||
version: 0.33.4
|
||||
resolution: "@img/sharp-linuxmusl-x64@npm:0.33.4"
|
||||
@ -3569,6 +3718,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-linuxmusl-x64@npm:0.33.5":
|
||||
version: 0.33.5
|
||||
resolution: "@img/sharp-linuxmusl-x64@npm:0.33.5"
|
||||
dependencies:
|
||||
"@img/sharp-libvips-linuxmusl-x64": "npm:1.0.4"
|
||||
dependenciesMeta:
|
||||
"@img/sharp-libvips-linuxmusl-x64":
|
||||
optional: true
|
||||
conditions: os=linux & cpu=x64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-wasm32@npm:0.33.4":
|
||||
version: 0.33.4
|
||||
resolution: "@img/sharp-wasm32@npm:0.33.4"
|
||||
@ -3578,6 +3739,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-wasm32@npm:0.33.5":
|
||||
version: 0.33.5
|
||||
resolution: "@img/sharp-wasm32@npm:0.33.5"
|
||||
dependencies:
|
||||
"@emnapi/runtime": "npm:^1.2.0"
|
||||
conditions: cpu=wasm32
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-win32-ia32@npm:0.33.4":
|
||||
version: 0.33.4
|
||||
resolution: "@img/sharp-win32-ia32@npm:0.33.4"
|
||||
@ -3585,6 +3755,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-win32-ia32@npm:0.33.5":
|
||||
version: 0.33.5
|
||||
resolution: "@img/sharp-win32-ia32@npm:0.33.5"
|
||||
conditions: os=win32 & cpu=ia32
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-win32-x64@npm:0.33.4":
|
||||
version: 0.33.4
|
||||
resolution: "@img/sharp-win32-x64@npm:0.33.4"
|
||||
@ -3592,6 +3769,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@img/sharp-win32-x64@npm:0.33.5":
|
||||
version: 0.33.5
|
||||
resolution: "@img/sharp-win32-x64@npm:0.33.5"
|
||||
conditions: os=win32 & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@inquirer/confirm@npm:^3.0.0":
|
||||
version: 3.1.20
|
||||
resolution: "@inquirer/confirm@npm:3.1.20"
|
||||
@ -3908,72 +4092,142 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/env@npm:14.2.5, @next/env@npm:^14.2.5":
|
||||
"@next/env@npm:14.2.17":
|
||||
version: 14.2.17
|
||||
resolution: "@next/env@npm:14.2.17"
|
||||
checksum: 10c0/181998dfe06275a7f43c56847bfbc4c521a10bd0e4a223b5b0fa1f73c24b0a993daa7ee736b82cbc3a6b64b13d965f7452dd4fc47f0a99909a1aa150862f5b1e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/env@npm:15.0.3":
|
||||
version: 15.0.3
|
||||
resolution: "@next/env@npm:15.0.3"
|
||||
checksum: 10c0/63582fed80d6a28fff102c935095da71fd57ddf6b5f5d564e85ebdefdeb93298f7f7cf7d813c75b460c6627106717ea959b4c232939e7abb97d73d8b8467d4cd
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/env@npm:^14.2.5":
|
||||
version: 14.2.5
|
||||
resolution: "@next/env@npm:14.2.5"
|
||||
checksum: 10c0/63d8b88ac450b3c37940a9e2119a63a1074aca89908574ade6157a8aa295275dcb3ac5f69e00883fc55d0f12963b73b74e87ba32a5768a489f9609c6be57b699
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-darwin-arm64@npm:14.2.5":
|
||||
version: 14.2.5
|
||||
resolution: "@next/swc-darwin-arm64@npm:14.2.5"
|
||||
"@next/swc-darwin-arm64@npm:14.2.17":
|
||||
version: 14.2.17
|
||||
resolution: "@next/swc-darwin-arm64@npm:14.2.17"
|
||||
conditions: os=darwin & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-darwin-x64@npm:14.2.5":
|
||||
version: 14.2.5
|
||||
resolution: "@next/swc-darwin-x64@npm:14.2.5"
|
||||
"@next/swc-darwin-arm64@npm:15.0.3":
|
||||
version: 15.0.3
|
||||
resolution: "@next/swc-darwin-arm64@npm:15.0.3"
|
||||
conditions: os=darwin & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-darwin-x64@npm:14.2.17":
|
||||
version: 14.2.17
|
||||
resolution: "@next/swc-darwin-x64@npm:14.2.17"
|
||||
conditions: os=darwin & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-linux-arm64-gnu@npm:14.2.5":
|
||||
version: 14.2.5
|
||||
resolution: "@next/swc-linux-arm64-gnu@npm:14.2.5"
|
||||
"@next/swc-darwin-x64@npm:15.0.3":
|
||||
version: 15.0.3
|
||||
resolution: "@next/swc-darwin-x64@npm:15.0.3"
|
||||
conditions: os=darwin & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-linux-arm64-gnu@npm:14.2.17":
|
||||
version: 14.2.17
|
||||
resolution: "@next/swc-linux-arm64-gnu@npm:14.2.17"
|
||||
conditions: os=linux & cpu=arm64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-linux-arm64-musl@npm:14.2.5":
|
||||
version: 14.2.5
|
||||
resolution: "@next/swc-linux-arm64-musl@npm:14.2.5"
|
||||
"@next/swc-linux-arm64-gnu@npm:15.0.3":
|
||||
version: 15.0.3
|
||||
resolution: "@next/swc-linux-arm64-gnu@npm:15.0.3"
|
||||
conditions: os=linux & cpu=arm64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-linux-arm64-musl@npm:14.2.17":
|
||||
version: 14.2.17
|
||||
resolution: "@next/swc-linux-arm64-musl@npm:14.2.17"
|
||||
conditions: os=linux & cpu=arm64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-linux-x64-gnu@npm:14.2.5":
|
||||
version: 14.2.5
|
||||
resolution: "@next/swc-linux-x64-gnu@npm:14.2.5"
|
||||
"@next/swc-linux-arm64-musl@npm:15.0.3":
|
||||
version: 15.0.3
|
||||
resolution: "@next/swc-linux-arm64-musl@npm:15.0.3"
|
||||
conditions: os=linux & cpu=arm64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-linux-x64-gnu@npm:14.2.17":
|
||||
version: 14.2.17
|
||||
resolution: "@next/swc-linux-x64-gnu@npm:14.2.17"
|
||||
conditions: os=linux & cpu=x64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-linux-x64-musl@npm:14.2.5":
|
||||
version: 14.2.5
|
||||
resolution: "@next/swc-linux-x64-musl@npm:14.2.5"
|
||||
"@next/swc-linux-x64-gnu@npm:15.0.3":
|
||||
version: 15.0.3
|
||||
resolution: "@next/swc-linux-x64-gnu@npm:15.0.3"
|
||||
conditions: os=linux & cpu=x64 & libc=glibc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-linux-x64-musl@npm:14.2.17":
|
||||
version: 14.2.17
|
||||
resolution: "@next/swc-linux-x64-musl@npm:14.2.17"
|
||||
conditions: os=linux & cpu=x64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-win32-arm64-msvc@npm:14.2.5":
|
||||
version: 14.2.5
|
||||
resolution: "@next/swc-win32-arm64-msvc@npm:14.2.5"
|
||||
"@next/swc-linux-x64-musl@npm:15.0.3":
|
||||
version: 15.0.3
|
||||
resolution: "@next/swc-linux-x64-musl@npm:15.0.3"
|
||||
conditions: os=linux & cpu=x64 & libc=musl
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-win32-arm64-msvc@npm:14.2.17":
|
||||
version: 14.2.17
|
||||
resolution: "@next/swc-win32-arm64-msvc@npm:14.2.17"
|
||||
conditions: os=win32 & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-win32-ia32-msvc@npm:14.2.5":
|
||||
version: 14.2.5
|
||||
resolution: "@next/swc-win32-ia32-msvc@npm:14.2.5"
|
||||
"@next/swc-win32-arm64-msvc@npm:15.0.3":
|
||||
version: 15.0.3
|
||||
resolution: "@next/swc-win32-arm64-msvc@npm:15.0.3"
|
||||
conditions: os=win32 & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-win32-ia32-msvc@npm:14.2.17":
|
||||
version: 14.2.17
|
||||
resolution: "@next/swc-win32-ia32-msvc@npm:14.2.17"
|
||||
conditions: os=win32 & cpu=ia32
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-win32-x64-msvc@npm:14.2.5":
|
||||
version: 14.2.5
|
||||
resolution: "@next/swc-win32-x64-msvc@npm:14.2.5"
|
||||
"@next/swc-win32-x64-msvc@npm:14.2.17":
|
||||
version: 14.2.17
|
||||
resolution: "@next/swc-win32-x64-msvc@npm:14.2.17"
|
||||
conditions: os=win32 & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@next/swc-win32-x64-msvc@npm:15.0.3":
|
||||
version: 15.0.3
|
||||
resolution: "@next/swc-win32-x64-msvc@npm:15.0.3"
|
||||
conditions: os=win32 & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
@ -6477,7 +6731,7 @@ __metadata:
|
||||
find-up: "npm:^5.0.0"
|
||||
image-size: "npm:^1.0.0"
|
||||
loader-utils: "npm:^3.2.1"
|
||||
next: "npm:^14.1.0"
|
||||
next: "npm:^15.0.3"
|
||||
node-polyfill-webpack-plugin: "npm:^2.0.1"
|
||||
pnp-webpack-plugin: "npm:^1.7.0"
|
||||
postcss: "npm:^8.4.38"
|
||||
@ -6495,7 +6749,7 @@ __metadata:
|
||||
typescript: "npm:^5.3.2"
|
||||
webpack: "npm:^5.65.0"
|
||||
peerDependencies:
|
||||
next: ^13.5.0 || ^14.0.0
|
||||
next: ^13.5.0 || ^14.0.0 || ^15.0.0
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
|
||||
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
|
||||
storybook: "workspace:^"
|
||||
@ -7343,13 +7597,22 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/counter@npm:^0.1.3":
|
||||
"@swc/counter@npm:0.1.3, @swc/counter@npm:^0.1.3":
|
||||
version: 0.1.3
|
||||
resolution: "@swc/counter@npm:0.1.3"
|
||||
checksum: 10c0/8424f60f6bf8694cfd2a9bca45845bce29f26105cda8cf19cdb9fd3e78dc6338699e4db77a89ae449260bafa1cc6bec307e81e7fb96dbf7dcfce0eea55151356
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/helpers@npm:0.5.13":
|
||||
version: 0.5.13
|
||||
resolution: "@swc/helpers@npm:0.5.13"
|
||||
dependencies:
|
||||
tslib: "npm:^2.4.0"
|
||||
checksum: 10c0/b9df578401fc62405da9a6c31e79e447a2fd90f68b25b1daee12f2caf2821991bb89106f0397bc1acb4c4d84a8ce079d04b60b65f534496952e3bf8c9a52f40f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@swc/helpers@npm:0.5.5":
|
||||
version: 0.5.5
|
||||
resolution: "@swc/helpers@npm:0.5.5"
|
||||
@ -21267,20 +21530,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"next@npm:^14.1.0, next@npm:^14.2.5":
|
||||
version: 14.2.5
|
||||
resolution: "next@npm:14.2.5"
|
||||
"next@npm:^14.2.5":
|
||||
version: 14.2.17
|
||||
resolution: "next@npm:14.2.17"
|
||||
dependencies:
|
||||
"@next/env": "npm:14.2.5"
|
||||
"@next/swc-darwin-arm64": "npm:14.2.5"
|
||||
"@next/swc-darwin-x64": "npm:14.2.5"
|
||||
"@next/swc-linux-arm64-gnu": "npm:14.2.5"
|
||||
"@next/swc-linux-arm64-musl": "npm:14.2.5"
|
||||
"@next/swc-linux-x64-gnu": "npm:14.2.5"
|
||||
"@next/swc-linux-x64-musl": "npm:14.2.5"
|
||||
"@next/swc-win32-arm64-msvc": "npm:14.2.5"
|
||||
"@next/swc-win32-ia32-msvc": "npm:14.2.5"
|
||||
"@next/swc-win32-x64-msvc": "npm:14.2.5"
|
||||
"@next/env": "npm:14.2.17"
|
||||
"@next/swc-darwin-arm64": "npm:14.2.17"
|
||||
"@next/swc-darwin-x64": "npm:14.2.17"
|
||||
"@next/swc-linux-arm64-gnu": "npm:14.2.17"
|
||||
"@next/swc-linux-arm64-musl": "npm:14.2.17"
|
||||
"@next/swc-linux-x64-gnu": "npm:14.2.17"
|
||||
"@next/swc-linux-x64-musl": "npm:14.2.17"
|
||||
"@next/swc-win32-arm64-msvc": "npm:14.2.17"
|
||||
"@next/swc-win32-ia32-msvc": "npm:14.2.17"
|
||||
"@next/swc-win32-x64-msvc": "npm:14.2.17"
|
||||
"@swc/helpers": "npm:0.5.5"
|
||||
busboy: "npm:1.6.0"
|
||||
caniuse-lite: "npm:^1.0.30001579"
|
||||
@ -21321,7 +21584,68 @@ __metadata:
|
||||
optional: true
|
||||
bin:
|
||||
next: dist/bin/next
|
||||
checksum: 10c0/8df7d8ccc1a5bab03fa50dd6656c8a6f3750e81ef0b087dc329fea9346847c3094a933a890a8e87151dc32f0bc55020b8f6386d4565856d83bcc10895d29ec08
|
||||
checksum: 10c0/ee350c1de7709da9a240752ebb8f56e0a01bbeae43177a43a463dd1d4ed071c414899afb3ff2d4228e38afa4029f0e0f0b56d9939b0f4a1bf383f77f32ec5ad9
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"next@npm:^15.0.3":
|
||||
version: 15.0.3
|
||||
resolution: "next@npm:15.0.3"
|
||||
dependencies:
|
||||
"@next/env": "npm:15.0.3"
|
||||
"@next/swc-darwin-arm64": "npm:15.0.3"
|
||||
"@next/swc-darwin-x64": "npm:15.0.3"
|
||||
"@next/swc-linux-arm64-gnu": "npm:15.0.3"
|
||||
"@next/swc-linux-arm64-musl": "npm:15.0.3"
|
||||
"@next/swc-linux-x64-gnu": "npm:15.0.3"
|
||||
"@next/swc-linux-x64-musl": "npm:15.0.3"
|
||||
"@next/swc-win32-arm64-msvc": "npm:15.0.3"
|
||||
"@next/swc-win32-x64-msvc": "npm:15.0.3"
|
||||
"@swc/counter": "npm:0.1.3"
|
||||
"@swc/helpers": "npm:0.5.13"
|
||||
busboy: "npm:1.6.0"
|
||||
caniuse-lite: "npm:^1.0.30001579"
|
||||
postcss: "npm:8.4.31"
|
||||
sharp: "npm:^0.33.5"
|
||||
styled-jsx: "npm:5.1.6"
|
||||
peerDependencies:
|
||||
"@opentelemetry/api": ^1.1.0
|
||||
"@playwright/test": ^1.41.2
|
||||
babel-plugin-react-compiler: "*"
|
||||
react: ^18.2.0 || 19.0.0-rc-66855b96-20241106
|
||||
react-dom: ^18.2.0 || 19.0.0-rc-66855b96-20241106
|
||||
sass: ^1.3.0
|
||||
dependenciesMeta:
|
||||
"@next/swc-darwin-arm64":
|
||||
optional: true
|
||||
"@next/swc-darwin-x64":
|
||||
optional: true
|
||||
"@next/swc-linux-arm64-gnu":
|
||||
optional: true
|
||||
"@next/swc-linux-arm64-musl":
|
||||
optional: true
|
||||
"@next/swc-linux-x64-gnu":
|
||||
optional: true
|
||||
"@next/swc-linux-x64-musl":
|
||||
optional: true
|
||||
"@next/swc-win32-arm64-msvc":
|
||||
optional: true
|
||||
"@next/swc-win32-x64-msvc":
|
||||
optional: true
|
||||
sharp:
|
||||
optional: true
|
||||
peerDependenciesMeta:
|
||||
"@opentelemetry/api":
|
||||
optional: true
|
||||
"@playwright/test":
|
||||
optional: true
|
||||
babel-plugin-react-compiler:
|
||||
optional: true
|
||||
sass:
|
||||
optional: true
|
||||
bin:
|
||||
next: dist/bin/next
|
||||
checksum: 10c0/c5f6a57acb5f29063abc82d4d4417a048d0c2d5216d6ded6aa3fe32d60bb4835ed57dd34e2ef8fdda15579e97205820dc25bf34556b1d942a01a33d9ae7f88db
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -25724,6 +26048,75 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"sharp@npm:^0.33.5":
|
||||
version: 0.33.5
|
||||
resolution: "sharp@npm:0.33.5"
|
||||
dependencies:
|
||||
"@img/sharp-darwin-arm64": "npm:0.33.5"
|
||||
"@img/sharp-darwin-x64": "npm:0.33.5"
|
||||
"@img/sharp-libvips-darwin-arm64": "npm:1.0.4"
|
||||
"@img/sharp-libvips-darwin-x64": "npm:1.0.4"
|
||||
"@img/sharp-libvips-linux-arm": "npm:1.0.5"
|
||||
"@img/sharp-libvips-linux-arm64": "npm:1.0.4"
|
||||
"@img/sharp-libvips-linux-s390x": "npm:1.0.4"
|
||||
"@img/sharp-libvips-linux-x64": "npm:1.0.4"
|
||||
"@img/sharp-libvips-linuxmusl-arm64": "npm:1.0.4"
|
||||
"@img/sharp-libvips-linuxmusl-x64": "npm:1.0.4"
|
||||
"@img/sharp-linux-arm": "npm:0.33.5"
|
||||
"@img/sharp-linux-arm64": "npm:0.33.5"
|
||||
"@img/sharp-linux-s390x": "npm:0.33.5"
|
||||
"@img/sharp-linux-x64": "npm:0.33.5"
|
||||
"@img/sharp-linuxmusl-arm64": "npm:0.33.5"
|
||||
"@img/sharp-linuxmusl-x64": "npm:0.33.5"
|
||||
"@img/sharp-wasm32": "npm:0.33.5"
|
||||
"@img/sharp-win32-ia32": "npm:0.33.5"
|
||||
"@img/sharp-win32-x64": "npm:0.33.5"
|
||||
color: "npm:^4.2.3"
|
||||
detect-libc: "npm:^2.0.3"
|
||||
semver: "npm:^7.6.3"
|
||||
dependenciesMeta:
|
||||
"@img/sharp-darwin-arm64":
|
||||
optional: true
|
||||
"@img/sharp-darwin-x64":
|
||||
optional: true
|
||||
"@img/sharp-libvips-darwin-arm64":
|
||||
optional: true
|
||||
"@img/sharp-libvips-darwin-x64":
|
||||
optional: true
|
||||
"@img/sharp-libvips-linux-arm":
|
||||
optional: true
|
||||
"@img/sharp-libvips-linux-arm64":
|
||||
optional: true
|
||||
"@img/sharp-libvips-linux-s390x":
|
||||
optional: true
|
||||
"@img/sharp-libvips-linux-x64":
|
||||
optional: true
|
||||
"@img/sharp-libvips-linuxmusl-arm64":
|
||||
optional: true
|
||||
"@img/sharp-libvips-linuxmusl-x64":
|
||||
optional: true
|
||||
"@img/sharp-linux-arm":
|
||||
optional: true
|
||||
"@img/sharp-linux-arm64":
|
||||
optional: true
|
||||
"@img/sharp-linux-s390x":
|
||||
optional: true
|
||||
"@img/sharp-linux-x64":
|
||||
optional: true
|
||||
"@img/sharp-linuxmusl-arm64":
|
||||
optional: true
|
||||
"@img/sharp-linuxmusl-x64":
|
||||
optional: true
|
||||
"@img/sharp-wasm32":
|
||||
optional: true
|
||||
"@img/sharp-win32-ia32":
|
||||
optional: true
|
||||
"@img/sharp-win32-x64":
|
||||
optional: true
|
||||
checksum: 10c0/6b81421ddfe6ee524d8d77e325c5e147fef22884e1c7b1656dfd89a88d7025894115da02d5f984261bf2e6daa16f98cadd1721c4ba408b4212b1d2a60f233484
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"shebang-command@npm:^1.2.0":
|
||||
version: 1.2.0
|
||||
resolution: "shebang-command@npm:1.2.0"
|
||||
|
@ -10,7 +10,7 @@ Contribute a new feature or bug fix to [Storybook's monorepo](https://github.com
|
||||
## Prerequisites
|
||||
|
||||
* Ensure you have Node version 18 installed (suggestion: v18.16.0).
|
||||
* Ensure if you are using Windows to use the Windows Subsystem for Linux (WSL).
|
||||
* If you're working with Windows, all commands should be run in a terminal with administrator privileges.
|
||||
|
||||
## Initial setup
|
||||
|
||||
|
@ -1 +1 @@
|
||||
{"version":"8.5.0-alpha.3","info":{"plain":"- Addon Test: Fix post-install logic for Next.js Vite framework support - [#29524](https://github.com/storybookjs/storybook/pull/29524), thanks @valentinpalkovic!\n- Core: Prevent clipping box shadow on file search modal - [#29523](https://github.com/storybookjs/storybook/pull/29523), thanks @ghengeveld!"}}
|
||||
{"version":"8.5.0-alpha.4","info":{"plain":"- Next.js: Add support for Next 15 - [#29587](https://github.com/storybookjs/storybook/pull/29587), thanks @yannbf!\n- UI: Add Yarn to About Section - [#29225](https://github.com/storybookjs/storybook/pull/29225), thanks @grantwforsythe!"}}
|
||||
|
@ -15,7 +15,7 @@
|
||||
"upload-bench": "cd scripts; yarn upload-bench",
|
||||
"vite-ecosystem-ci:before-test": "node ./scripts/vite-ecosystem-ci/before-test.js && cd ./sandbox/react-vite-default-ts && yarn install",
|
||||
"vite-ecosystem-ci:build": "yarn task --task sandbox --template react-vite/default-ts --start-from=install",
|
||||
"vite-ecosystem-ci:test": "yarn task --task test-runner-dev --template react-vite/default-ts --start-from=dev"
|
||||
"vite-ecosystem-ci:test": "yarn task --task test-runner-dev --template react-vite/default-ts --start-from=dev && yarn task --task test-runner --template react-vite/default-ts --start-from=build"
|
||||
},
|
||||
"packageManager": "yarn@4.4.0+sha512.91d93b445d9284e7ed52931369bc89a663414e5582d00eea45c67ddc459a2582919eece27c412d6ffd1bd0793ff35399381cb229326b961798ce4f4cc60ddfdb"
|
||||
}
|
||||
|
493
scripts/bench/bench-packages.ts
Normal file
493
scripts/bench/bench-packages.ts
Normal file
@ -0,0 +1,493 @@
|
||||
import { BigQuery } from '@google-cloud/bigquery';
|
||||
import { InvalidArgumentError, program } from 'commander';
|
||||
import detectFreePort from 'detect-port';
|
||||
import { mkdir, readdir, rm, stat, writeFile } from 'fs/promises';
|
||||
import pLimit from 'p-limit';
|
||||
import { join } from 'path';
|
||||
import picocolors from 'picocolors';
|
||||
import { x } from 'tinyexec';
|
||||
import dedent from 'ts-dedent';
|
||||
|
||||
import versions from '../../code/core/src/common/versions';
|
||||
import { maxConcurrentTasks } from '../utils/concurrency';
|
||||
import { esMain } from '../utils/esmain';
|
||||
|
||||
const Thresholds = {
|
||||
SELF_SIZE_RATIO: 0.1,
|
||||
SELF_SIZE_ABSOLUTE: 10_000,
|
||||
DEPS_SIZE_RATIO: 0.1,
|
||||
DEPS_SIZE_ABSOLUTE: 10_000,
|
||||
DEPS_COUNT_ABSOLUTE: 1,
|
||||
} as const;
|
||||
|
||||
const BENCH_PACKAGES_PATH = join(__dirname, '..', '..', 'bench', 'packages');
|
||||
const REGISTRY_PORT = 6001;
|
||||
const GCP_CREDENTIALS = JSON.parse(process.env.GCP_CREDENTIALS || '{}');
|
||||
const bigQueryBenchTable = new BigQuery({
|
||||
projectId: GCP_CREDENTIALS.project_id,
|
||||
credentials: GCP_CREDENTIALS,
|
||||
})
|
||||
.dataset('benchmark_results')
|
||||
.table('package_bench');
|
||||
|
||||
type PackageName = keyof typeof versions;
|
||||
type Result = {
|
||||
package: PackageName;
|
||||
dependencyCount: number;
|
||||
selfSize: number;
|
||||
dependencySize: number;
|
||||
};
|
||||
type ComparisonResult = {
|
||||
package: PackageName;
|
||||
dependencyCount: {
|
||||
base: number;
|
||||
new: number;
|
||||
diff: number;
|
||||
};
|
||||
selfSize: {
|
||||
base: number;
|
||||
new: number;
|
||||
diff: number;
|
||||
};
|
||||
dependencySize: {
|
||||
base: number;
|
||||
new: number;
|
||||
diff: number;
|
||||
};
|
||||
};
|
||||
type ResultMap = Record<PackageName, Result>;
|
||||
type ComparisonResultMap = Record<PackageName, ComparisonResult>;
|
||||
|
||||
/**
|
||||
* This function benchmarks the size of Storybook packages and their dependencies. For each package,
|
||||
* the steps are:
|
||||
*
|
||||
* 1. Create a temporary directory in /bench/packages and create a package.json file that only depends
|
||||
* on that one package
|
||||
* 2. Install the package and its dependencies, without peer dependencies
|
||||
* 3. Measure the size of the package and its dependencies, and count the number of dependencies
|
||||
* (including transitive)
|
||||
* 4. Print and return the results
|
||||
*/
|
||||
export const benchPackage = async (packageName: PackageName) => {
|
||||
console.log(`Benching ${picocolors.blue(packageName)}...`);
|
||||
const tmpBenchPackagePath = join(BENCH_PACKAGES_PATH, packageName.replace('@storybook', ''));
|
||||
|
||||
await rm(tmpBenchPackagePath, { recursive: true }).catch(() => {});
|
||||
await mkdir(tmpBenchPackagePath, { recursive: true });
|
||||
|
||||
await writeFile(
|
||||
join(tmpBenchPackagePath, 'package.json'),
|
||||
JSON.stringify(
|
||||
{
|
||||
name: `${packageName}-bench`,
|
||||
version: '1.0.0',
|
||||
dependencies: {
|
||||
[packageName]: versions[packageName],
|
||||
},
|
||||
// Overrides ensures that Storybook packages outside the monorepo are using the versions we have in the monorepo
|
||||
overrides: versions,
|
||||
},
|
||||
null,
|
||||
2
|
||||
)
|
||||
);
|
||||
|
||||
const npmInstallResult = await x(
|
||||
'npm',
|
||||
`install --registry http://localhost:6001 --omit peer --json`.split(' '),
|
||||
{
|
||||
nodeOptions: { cwd: tmpBenchPackagePath },
|
||||
}
|
||||
);
|
||||
|
||||
const { added } = JSON.parse(npmInstallResult.stdout) as { added: number };
|
||||
// -1 of reported packages added because we shouldn't count the actual package as a dependency
|
||||
const dependencyCount = added - 1;
|
||||
|
||||
const getDirSize = async (path: string) => {
|
||||
const entities = await readdir(path, {
|
||||
recursive: true,
|
||||
withFileTypes: true,
|
||||
});
|
||||
const stats = await Promise.all(
|
||||
entities
|
||||
.filter((entity) => entity.isFile())
|
||||
.map((entity) => stat(join(entity.parentPath, entity.name)))
|
||||
);
|
||||
return stats.reduce((acc, { size }) => acc + size, 0);
|
||||
};
|
||||
|
||||
const nodeModulesSize = await getDirSize(join(tmpBenchPackagePath, 'node_modules'));
|
||||
const selfSize = await getDirSize(join(tmpBenchPackagePath, 'node_modules', packageName));
|
||||
const dependencySize = nodeModulesSize - selfSize;
|
||||
|
||||
const result: Result = {
|
||||
package: packageName,
|
||||
dependencyCount,
|
||||
selfSize,
|
||||
dependencySize,
|
||||
};
|
||||
console.log(`Done benching ${picocolors.blue(packageName)}`);
|
||||
return result;
|
||||
};
|
||||
|
||||
const toHumanReadable = (result: Partial<Result> | Partial<ComparisonResult>) => {
|
||||
const formatBytes = (bytes: number, diff = false) => {
|
||||
const units = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
let size = Math.abs(bytes);
|
||||
let unitIndex = 0;
|
||||
|
||||
while (size >= 1000 && unitIndex < units.length - 1) {
|
||||
size /= 1000;
|
||||
unitIndex++;
|
||||
}
|
||||
|
||||
// B, KB = 0 decimal places
|
||||
// MB, GB, TB = 2 decimal places
|
||||
const decimals = unitIndex < 2 ? 0 : 2;
|
||||
const formattedSize = `${size.toFixed(decimals)} ${units[unitIndex]}`;
|
||||
|
||||
if (bytes < 0) {
|
||||
return `-${formattedSize}`;
|
||||
}
|
||||
if (diff && bytes > 0) {
|
||||
return `+${formattedSize}`;
|
||||
}
|
||||
return formattedSize;
|
||||
};
|
||||
|
||||
if (typeof result.dependencyCount === 'number') {
|
||||
const { dependencyCount, selfSize, dependencySize } = result as Result;
|
||||
return {
|
||||
package: result.package,
|
||||
dependencyCount: dependencyCount.toString(),
|
||||
selfSize: formatBytes(selfSize),
|
||||
dependencySize: formatBytes(dependencySize),
|
||||
totalSize: formatBytes(selfSize + dependencySize),
|
||||
};
|
||||
}
|
||||
const { dependencyCount, selfSize, dependencySize } = result as ComparisonResult;
|
||||
|
||||
return {
|
||||
package: result.package,
|
||||
dependencyCount: {
|
||||
base: dependencyCount.base.toString(),
|
||||
new: dependencyCount.new.toString(),
|
||||
diff: `${dependencyCount.diff > 0 ? '+' : dependencyCount.diff < 0 ? '-' : ''}${dependencyCount.diff}`,
|
||||
},
|
||||
selfSize: {
|
||||
base: formatBytes(selfSize.base),
|
||||
new: formatBytes(selfSize.new),
|
||||
diff: formatBytes(selfSize.diff, true),
|
||||
},
|
||||
dependencySize: {
|
||||
base: formatBytes(dependencySize.base),
|
||||
new: formatBytes(dependencySize.new),
|
||||
diff: formatBytes(dependencySize.diff, true),
|
||||
},
|
||||
totalSize: {
|
||||
base: formatBytes(selfSize.base + dependencySize.base),
|
||||
new: formatBytes(selfSize.new + dependencySize.new),
|
||||
diff: formatBytes(selfSize.diff + dependencySize.diff, true),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const saveLocally = async ({
|
||||
results,
|
||||
filename,
|
||||
}: {
|
||||
results: Partial<ResultMap | ComparisonResultMap>;
|
||||
filename: string;
|
||||
diff?: boolean;
|
||||
}) => {
|
||||
const resultPath = join(BENCH_PACKAGES_PATH, filename);
|
||||
console.log(`Saving results to ${picocolors.magenta(resultPath)}...`);
|
||||
|
||||
const humanReadableResults = Object.entries(results).reduce(
|
||||
(acc, [packageName, result]) => {
|
||||
acc[packageName as PackageName] = toHumanReadable(result);
|
||||
return acc;
|
||||
},
|
||||
{} as Record<PackageName, ReturnType<typeof toHumanReadable>>
|
||||
);
|
||||
await writeFile(resultPath, JSON.stringify(humanReadableResults, null, 2));
|
||||
};
|
||||
|
||||
const compareResults = async ({
|
||||
results,
|
||||
baseBranch,
|
||||
}: {
|
||||
results: ResultMap;
|
||||
baseBranch: string;
|
||||
}) => {
|
||||
console.log(`Comparing results with base branch ${picocolors.magenta(baseBranch)}...`);
|
||||
const [baseResults] = await bigQueryBenchTable.query({
|
||||
query: `
|
||||
WITH
|
||||
latest_packages AS (
|
||||
SELECT *,
|
||||
ROW_NUMBER() OVER (PARTITION BY package ORDER BY benchmarkedAt DESC) AS row_number
|
||||
FROM
|
||||
\`storybook-benchmark.benchmark_results.package_bench\`
|
||||
WHERE
|
||||
branch = @baseBranch
|
||||
AND package IN UNNEST(@packages)
|
||||
AND benchmarkedAt > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 7 DAY) )
|
||||
SELECT *
|
||||
FROM latest_packages
|
||||
WHERE row_number = 1;`,
|
||||
params: { baseBranch, packages: Object.keys(results) },
|
||||
});
|
||||
|
||||
const comparisonResults = {} as ComparisonResultMap;
|
||||
for (const result of Object.values(results)) {
|
||||
let baseResult = baseResults.find((row) => row.package === result.package);
|
||||
if (!baseResult) {
|
||||
console.warn(
|
||||
`No base result found for ${picocolors.blue(result.package)}, comparing with zero values.`
|
||||
);
|
||||
baseResult = {
|
||||
package: result.package,
|
||||
dependencyCount: 0,
|
||||
selfSize: 0,
|
||||
dependencySize: 0,
|
||||
};
|
||||
}
|
||||
|
||||
comparisonResults[result.package] = {
|
||||
package: result.package,
|
||||
dependencyCount: {
|
||||
base: baseResult.dependencyCount,
|
||||
new: result.dependencyCount,
|
||||
diff: result.dependencyCount - baseResult.dependencyCount,
|
||||
},
|
||||
selfSize: {
|
||||
base: baseResult.selfSize,
|
||||
new: result.selfSize,
|
||||
diff: result.selfSize - baseResult.selfSize,
|
||||
},
|
||||
dependencySize: {
|
||||
base: baseResult.dependencySize,
|
||||
new: result.dependencySize,
|
||||
diff: result.dependencySize - baseResult.dependencySize,
|
||||
},
|
||||
};
|
||||
}
|
||||
console.log(picocolors.green('Done comparing results'));
|
||||
return comparisonResults;
|
||||
};
|
||||
|
||||
const filterResultsByThresholds = (comparisonResults: ComparisonResultMap) => {
|
||||
const filteredResults: Partial<ComparisonResultMap> = {};
|
||||
for (const comparisonResult of Object.values(comparisonResults)) {
|
||||
const exceedsThresholds =
|
||||
Math.abs(comparisonResult.selfSize.diff) > Thresholds.SELF_SIZE_ABSOLUTE ||
|
||||
Math.abs(comparisonResult.selfSize.diff) / comparisonResult.selfSize.base >
|
||||
Thresholds.SELF_SIZE_RATIO ||
|
||||
Math.abs(comparisonResult.dependencySize.diff) > Thresholds.DEPS_SIZE_ABSOLUTE ||
|
||||
Math.abs(comparisonResult.dependencySize.diff) / comparisonResult.dependencySize.base >
|
||||
Thresholds.DEPS_SIZE_RATIO ||
|
||||
Math.abs(comparisonResult.dependencyCount.diff) > Thresholds.DEPS_COUNT_ABSOLUTE;
|
||||
|
||||
if (exceedsThresholds) {
|
||||
filteredResults[comparisonResult.package] = comparisonResult;
|
||||
}
|
||||
}
|
||||
|
||||
const amountAboveThreshold = Object.keys(filteredResults).length;
|
||||
const color = amountAboveThreshold === 0 ? picocolors.green : picocolors.red;
|
||||
console.log(color(`${amountAboveThreshold} packages exceeded the thresholds`));
|
||||
|
||||
return filteredResults;
|
||||
};
|
||||
|
||||
const uploadToBigQuery = async ({
|
||||
results,
|
||||
branch,
|
||||
commit,
|
||||
benchmarkedAt,
|
||||
}: {
|
||||
results: ResultMap;
|
||||
branch: string;
|
||||
commit: string;
|
||||
benchmarkedAt: Date;
|
||||
}) => {
|
||||
console.log('Uploading results to BigQuery...');
|
||||
const rows = Object.values(results).map((result) => ({
|
||||
branch,
|
||||
commit,
|
||||
benchmarkedAt,
|
||||
package: result.package,
|
||||
selfSize: result.selfSize,
|
||||
dependencySize: result.dependencySize,
|
||||
dependencyCount: result.dependencyCount,
|
||||
}));
|
||||
|
||||
await bigQueryBenchTable.insert(rows);
|
||||
};
|
||||
|
||||
const uploadToGithub = async ({
|
||||
results,
|
||||
headBranch,
|
||||
baseBranch,
|
||||
commit,
|
||||
benchmarkedAt,
|
||||
pullRequest,
|
||||
}: {
|
||||
results: Partial<ComparisonResultMap>;
|
||||
headBranch: string;
|
||||
baseBranch: string;
|
||||
commit: string;
|
||||
benchmarkedAt: Date;
|
||||
pullRequest: number;
|
||||
}) => {
|
||||
console.log('Uploading results to GitHub...');
|
||||
// const response = await fetch('http://localhost:3000/package-bench', {
|
||||
const response = await fetch('https://storybook-benchmark-bot.vercel.app/package-bench', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
owner: 'storybookjs',
|
||||
repo: 'storybook',
|
||||
issueNumber: pullRequest,
|
||||
headBranch,
|
||||
baseBranch,
|
||||
commit,
|
||||
benchmarkedAt: benchmarkedAt.toISOString(),
|
||||
results,
|
||||
}),
|
||||
});
|
||||
if (response.status < 200 || response.status >= 400) {
|
||||
const body = await response.text();
|
||||
throw new Error(`Failed to upload results to GitHub.
|
||||
STATUS: ${response.status} - ${response.statusText}
|
||||
BODY:
|
||||
${body}`);
|
||||
}
|
||||
};
|
||||
|
||||
const run = async () => {
|
||||
program
|
||||
.option(
|
||||
'-b, --base-branch <string>',
|
||||
'The base branch to compare the results with. Requires GCP_CREDENTIALS env var'
|
||||
)
|
||||
.option(
|
||||
'-p, --pull-request <number>',
|
||||
'The PR number to add compare results to. Only used together with --baseBranch',
|
||||
function parseInt(value) {
|
||||
const parsedValue = Number.parseInt(value);
|
||||
if (Number.isNaN(parsedValue)) {
|
||||
throw new InvalidArgumentError('Must be a number');
|
||||
}
|
||||
return parsedValue;
|
||||
}
|
||||
)
|
||||
.option('-u, --upload', 'Upload results to BigQuery. Requires GCP_CREDENTIALS env var')
|
||||
.argument(
|
||||
'[packages...]',
|
||||
'which packages to bench. If omitted, all packages are benched',
|
||||
function parsePackages(value) {
|
||||
const parsedValue = value.split(' ');
|
||||
parsedValue.forEach((packageName) => {
|
||||
if (!Object.keys(versions).includes(packageName)) {
|
||||
throw new InvalidArgumentError(`Package '${packageName}' not found in the monorepo`);
|
||||
}
|
||||
});
|
||||
return parsedValue;
|
||||
}
|
||||
);
|
||||
program.parse(process.argv);
|
||||
|
||||
const packageNames = (
|
||||
program.args.length > 0 ? program.args : Object.keys(versions)
|
||||
) as PackageName[];
|
||||
const options = program.opts<{ pullRequest?: number; baseBranch?: string; upload?: boolean }>();
|
||||
|
||||
if (options.upload || options.baseBranch) {
|
||||
if (!GCP_CREDENTIALS.project_id) {
|
||||
throw new Error(
|
||||
'GCP_CREDENTIALS env var is required to upload to BigQuery or compare against a base branch'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ((await detectFreePort(REGISTRY_PORT)) === REGISTRY_PORT) {
|
||||
throw new Error(dedent`The local verdaccio registry must be running in the background for package benching to work,
|
||||
and packages must be published to it in --no-link mode with 'yarn --task publish --no-link'
|
||||
Then run the registry with 'yarn --task run-registry --no-link'`);
|
||||
}
|
||||
|
||||
// The amount of VCPUs for this task in CI is 2 (medium resource)
|
||||
const amountOfVCPUs = 2;
|
||||
const concurrentLimit = process.env.CI ? amountOfVCPUs - 1 : maxConcurrentTasks;
|
||||
const limit = pLimit(concurrentLimit);
|
||||
|
||||
const progressIntervalId = setInterval(() => {
|
||||
const doneCount = packageNames.length - limit.activeCount - limit.pendingCount;
|
||||
if (doneCount === packageNames.length) {
|
||||
clearInterval(progressIntervalId);
|
||||
return;
|
||||
}
|
||||
console.log(
|
||||
`Benching status: ${picocolors.red(limit.pendingCount)} pending, ${picocolors.yellow(limit.activeCount)} running, ${picocolors.green(doneCount)} done...`
|
||||
);
|
||||
}, 2_000);
|
||||
const resultsArray = await Promise.all(
|
||||
packageNames.map((packageName) => limit(() => benchPackage(packageName)))
|
||||
);
|
||||
const results = resultsArray.reduce((acc, result) => {
|
||||
acc[result.package] = result;
|
||||
return acc;
|
||||
}, {} as ResultMap);
|
||||
await saveLocally({
|
||||
filename: `results.json`,
|
||||
results,
|
||||
});
|
||||
|
||||
const headBranch =
|
||||
process.env.CIRCLE_BRANCH ||
|
||||
(await x('git', 'rev-parse --abbrev-ref HEAD'.split(' '))).stdout.trim();
|
||||
const commit =
|
||||
process.env.CIRCLE_SHA1 || (await x('git', 'rev-parse HEAD'.split(' '))).stdout.trim();
|
||||
const benchmarkedAt = new Date();
|
||||
|
||||
if (options.upload) {
|
||||
await uploadToBigQuery({ results, branch: headBranch, commit, benchmarkedAt });
|
||||
}
|
||||
|
||||
if (options.baseBranch) {
|
||||
const comparisonResults = await compareResults({ results, baseBranch: options.baseBranch });
|
||||
const resultsAboveThreshold = filterResultsByThresholds(comparisonResults);
|
||||
await saveLocally({
|
||||
filename: `compare-with-${options.baseBranch}.json`,
|
||||
results: comparisonResults,
|
||||
diff: true,
|
||||
});
|
||||
await saveLocally({
|
||||
filename: `comparisons-above-threshold-with-${options.baseBranch}.json`,
|
||||
results: resultsAboveThreshold,
|
||||
diff: true,
|
||||
});
|
||||
if (options.pullRequest) {
|
||||
await uploadToGithub({
|
||||
results: resultsAboveThreshold,
|
||||
pullRequest: options.pullRequest,
|
||||
baseBranch: options.baseBranch,
|
||||
headBranch,
|
||||
commit,
|
||||
benchmarkedAt,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
console.log(picocolors.green('Done benching all packages'));
|
||||
};
|
||||
|
||||
if (esMain(import.meta.url)) {
|
||||
run().catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
@ -4,6 +4,7 @@
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"bench-packages": "jiti ./bench/bench-packages.ts",
|
||||
"build-package": "jiti ./build-package.ts",
|
||||
"check": "jiti ./prepare/check-scripts.ts",
|
||||
"check-package": "jiti ./check-package.ts",
|
||||
@ -174,6 +175,7 @@
|
||||
"slash": "^3.0.0",
|
||||
"sort-package-json": "^2.10.0",
|
||||
"tiny-invariant": "^1.3.3",
|
||||
"tinyexec": "^0.3.0",
|
||||
"trash": "^7.2.0",
|
||||
"ts-dedent": "^2.2.0",
|
||||
"tsup": "^6.7.0",
|
||||
|
@ -118,7 +118,10 @@ export const nodeInternals = [
|
||||
...require('module').builtinModules.flatMap((m: string) => [m, `node:${m}`]),
|
||||
];
|
||||
|
||||
export const getWorkspace = async () => {
|
||||
type PackageJson = typefest.PackageJson &
|
||||
Required<Pick<typefest.PackageJson, 'name' | 'version'>> & { path: string };
|
||||
|
||||
export const getWorkspace = async (): Promise<PackageJson[]> => {
|
||||
const codePackage = await readJson(join(CODE_DIRECTORY, 'package.json'));
|
||||
const {
|
||||
workspaces: { packages: patterns },
|
||||
@ -142,8 +145,7 @@ export const getWorkspace = async () => {
|
||||
return null;
|
||||
}
|
||||
const pkg = await readJson(packageJsonPath);
|
||||
return { ...pkg, path: packagePath } as typefest.PackageJson &
|
||||
Required<Pick<typefest.PackageJson, 'name' | 'version'>> & { path: string };
|
||||
return { ...pkg, path: packagePath } as PackageJson;
|
||||
})
|
||||
).then((packages) => packages.filter((p) => p !== null));
|
||||
};
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { exec } from 'node:child_process';
|
||||
import { mkdir } from 'node:fs/promises';
|
||||
import { mkdir, rm } from 'node:fs/promises';
|
||||
import http from 'node:http';
|
||||
import type { Server } from 'node:http';
|
||||
import { join, resolve as resolvePath } from 'node:path';
|
||||
|
||||
import { program } from 'commander';
|
||||
// eslint-disable-next-line depend/ban-dependencies
|
||||
import { execa, execaSync } from 'execa';
|
||||
import { execa } from 'execa';
|
||||
// eslint-disable-next-line depend/ban-dependencies
|
||||
import { pathExists, readJSON, remove } from 'fs-extra';
|
||||
import pLimit from 'p-limit';
|
||||
@ -207,7 +207,7 @@ const run = async () => {
|
||||
await publish(packages, 'http://localhost:6002');
|
||||
}
|
||||
|
||||
await execa('npx', ['rimraf', '.npmrc'], { cwd: root });
|
||||
await rm(join(root, '.npmrc'), { force: true });
|
||||
|
||||
if (!opts.open) {
|
||||
verdaccioServer.close();
|
||||
@ -217,6 +217,7 @@ const run = async () => {
|
||||
|
||||
run().catch((e) => {
|
||||
logger.error(e);
|
||||
execaSync('npx', ['rimraf', '.npmrc'], { cwd: root });
|
||||
process.exit(1);
|
||||
rm(join(root, '.npmrc'), { force: true }).then(() => {
|
||||
process.exit(1);
|
||||
});
|
||||
});
|
||||
|
@ -1660,6 +1660,7 @@ __metadata:
|
||||
slash: "npm:^3.0.0"
|
||||
sort-package-json: "npm:^2.10.0"
|
||||
tiny-invariant: "npm:^1.3.3"
|
||||
tinyexec: "npm:^0.3.0"
|
||||
trash: "npm:^7.2.0"
|
||||
ts-dedent: "npm:^2.2.0"
|
||||
tsup: "npm:^6.7.0"
|
||||
@ -13452,9 +13453,9 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"tinyexec@npm:^0.3.0":
|
||||
version: 0.3.1
|
||||
resolution: "tinyexec@npm:0.3.1"
|
||||
checksum: 10c0/11e7a7c5d8b3bddf8b5cbe82a9290d70a6fad84d528421d5d18297f165723cb53d2e737d8f58dcce5ca56f2e4aa2d060f02510b1f8971784f97eb3e9aec28f09
|
||||
version: 0.3.0
|
||||
resolution: "tinyexec@npm:0.3.0"
|
||||
checksum: 10c0/138a4f4241aea6b6312559508468ab275a31955e66e2f57ed206e0aaabecee622624f208c5740345f0a66e33478fd065e359ed1eb1269eb6fd4fa25d44d0ba3b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
@ -15,6 +15,6 @@ function Component() {
|
||||
|
||||
export default {
|
||||
component: Component,
|
||||
};
|
||||
} as Meta<typeof Component>;
|
||||
|
||||
export const Default = {};
|
||||
|
@ -20,7 +20,7 @@ function Component() {
|
||||
|
||||
export default {
|
||||
component: Component,
|
||||
};
|
||||
} as Meta<typeof Component>;
|
||||
|
||||
export const Default: StoryObj = {
|
||||
play: async () => {
|
||||
|
@ -1,5 +1,4 @@
|
||||
import type { Meta } from '@storybook/react';
|
||||
import type { StoryObj } from '@storybook/react';
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { expect, userEvent, within } from '@storybook/test';
|
||||
import { cookies, headers } from '@storybook/nextjs/headers.mock';
|
||||
import NextHeader from './NextHeader';
|
||||
|
@ -15,6 +15,6 @@ const Component = () => (
|
||||
|
||||
export default {
|
||||
component: Component,
|
||||
};
|
||||
} as Meta<typeof Component>;
|
||||
|
||||
export const Default = {};
|
||||
|
@ -11,7 +11,7 @@ const Component = () => <button>test</button>
|
||||
export default {
|
||||
title: 'Addons/Test',
|
||||
component: Component,
|
||||
};
|
||||
} as Meta<typeof Component>;
|
||||
|
||||
const { pass } = instrument({
|
||||
pass: async () => {},
|
||||
|
Loading…
x
Reference in New Issue
Block a user