Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Core: Update index generation to use tags to detect MDX stories #19712

Merged
merged 10 commits into from
Nov 7, 2022
4 changes: 2 additions & 2 deletions code/addons/docs/jest-transform-mdx.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ const path = require('path');
const { ScriptTransformer } = require('@jest/transform');
const { dedent } = require('ts-dedent');

const { compileAsync } = require('@storybook/mdx2-csf');
const { compile } = require('@storybook/mdx2-csf');

module.exports = {
async processAsync(src, filename, config, { instrument }) {
const code = await compileAsync(src, { skipCsf: false });
const code = await compile(src, { skipCsf: false });
const result = dedent`
/* @jsx mdx */
import React from 'react'
Expand Down
4 changes: 1 addition & 3 deletions code/addons/docs/src/preset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,10 +160,9 @@ export async function webpack(
return result;
}

export const storyIndexers = async (indexers: CoreCommon_StoryIndexer[] | null) => {
export const storyIndexers = (indexers: CoreCommon_StoryIndexer[] | null) => {
const mdxIndexer = async (fileName: string, opts: CoreCommon_IndexerOptions) => {
let code = (await fs.readFile(fileName, 'utf-8')).toString();
// @ts-expect-error (Converted from ts-ignore)
const { compile } = await import('@storybook/mdx2-csf');
code = await compile(code, {});
return loadCsf(code, { ...opts, fileName }).parse();
Expand All @@ -172,7 +171,6 @@ export const storyIndexers = async (indexers: CoreCommon_StoryIndexer[] | null)
{
test: /(stories|story)\.mdx$/,
indexer: mdxIndexer,
addDocsTemplate: true,
},
...(indexers || []),
];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Meta, Story, Canvas } from '@storybook/addon-docs';
import { Meta, Story, Canvas, ArgsTable } from '@storybook/addon-docs';
import globalThis from 'global';
import * as Csf from './csf-in-mdx.stories.js';

Expand Down
1 change: 0 additions & 1 deletion code/lib/builder-vite/src/plugins/mdx-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ export function mdxPlugin(): Plugin {
async transform(src, id, options) {
if (!filter(id)) return undefined;

// @ts-expect-error typescript doesn't think compile exists, but it does.
const { compile } = await import('@storybook/mdx2-csf');

const mdxCode = String(await compile(src, { skipCsf: !isStorybookMdx(id) }));
Expand Down
3 changes: 1 addition & 2 deletions code/lib/client-api/src/StoryStoreFacade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,7 @@ export class StoryStoreFacade<TFramework extends AnyFramework> {
docsOptions.docsPage === 'automatic' ||
(docsOptions.docsPage && componentTags.includes('docsPage'));
if (docsOptions.enabled && storyExports.length) {
// We will use tags soon and this crappy filename test will go away
if (fileName.match(/\.mdx$/) || docsPageOptedIn) {
if (componentTags.includes('mdx') || docsPageOptedIn) {
const name = docsOptions.defaultName;
const docsId = toId(componentId || title, name);
this.entries[docsId] = {
Expand Down
3 changes: 2 additions & 1 deletion code/lib/core-client/src/start.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -961,7 +961,7 @@ describe('start', () => {
'test',
makeRequireContext({
'./Introduction.stories.mdx': {
default: { title: 'Introduction' },
default: { title: 'Introduction', tags: ['mdx'] },
_Page: { name: 'Page', parameters: { docsOnly: true } },
},
})
Expand All @@ -979,6 +979,7 @@ describe('start', () => {
"standalone": false,
"storiesImports": Array [],
"tags": Array [
"mdx",
"docs",
],
"title": "Introduction",
Expand Down
46 changes: 25 additions & 21 deletions code/lib/core-server/src/utils/StoryIndexGenerator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ jest.mock('@storybook/docs-mdx', async () => ({
const name = content.match(/name=['"](.*)['"]/)?.[1];
const ofMatch = content.match(/of=\{(.*)\}/)?.[1];
const isTemplate = content.match(/isTemplate/);
return { title, name, imports, of: ofMatch && imports.length && imports[0], isTemplate };
const tags = ['mdx'];
return { title, name, tags, imports, of: ofMatch && imports.length && imports[0], isTemplate };
},
}));

Expand All @@ -50,12 +51,20 @@ const csfIndexer = async (fileName: string, opts: any) => {
return loadCsf(code, { ...opts, fileName }).parse();
};

const storiesMdxIndexer = async (fileName: string, opts: any) => {
let code = (await fs.readFile(fileName, 'utf-8')).toString();
const { compile } = await import('@storybook/mdx2-csf');
code = await compile(code, {});
return loadCsf(code, { ...opts, fileName }).parse();
};

const options = {
configDir: path.join(__dirname, '__mockdata__'),
workingDir: path.join(__dirname, '__mockdata__'),
storyIndexers: [
{ test: /\.stories\..*$/, indexer: csfIndexer as any as CoreCommon_StoryIndexer['indexer'] },
],
{ test: /\.stories\.mdx$/, indexer: storiesMdxIndexer },
{ test: /\.stories\.(js|ts)x?$/, indexer: csfIndexer },
] as CoreCommon_StoryIndexer[],
storiesV2Compatibility: false,
storyStoreV7: true,
docs: { enabled: true, defaultName: 'docs', docsPage: false },
Expand Down Expand Up @@ -232,47 +241,43 @@ describe('StoryIndexGenerator', () => {
});
});

describe('addDocsTemplate indexer', () => {
const templateIndexer = { ...options.storyIndexers[0], addDocsTemplate: true };

describe('mdx tagged components', () => {
it('adds docs entry with docs enabled', async () => {
const specifier: CoreCommon_NormalizedStoriesSpecifier = normalizeStoriesEntry(
'./src/A.stories.js',
'./src/nested/Page.stories.mdx',
options
);

const generator = new StoryIndexGenerator([specifier], {
...options,
storyIndexers: [templateIndexer],
});
await generator.initialize();

expect(await generator.getIndex()).toMatchInlineSnapshot(`
Object {
"entries": Object {
"a--docs": Object {
"id": "a--docs",
"importPath": "./src/A.stories.js",
"page--docs": Object {
"id": "page--docs",
"importPath": "./src/nested/Page.stories.mdx",
"name": "docs",
"standalone": false,
"storiesImports": Array [],
"tags": Array [
"component-tag",
"docsPage",
"mdx",
"docs",
],
"title": "A",
"title": "Page",
"type": "docs",
},
"a--story-one": Object {
"id": "a--story-one",
"importPath": "./src/A.stories.js",
"name": "Story One",
"page--story-one": Object {
"id": "page--story-one",
"importPath": "./src/nested/Page.stories.mdx",
"name": "StoryOne",
"tags": Array [
"story-tag",
"mdx",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just confirming that the mdx tag here means that the story was generated from MDX. Do we want that? It could be confusing

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was intentional on my part anyway. Happy to change the tag from mdx if it is confusing that a story can be "mdx". To me it makes sense.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WFM after letting it settle in

"story",
],
"title": "A",
"title": "Page",
"type": "story",
},
},
Expand All @@ -288,7 +293,6 @@ describe('StoryIndexGenerator', () => {

const generator = new StoryIndexGenerator([specifier], {
...options,
storyIndexers: [templateIndexer],
docs: { enabled: false },
});
await generator.initialize();
Expand Down
7 changes: 4 additions & 3 deletions code/lib/core-server/src/utils/StoryIndexGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,9 +227,10 @@ export class StoryIndexGenerator {
const { docsPage } = this.options.docs;
const docsPageOptedIn =
docsPage === 'automatic' || (docsPage && componentTags.includes('docsPage'));
// We always add a template for *.stories.mdx, but only if docs page is enabled for
// regular CSF files
if (storyIndexer.addDocsTemplate || docsPageOptedIn) {
// We need a docs entry attached to the CSF file if either:
// a) it is a stories.mdx transpiled to CSF, OR
// b) we have docs page enabled for this file
if (componentTags.includes('mdx') || docsPageOptedIn) {
const name = this.options.docs.defaultName;
const id = toId(csf.meta.title, name);
entries.unshift({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Meta, Story } from '@storybook/addon-docs';

<Meta component={{}} />;
<Meta component={{}} />

<Story name="StoryOne" />
1 change: 0 additions & 1 deletion code/lib/types/src/modules/core-common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,6 @@ export interface CoreCommon_StoryIndex {
export interface CoreCommon_StoryIndexer {
test: RegExp;
indexer: (fileName: string, options: CoreCommon_IndexerOptions) => Promise<CoreCommon_StoryIndex>;
addDocsTemplate?: boolean;
}

/**
Expand Down
32 changes: 3 additions & 29 deletions code/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2159,17 +2159,6 @@ __metadata:
languageName: node
linkType: hard

"@babel/types@npm:^7.14.8":
version: 7.20.0
resolution: "@babel/types@npm:7.20.0"
dependencies:
"@babel/helper-string-parser": ^7.19.4
"@babel/helper-validator-identifier": ^7.19.1
to-fast-properties: ^2.0.0
checksum: 8b9c960eb013142eaf6294d77b75e469b7e97461bd7ad939e625ed74865fbf5a1c20b7989ec3357d0f4ffd93dd79d6daead08c0c06647815d8bbe94dae445f5c
languageName: node
linkType: hard

"@base2/pretty-print-object@npm:1.0.1":
version: 1.0.1
resolution: "@base2/pretty-print-object@npm:1.0.1"
Expand Down Expand Up @@ -6935,19 +6924,11 @@ __metadata:
linkType: soft

"@storybook/mdx2-csf@npm:next":
version: 0.1.0-next.3
resolution: "@storybook/mdx2-csf@npm:0.1.0-next.3"
version: 0.1.0-next.4
resolution: "@storybook/mdx2-csf@npm:0.1.0-next.4"
dependencies:
"@babel/generator": ^7.12.11
"@babel/parser": ^7.12.11
"@babel/types": ^7.14.8
"@mdx-js/mdx": ^2.0.0
estree-to-babel: ^4.9.0
hast-util-to-estree: ^2.0.2
js-string-escape: ^1.0.1
loader-utils: ^2.0.0
lodash: ^4.17.21
checksum: b8cf49e6549507b0e176191ce58f2fb9ab152383e54c73d665414bd5013dc0b90d3cddc814e396563e6af7164b762f75a6a488091f2b46aa33b3fcbd89a12e70
checksum: 206f3fea03db7aad37873653e7c98cdda28c27253eef26df5e5cff7943770c404af839a250c6e9035604670362810847e7103a5834af0632cfd16576dd386c1f
languageName: node
linkType: hard

Expand Down Expand Up @@ -22895,13 +22876,6 @@ __metadata:
languageName: node
linkType: hard

"js-string-escape@npm:^1.0.1":
version: 1.0.1
resolution: "js-string-escape@npm:1.0.1"
checksum: 2c33b9ff1ba6b84681c51ca0997e7d5a1639813c95d5b61cb7ad47e55cc28fa4a0b1935c3d218710d8e6bcee5d0cd8c44755231e3a4e45fc604534d9595a3628
languageName: node
linkType: hard

"js-stringify@npm:^1.0.2":
version: 1.0.2
resolution: "js-stringify@npm:1.0.2"
Expand Down