mirror of
https://github.com/storybookjs/storybook.git
synced 2025-04-09 00:19:13 +08:00
Merge latest-release into version-non-patch-from-8.1.0-beta.1 with conflicts resolved to ours [skip ci]
This commit is contained in:
commit
254bd81b4d
@ -5,8 +5,8 @@ import path from 'path';
|
|||||||
import type { PluginOption } from 'vite';
|
import type { PluginOption } from 'vite';
|
||||||
import {
|
import {
|
||||||
TypeMeta,
|
TypeMeta,
|
||||||
createComponentMetaChecker,
|
createChecker,
|
||||||
createComponentMetaCheckerByJsonConfig,
|
createCheckerByJson,
|
||||||
type ComponentMeta,
|
type ComponentMeta,
|
||||||
type MetaCheckerOptions,
|
type MetaCheckerOptions,
|
||||||
} from 'vue-component-meta';
|
} from 'vue-component-meta';
|
||||||
@ -19,7 +19,7 @@ type MetaSource = {
|
|||||||
} & ComponentMeta &
|
} & ComponentMeta &
|
||||||
MetaCheckerOptions['schema'];
|
MetaCheckerOptions['schema'];
|
||||||
|
|
||||||
export async function vueComponentMeta(): Promise<PluginOption> {
|
export async function vueComponentMeta(tsconfigPath = 'tsconfig.json'): Promise<PluginOption> {
|
||||||
const { createFilter } = await import('vite');
|
const { createFilter } = await import('vite');
|
||||||
|
|
||||||
// exclude stories, virtual modules and storybook internals
|
// exclude stories, virtual modules and storybook internals
|
||||||
@ -28,7 +28,7 @@ export async function vueComponentMeta(): Promise<PluginOption> {
|
|||||||
const include = /\.(vue|ts|js|tsx|jsx)$/;
|
const include = /\.(vue|ts|js|tsx|jsx)$/;
|
||||||
const filter = createFilter(include, exclude);
|
const filter = createFilter(include, exclude);
|
||||||
|
|
||||||
const checker = await createChecker();
|
const checker = await createVueComponentMetaChecker(tsconfigPath);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: 'storybook:vue-component-meta-plugin',
|
name: 'storybook:vue-component-meta-plugin',
|
||||||
@ -126,9 +126,10 @@ export async function vueComponentMeta(): Promise<PluginOption> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the vue-component-meta checker to use for extracting component meta/docs.
|
* Creates the `vue-component-meta` checker to use for extracting component meta/docs.
|
||||||
|
* Considers the given tsconfig file (will use a fallback checker if it does not exist or is not supported).
|
||||||
*/
|
*/
|
||||||
async function createChecker() {
|
async function createVueComponentMetaChecker(tsconfigPath = 'tsconfig.json') {
|
||||||
const checkerOptions: MetaCheckerOptions = {
|
const checkerOptions: MetaCheckerOptions = {
|
||||||
forceUseTs: true,
|
forceUseTs: true,
|
||||||
noDeclarations: true,
|
noDeclarations: true,
|
||||||
@ -136,26 +137,18 @@ async function createChecker() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const projectRoot = getProjectRoot();
|
const projectRoot = getProjectRoot();
|
||||||
const projectTsConfigPath = path.join(projectRoot, 'tsconfig.json');
|
const projectTsConfigPath = path.join(projectRoot, tsconfigPath);
|
||||||
|
|
||||||
const defaultChecker = createComponentMetaCheckerByJsonConfig(
|
const defaultChecker = createCheckerByJson(projectRoot, { include: ['**/*'] }, checkerOptions);
|
||||||
projectRoot,
|
|
||||||
{ include: ['**/*'] },
|
|
||||||
checkerOptions
|
|
||||||
);
|
|
||||||
|
|
||||||
// prefer the tsconfig.json file of the project to support alias resolution etc.
|
// prefer the tsconfig.json file of the project to support alias resolution etc.
|
||||||
if (await fileExists(projectTsConfigPath)) {
|
if (await fileExists(projectTsConfigPath)) {
|
||||||
// tsconfig that uses references is currently not supported by vue-component-meta
|
// vue-component-meta does currently not resolve tsconfig references (see https://github.com/vuejs/language-tools/issues/3896)
|
||||||
// see: https://github.com/vuejs/language-tools/issues/3896
|
// so we will return the defaultChecker if references are used.
|
||||||
// so we return the no-tsconfig defaultChecker if tsconfig references are found
|
// Otherwise vue-component-meta might not work at all for the Storybook docgen.
|
||||||
// remove this workaround once the above issue is fixed
|
|
||||||
const references = await getTsConfigReferences(projectTsConfigPath);
|
const references = await getTsConfigReferences(projectTsConfigPath);
|
||||||
if (references.length > 0) {
|
if (references.length > 0) return defaultChecker;
|
||||||
// TODO: paths/aliases are not resolvable, find workaround for this
|
return createChecker(projectTsConfigPath, checkerOptions);
|
||||||
return defaultChecker;
|
|
||||||
}
|
|
||||||
return createComponentMetaChecker(projectTsConfigPath, checkerOptions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return defaultChecker;
|
return defaultChecker;
|
||||||
|
@ -3,7 +3,7 @@ import { dirname, join } from 'path';
|
|||||||
import type { PluginOption } from 'vite';
|
import type { PluginOption } from 'vite';
|
||||||
import { vueComponentMeta } from './plugins/vue-component-meta';
|
import { vueComponentMeta } from './plugins/vue-component-meta';
|
||||||
import { vueDocgen } from './plugins/vue-docgen';
|
import { vueDocgen } from './plugins/vue-docgen';
|
||||||
import type { FrameworkOptions, StorybookConfig } from './types';
|
import type { FrameworkOptions, StorybookConfig, VueDocgenPlugin } from './types';
|
||||||
|
|
||||||
const getAbsolutePath = <I extends string>(input: I): I =>
|
const getAbsolutePath = <I extends string>(input: I): I =>
|
||||||
dirname(require.resolve(join(input, 'package.json'))) as any;
|
dirname(require.resolve(join(input, 'package.json'))) as any;
|
||||||
@ -20,11 +20,11 @@ export const viteFinal: StorybookConfig['viteFinal'] = async (config, options) =
|
|||||||
const frameworkOptions: FrameworkOptions =
|
const frameworkOptions: FrameworkOptions =
|
||||||
typeof framework === 'string' ? {} : framework.options ?? {};
|
typeof framework === 'string' ? {} : framework.options ?? {};
|
||||||
|
|
||||||
const docgenPlugin = frameworkOptions.docgen ?? 'vue-docgen-api';
|
const docgen = resolveDocgenOptions(frameworkOptions.docgen);
|
||||||
|
|
||||||
// add docgen plugin depending on framework option
|
// add docgen plugin depending on framework option
|
||||||
if (docgenPlugin === 'vue-component-meta') {
|
if (docgen.plugin === 'vue-component-meta') {
|
||||||
plugins.push(await vueComponentMeta());
|
plugins.push(await vueComponentMeta(docgen.tsconfig));
|
||||||
} else {
|
} else {
|
||||||
plugins.push(await vueDocgen());
|
plugins.push(await vueDocgen());
|
||||||
}
|
}
|
||||||
@ -39,3 +39,14 @@ export const viteFinal: StorybookConfig['viteFinal'] = async (config, options) =
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves the docgen framework option.
|
||||||
|
*/
|
||||||
|
const resolveDocgenOptions = (
|
||||||
|
docgen?: FrameworkOptions['docgen']
|
||||||
|
): { plugin: VueDocgenPlugin; tsconfig?: string } => {
|
||||||
|
if (!docgen) return { plugin: 'vue-docgen-api' };
|
||||||
|
if (typeof docgen === 'string') return { plugin: docgen };
|
||||||
|
return docgen;
|
||||||
|
};
|
||||||
|
@ -21,7 +21,21 @@ export type FrameworkOptions = {
|
|||||||
* "vue-component-meta" will become the new default in the future and "vue-docgen-api" will be removed.
|
* "vue-component-meta" will become the new default in the future and "vue-docgen-api" will be removed.
|
||||||
* @default "vue-docgen-api"
|
* @default "vue-docgen-api"
|
||||||
*/
|
*/
|
||||||
docgen?: VueDocgenPlugin;
|
docgen?:
|
||||||
|
| VueDocgenPlugin
|
||||||
|
| {
|
||||||
|
plugin: 'vue-component-meta';
|
||||||
|
/**
|
||||||
|
* Tsconfig filename to use. Should be set if your main `tsconfig.json` includes references to other tsconfig files
|
||||||
|
* like `tsconfig.app.json`.
|
||||||
|
* Otherwise docgen might not be generated correctly (e.g. import aliases are not resolved).
|
||||||
|
*
|
||||||
|
* For further information, see our [docs](https://storybook.js.org/docs/get-started/vue3-vite#override-the-default-configuration).
|
||||||
|
*
|
||||||
|
* @default "tsconfig.json"
|
||||||
|
*/
|
||||||
|
tsconfig: `tsconfig${string}.json`;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
type StorybookConfigFramework = {
|
type StorybookConfigFramework = {
|
||||||
|
@ -20,6 +20,7 @@ import {
|
|||||||
getStorybookInfo,
|
getStorybookInfo,
|
||||||
loadMainConfig,
|
loadMainConfig,
|
||||||
JsPackageManagerFactory,
|
JsPackageManagerFactory,
|
||||||
|
getCoercedStorybookVersion,
|
||||||
} from '@storybook/core-common';
|
} from '@storybook/core-common';
|
||||||
import { automigrate } from './automigrate/index';
|
import { automigrate } from './automigrate/index';
|
||||||
import { autoblock } from './autoblock/index';
|
import { autoblock } from './autoblock/index';
|
||||||
@ -146,10 +147,11 @@ export const doUpgrade = async ({
|
|||||||
throw new UpgradeStorybookToSameVersionError({ beforeVersion });
|
throw new UpgradeStorybookToSameVersionError({ beforeVersion });
|
||||||
}
|
}
|
||||||
|
|
||||||
const [latestVersion, packageJson] = await Promise.all([
|
const [latestVersion, packageJson, storybookVersion] = await Promise.all([
|
||||||
//
|
//
|
||||||
packageManager.latestVersion('@storybook/cli'),
|
packageManager.latestVersion('@storybook/cli'),
|
||||||
packageManager.retrievePackageJson(),
|
packageManager.retrievePackageJson(),
|
||||||
|
getCoercedStorybookVersion(packageManager),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const isOutdated = lt(currentVersion, latestVersion);
|
const isOutdated = lt(currentVersion, latestVersion);
|
||||||
@ -193,7 +195,7 @@ export const doUpgrade = async ({
|
|||||||
const mainConfig = await loadMainConfig({ configDir });
|
const mainConfig = await loadMainConfig({ configDir });
|
||||||
|
|
||||||
// GUARDS
|
// GUARDS
|
||||||
if (!beforeVersion) {
|
if (!storybookVersion) {
|
||||||
throw new UpgradeStorybookUnknownCurrentVersionError();
|
throw new UpgradeStorybookUnknownCurrentVersionError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,6 +218,34 @@ describe('composeConfigs', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('allows single array to be written without array', () => {
|
||||||
|
expect(
|
||||||
|
composeConfigs([
|
||||||
|
{
|
||||||
|
argsEnhancers: ['1', '2'],
|
||||||
|
argTypesEnhancers: ['1', '2'],
|
||||||
|
loaders: '1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
argsEnhancers: '3',
|
||||||
|
argTypesEnhancers: '3',
|
||||||
|
loaders: ['2', '3'],
|
||||||
|
},
|
||||||
|
])
|
||||||
|
).toEqual({
|
||||||
|
parameters: {},
|
||||||
|
decorators: [],
|
||||||
|
args: {},
|
||||||
|
argsEnhancers: ['1', '2', '3'],
|
||||||
|
argTypes: {},
|
||||||
|
argTypesEnhancers: ['1', '2', '3'],
|
||||||
|
globals: {},
|
||||||
|
globalTypes: {},
|
||||||
|
loaders: ['1', '2', '3'],
|
||||||
|
runStep: expect.any(Function),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('combines decorators in reverse file order', () => {
|
it('combines decorators in reverse file order', () => {
|
||||||
expect(
|
expect(
|
||||||
composeConfigs([
|
composeConfigs([
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
import type { Meta, StoryObj } from '@storybook/vue3';
|
||||||
|
import Component from './define-model/component.vue';
|
||||||
|
|
||||||
|
const meta = {
|
||||||
|
component: Component,
|
||||||
|
tags: ['autodocs'],
|
||||||
|
} satisfies Meta<typeof Component>;
|
||||||
|
|
||||||
|
type Story = StoryObj<typeof meta>;
|
||||||
|
export default meta;
|
||||||
|
|
||||||
|
export const Default: Story = {
|
||||||
|
args: {
|
||||||
|
modelValue: 'Test value',
|
||||||
|
},
|
||||||
|
};
|
@ -0,0 +1,18 @@
|
|||||||
|
import type { Meta, StoryObj } from '@storybook/vue3';
|
||||||
|
import Component from './define-slots/component.vue';
|
||||||
|
|
||||||
|
const meta = {
|
||||||
|
component: Component,
|
||||||
|
tags: ['autodocs'],
|
||||||
|
} satisfies Meta<typeof Component>;
|
||||||
|
|
||||||
|
type Story = StoryObj<typeof meta>;
|
||||||
|
export default meta;
|
||||||
|
|
||||||
|
export const Default: Story = {
|
||||||
|
args: {
|
||||||
|
default: ({ num }) => `Default slot { num=${num} }`,
|
||||||
|
named: ({ str }) => `Named slot { str=${str} }`,
|
||||||
|
vbind: ({ num, str }) => `Named v-bind slot { num=${num}, str=${str} }`,
|
||||||
|
},
|
||||||
|
};
|
@ -0,0 +1,7 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
const model = defineModel<string>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
{{ model }}
|
||||||
|
</template>
|
@ -0,0 +1,22 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
defineSlots<{
|
||||||
|
/** Some description for "no-bind" slot. */
|
||||||
|
'no-bind'(): any;
|
||||||
|
/** Some description for "default" slot. */
|
||||||
|
default(props: { num: number }): any;
|
||||||
|
/** Some description for "named" slot. */
|
||||||
|
named(props: { str: string }): any;
|
||||||
|
/** Some description for "vbind" slot. */
|
||||||
|
vbind(props: { num: number; str: string }): any;
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<slot name="no-bind"></slot>
|
||||||
|
<br />
|
||||||
|
<slot :num="123"></slot>
|
||||||
|
<br />
|
||||||
|
<slot name="named" str="str"></slot>
|
||||||
|
<br />
|
||||||
|
<slot name="vbind" v-bind="{ num: 123, str: 'str' }"></slot>
|
||||||
|
</template>
|
@ -275,16 +275,37 @@ The definition above will generate the following controls:
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
### Limitations
|
### Override the default configuration
|
||||||
|
|
||||||
`vue-component-meta` cannot currently reference types from an import alias. You will need to replace any aliased imports with relative ones, as in the example below. See [this issue](https://github.com/vuejs/language-tools/issues/3896) for more information.
|
If you're working with a project that relies on [`tsconfig references`](https://www.typescriptlang.org/docs/handbook/project-references.html) to link to other existing configuration files (e.g. `tsconfig.app.json`, `tsconfig.node.json`), we recommend that you update your [`.storybook/main.js|ts`](../configure/index.md) configuration file and add the following:
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
// YourComponent.ts
|
// .storybook/main.ts
|
||||||
import type { MyProps } from '@/types'; // ❌ Cannot be resolved
|
import type { StorybookConfig } from '@storybook/vue3-vite';
|
||||||
import type { MyProps } from '../types'; // ✅ Can be resolved
|
|
||||||
|
const config: StorybookConfig = {
|
||||||
|
framework: {
|
||||||
|
name: '@storybook/vue3-vite',
|
||||||
|
options: {
|
||||||
|
docgen: {
|
||||||
|
plugin: 'vue-component-meta',
|
||||||
|
tsconfig: 'tsconfig.app.json',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
<Callout variant="info">
|
||||||
|
|
||||||
|
This is not a limitation of Storybook, but instead how `vue-component-meta` works. For more information, refer to the appropriate [GitHub issue](https://github.com/vuejs/language-tools/issues/3896).
|
||||||
|
|
||||||
|
</Callout>
|
||||||
|
|
||||||
|
Otherwise, you might face missing component types/descriptions or unresolvable import aliases like `@/some/import`.
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
### Storybook doesn't work with my Vue 2 project
|
### Storybook doesn't work with my Vue 2 project
|
||||||
|
@ -126,8 +126,10 @@ const run = async ({ cwd, flags }: { cwd: string; flags: string[] }) => {
|
|||||||
platform: 'neutral',
|
platform: 'neutral',
|
||||||
external: [...commonExternals, ...globalManagerPackages, ...globalPreviewPackages],
|
external: [...commonExternals, ...globalManagerPackages, ...globalPreviewPackages],
|
||||||
esbuildOptions: (options) => {
|
esbuildOptions: (options) => {
|
||||||
|
/* eslint-disable no-param-reassign */
|
||||||
options.platform = 'neutral';
|
options.platform = 'neutral';
|
||||||
Object.assign(options, getESBuildOptions(optimized));
|
Object.assign(options, getESBuildOptions(optimized));
|
||||||
|
/* eslint-enable no-param-reassign */
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user