Skip to content

Commit

Permalink
Merge latest-release into version-non-patch-from-8.1.0-beta.1 with co…
Browse files Browse the repository at this point in the history
…nflicts resolved to ours [skip ci]
  • Loading branch information
storybook-bot committed May 14, 2024
2 parents 9a1240f + 85705aa commit 254bd81
Show file tree
Hide file tree
Showing 11 changed files with 167 additions and 33 deletions.
35 changes: 14 additions & 21 deletions code/frameworks/vue3-vite/src/plugins/vue-component-meta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import path from 'path';
import type { PluginOption } from 'vite';
import {
TypeMeta,
createComponentMetaChecker,
createComponentMetaCheckerByJsonConfig,
createChecker,
createCheckerByJson,
type ComponentMeta,
type MetaCheckerOptions,
} from 'vue-component-meta';
Expand All @@ -19,7 +19,7 @@ type MetaSource = {
} & ComponentMeta &
MetaCheckerOptions['schema'];

export async function vueComponentMeta(): Promise<PluginOption> {
export async function vueComponentMeta(tsconfigPath = 'tsconfig.json'): Promise<PluginOption> {
const { createFilter } = await import('vite');

// exclude stories, virtual modules and storybook internals
Expand All @@ -28,7 +28,7 @@ export async function vueComponentMeta(): Promise<PluginOption> {
const include = /\.(vue|ts|js|tsx|jsx)$/;
const filter = createFilter(include, exclude);

const checker = await createChecker();
const checker = await createVueComponentMetaChecker(tsconfigPath);

return {
name: 'storybook:vue-component-meta-plugin',
Expand Down Expand Up @@ -126,36 +126,29 @@ 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 = {
forceUseTs: true,
noDeclarations: true,
printer: { newLine: 1 },
};

const projectRoot = getProjectRoot();
const projectTsConfigPath = path.join(projectRoot, 'tsconfig.json');
const projectTsConfigPath = path.join(projectRoot, tsconfigPath);

const defaultChecker = createComponentMetaCheckerByJsonConfig(
projectRoot,
{ include: ['**/*'] },
checkerOptions
);
const defaultChecker = createCheckerByJson(projectRoot, { include: ['**/*'] }, checkerOptions);

// prefer the tsconfig.json file of the project to support alias resolution etc.
if (await fileExists(projectTsConfigPath)) {
// tsconfig that uses references is currently not supported by vue-component-meta
// see: https://github.com/vuejs/language-tools/issues/3896
// so we return the no-tsconfig defaultChecker if tsconfig references are found
// remove this workaround once the above issue is fixed
// vue-component-meta does currently not resolve tsconfig references (see https://github.com/vuejs/language-tools/issues/3896)
// so we will return the defaultChecker if references are used.
// Otherwise vue-component-meta might not work at all for the Storybook docgen.
const references = await getTsConfigReferences(projectTsConfigPath);
if (references.length > 0) {
// TODO: paths/aliases are not resolvable, find workaround for this
return defaultChecker;
}
return createComponentMetaChecker(projectTsConfigPath, checkerOptions);
if (references.length > 0) return defaultChecker;
return createChecker(projectTsConfigPath, checkerOptions);
}

return defaultChecker;
Expand Down
19 changes: 15 additions & 4 deletions code/frameworks/vue3-vite/src/preset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { dirname, join } from 'path';
import type { PluginOption } from 'vite';
import { vueComponentMeta } from './plugins/vue-component-meta';
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 =>
dirname(require.resolve(join(input, 'package.json'))) as any;
Expand All @@ -20,11 +20,11 @@ export const viteFinal: StorybookConfig['viteFinal'] = async (config, options) =
const frameworkOptions: FrameworkOptions =
typeof framework === 'string' ? {} : framework.options ?? {};

const docgenPlugin = frameworkOptions.docgen ?? 'vue-docgen-api';
const docgen = resolveDocgenOptions(frameworkOptions.docgen);

// add docgen plugin depending on framework option
if (docgenPlugin === 'vue-component-meta') {
plugins.push(await vueComponentMeta());
if (docgen.plugin === 'vue-component-meta') {
plugins.push(await vueComponentMeta(docgen.tsconfig));
} else {
plugins.push(await vueDocgen());
}
Expand All @@ -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;
};
16 changes: 15 additions & 1 deletion code/frameworks/vue3-vite/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
* @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 = {
Expand Down
6 changes: 4 additions & 2 deletions code/lib/cli/src/upgrade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
getStorybookInfo,
loadMainConfig,
JsPackageManagerFactory,
getCoercedStorybookVersion,
} from '@storybook/core-common';
import { automigrate } from './automigrate/index';
import { autoblock } from './autoblock/index';
Expand Down Expand Up @@ -146,10 +147,11 @@ export const doUpgrade = async ({
throw new UpgradeStorybookToSameVersionError({ beforeVersion });
}

const [latestVersion, packageJson] = await Promise.all([
const [latestVersion, packageJson, storybookVersion] = await Promise.all([
//
packageManager.latestVersion('@storybook/cli'),
packageManager.retrievePackageJson(),
getCoercedStorybookVersion(packageManager),
]);

const isOutdated = lt(currentVersion, latestVersion);
Expand Down Expand Up @@ -193,7 +195,7 @@ export const doUpgrade = async ({
const mainConfig = await loadMainConfig({ configDir });

// GUARDS
if (!beforeVersion) {
if (!storybookVersion) {
throw new UpgradeStorybookUnknownCurrentVersionError();
}

Expand Down
28 changes: 28 additions & 0 deletions code/lib/preview-api/src/modules/store/csf/composeConfigs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
expect(
composeConfigs([
Expand Down
Original file line number Diff line number Diff line change
@@ -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',
},
};
Original file line number Diff line number Diff line change
@@ -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} }`,
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<script setup lang="ts">
const model = defineModel<string>();
</script>

<template>
{{ model }}
</template>
Original file line number Diff line number Diff line change
@@ -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>
31 changes: 26 additions & 5 deletions docs/get-started/vue3-vite.md
Original file line number Diff line number Diff line change
Expand Up @@ -275,16 +275,37 @@ The definition above will generate the following controls:

![Controls generated from exposed properties and methods](./vue-component-meta-exposed-types-controls.png)

### 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
// YourComponent.ts
import type { MyProps } from '@/types'; // ❌ Cannot be resolved
import type { MyProps } from '../types'; // ✅ Can be resolved
// .storybook/main.ts
import type { StorybookConfig } from '@storybook/vue3-vite';

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

### Storybook doesn't work with my Vue 2 project
Expand Down
2 changes: 2 additions & 0 deletions scripts/prepare/addon-bundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,10 @@ const run = async ({ cwd, flags }: { cwd: string; flags: string[] }) => {
platform: 'neutral',
external: [...commonExternals, ...globalManagerPackages, ...globalPreviewPackages],
esbuildOptions: (options) => {
/* eslint-disable no-param-reassign */
options.platform = 'neutral';
Object.assign(options, getESBuildOptions(optimized));
/* eslint-enable no-param-reassign */
},
})
);
Expand Down

0 comments on commit 254bd81

Please sign in to comment.