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

Addon-docs: Replace source-loader with csf-plugin #19680

Merged
merged 23 commits into from
Nov 1, 2022
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
2aff120
CSF-tools: Add source extraction WIP
shilman Oct 28, 2022
45a8482
Clean up tests
shilman Oct 28, 2022
ff964c0
Reorder tests to avoid confusoin
shilman Oct 28, 2022
f7edd49
Add csf-plugin to replace source-loader
shilman Oct 29, 2022
52fab18
Merge branch 'next' into shilman/csf-plugin
shilman Oct 29, 2022
f088942
Merge branch 'next' into shilman/csf-plugin
shilman Oct 29, 2022
a1ca59d
Fix linting errors
shilman Oct 29, 2022
0e93478
Update code/lib/csf-plugin/README.md
shilman Oct 29, 2022
96ca5a9
Merge branch 'shilman/csf-plugin' of github.com:storybookjs/storybook…
shilman Oct 29, 2022
924e4df
Delete index.test.ts
shilman Oct 29, 2022
4a9fc91
CSF plugin: Turn story comments into docs desciptions
shilman Oct 29, 2022
2c4c25d
Added some testcases
shilman Oct 29, 2022
87b2781
Turn this into a loader
shilman Oct 30, 2022
6bbe7f3
Preserve indentation & cleanup
shilman Oct 30, 2022
a7cb5c2
Merge branch 'next' into shilman/csf-plugin
shilman Oct 30, 2022
7d740f9
Provide migration instructions for source-loader
shilman Oct 30, 2022
d0cddf5
Fix csf-plugin to load "pre" & async for perf
shilman Oct 31, 2022
ec5dc1c
CSF-tools: Fix parameters merge for enrichCsf
shilman Oct 31, 2022
ffc9553
CsfPlugin: Fix options handling, add tests
shilman Oct 31, 2022
789a21b
Fix typo [ci skip]
shilman Oct 31, 2022
5954bd8
Fix comment [ci skip]
shilman Nov 1, 2022
75f1cb6
Merge pull request #19684 from storybookjs/shilman/csf-plugin-docgen-…
shilman Nov 1, 2022
498aa5f
Fix deepscan [ci skip]
shilman Nov 1, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
- [Configuring the Docs Container](#configuring-the-docs-container)
- [External Docs](#external-docs)
- [MDX2 upgrade](#mdx2-upgrade)
- [Dropped source loader / storiesOf static snippets](#dropped-source-loader--storiesof-static-snippets)
- [Dropped addon-docs manual configuration](#dropped-addon-docs-manual-configuration)
- [7.0 Deprecations](#70-deprecations)
- [`Story` type deprecated](#story-type-deprecated)
Expand Down Expand Up @@ -737,6 +738,33 @@ We will update this section with specific pointers based on user feedback during

As part of the upgrade we deleted the codemod `mdx-to-csf` and will be replacing it with a more sophisticated version prior to release.

#### Dropped source loader / storiesOf static snippets

In SB 6.x, Storybook Docs used a webpack loader called `source-loader` to help display static code snippets. This was configurable using the `options.sourceLoaderOptions` field.

In SB 7.0, we've moved to a faster, simpler alternative called `csf-plugin` that **only supports CSF**. It is configurable using the `options.csfPluginOptions` field.

If you're using `storiesOf` and want to restore the previous behavior, you can add `source-loader` by hand to your webpack config using the following snippet in `main.js`:

```js
module.exports = {
webpackFinal: (config) => {
config.modules.rules.push({
test: /\.stories\.[tj]sx?$/,
use: [
{
loader: require.resolve('@storybook/source-loader'),
options: {} /* your sourceLoaderOptions here */
},
],
enforce: 'pre',
})
return config;
}
}
```


#### Dropped addon-docs manual configuration

Storybook Docs 5.x shipped with instructions for how to manually configure webpack and storybook without the use of Storybook's "presets" feature. Over time, these docs went out of sync. Now in Storybook 7 we have removed support for manual configuration entirely.
Expand Down
4 changes: 2 additions & 2 deletions code/addons/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ module.exports = {
options: {
configureJSX: true,
babelOptions: {},
sourceLoaderOptions: null,
csfPluginOptions: null,
transcludeMarkdown: true,
},
},
Expand All @@ -152,7 +152,7 @@ module.exports = {

The `configureJSX` option is useful when you're writing your docs in MDX and your project's babel config isn't already set up to handle JSX files. `babelOptions` is a way to further configure the babel processor when you're using `configureJSX`.

`sourceLoaderOptions` is an object for configuring `@storybook/source-loader`. When set to `null` it tells docs not to run the `source-loader` at all, which can be used as an optimization, or if you're already using `source-loader` in your `main.js`.
`csfPluginOptions` is an object for configuring `@storybook/csf-plugin`. When set to `null` it tells docs not to run the `csf-plugin` at all, which can be used as an optimization, or if you're already using `csf-plugin` in your `main.js`.

The `transcludeMarkdown` option enables mdx files to import `.md` files and render them as a component.

Expand Down
4 changes: 2 additions & 2 deletions code/addons/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,13 @@
"@storybook/components": "7.0.0-alpha.46",
"@storybook/core-common": "7.0.0-alpha.46",
"@storybook/core-events": "7.0.0-alpha.46",
"@storybook/csf-plugin": "7.0.0-alpha.46",
"@storybook/csf-tools": "7.0.0-alpha.46",
"@storybook/docs-tools": "7.0.0-alpha.46",
"@storybook/mdx2-csf": "0.1.0-next.0",
"@storybook/mdx2-csf": "next",
"@storybook/node-logger": "7.0.0-alpha.46",
"@storybook/postinstall": "7.0.0-alpha.46",
"@storybook/preview-web": "7.0.0-alpha.46",
"@storybook/source-loader": "7.0.0-alpha.46",
"@storybook/store": "7.0.0-alpha.46",
"@storybook/theming": "7.0.0-alpha.46",
"@storybook/types": "7.0.0-alpha.46",
Expand Down
27 changes: 12 additions & 15 deletions code/addons/docs/src/preset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type {
DocsOptions,
Options,
} from '@storybook/types';
import type { CsfPluginOptions } from '@storybook/csf-plugin';
import { logger } from '@storybook/node-logger';
import { loadCsf } from '@storybook/csf-tools';

Expand Down Expand Up @@ -48,7 +49,10 @@ function createBabelOptions({ babelOptions, mdxBabelOptions, configureJSX }: Bab
export async function webpack(
webpackConfig: any = {},
options: Options &
BabelParams & { sourceLoaderOptions: any; transcludeMarkdown: boolean } /* & Parameters<
BabelParams & {
csfPluginOptions: CsfPluginOptions | null;
transcludeMarkdown: boolean;
} /* & Parameters<
typeof createCompiler
>[0] */
) {
Expand All @@ -62,7 +66,7 @@ export async function webpack(
babelOptions,
mdxBabelOptions,
configureJSX = true,
sourceLoaderOptions = { injectStoryParameters: true },
Copy link
Member

Choose a reason for hiding this comment

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

Would it make sense to still accept this property with the purpose of warning users/throwing an error and directing them to the migration docs?

Copy link
Member Author

Choose a reason for hiding this comment

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

Great idea! 💯

csfPluginOptions = {},
transcludeMarkdown = false,
} = options;

Expand All @@ -76,18 +80,6 @@ export async function webpack(

const mdxLoader = require.resolve('@storybook/mdx2-csf/loader');

// set `sourceLoaderOptions` to `null` to disable for manual configuration
const sourceLoader = sourceLoaderOptions
? [
{
test: /\.(stories|story)\.[tj]sx?$/,
loader: require.resolve('@storybook/source-loader'),
options: { ...sourceLoaderOptions, inspectLocalDependencies: true },
enforce: 'pre',
},
]
: [];

let rules = module.rules || [];
if (transcludeMarkdown) {
rules = [
Expand All @@ -110,6 +102,12 @@ export async function webpack(

const result = {
...webpackConfig,
plugins: [
...(webpackConfig.plugins || []),
// eslint-disable-next-line global-require
...(csfPluginOptions ? [require('@storybook/csf-plugin').webpack(csfPluginOptions)] : []),
],

module: {
...module,
rules: [
Expand Down Expand Up @@ -144,7 +142,6 @@ export async function webpack(
},
],
},
...sourceLoader,
],
},
};
Expand Down
2 changes: 1 addition & 1 deletion code/lib/builder-vite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"@storybook/client-api": "7.0.0-alpha.46",
"@storybook/client-logger": "7.0.0-alpha.46",
"@storybook/core-common": "7.0.0-alpha.46",
"@storybook/mdx2-csf": "0.1.0-next.0",
"@storybook/mdx2-csf": "next",
"@storybook/node-logger": "7.0.0-alpha.46",
"@storybook/preview-web": "7.0.0-alpha.46",
"@storybook/source-loader": "7.0.0-alpha.46",
Expand Down
26 changes: 26 additions & 0 deletions code/lib/csf-plugin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# CSF Plugin

The CSF plugin reads CSF files and enriches their content via static analysis.
It supports Webpack, Vite, and other bundlers using [unplugin](https://github.com/unjs/unplugin).

## Source snippets

CSF plugin can add static source snippets to each story. For example:

```js
export const Basic = () => <Button />;
```

Would be transformed to:

```js
export const Basic = () => <Button />;
Basic.parameers = {
shilman marked this conversation as resolved.
Show resolved Hide resolved
storySource: {
source: '() => <Button />',
},
...Basic.parameters,
};
```

This allows `@storybook/addon-docs` to display the static source snippet.
60 changes: 60 additions & 0 deletions code/lib/csf-plugin/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
{
"name": "@storybook/csf-plugin",
"version": "7.0.0-alpha.46",
"description": "Enrich CSF files via static analysis",
"keywords": [
"storybook"
],
"homepage": "https://github.com/storybookjs/storybook/tree/main/lib/csf-plugin",
"bugs": {
"url": "https://github.com/storybookjs/storybook/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/storybookjs/storybook.git",
"directory": "lib/csf-plugin"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/storybook"
},
"license": "MIT",
"sideEffects": false,
"exports": {
".": {
"require": "./dist/cjs/index.js",
"import": "./dist/esm/index.mjs",
"types": "./dist/types/index.d.ts"
},
"./package.json": "./package.json"
},
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
"types": "dist/types/index.d.ts",
"files": [
"dist/**/*",
"README.md",
"*.js",
"*.d.ts"
],
"scripts": {
"check": "../../../scripts/node_modules/.bin/tsc --noEmit",
"prep": "node ../../../scripts/prepare.js"
Copy link
Member

Choose a reason for hiding this comment

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

@shilman was there a reason not to use tsup for bundling this?

},
"dependencies": {
"@storybook/csf-tools": "7.0.0-alpha.46",
"unplugin": "^0.10.2"
},
"devDependencies": {
"typescript": "~4.6.3"
},
"publishConfig": {
"access": "public"
},
"bundler": {
"entries": [
"./src/index.ts"
]
},
"gitHead": "3ef14366115c56c1d45c0359ff681cc47ed50532"
}
Empty file.
31 changes: 31 additions & 0 deletions code/lib/csf-plugin/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { createUnplugin } from 'unplugin';
import { loadCsf, enrichCsf, formatCsf } from '@storybook/csf-tools';

export interface CsfPluginOptions {
source?: boolean;
}

const STORIES_REGEX = /\.(story|stories)\.[tj]sx?$/;

const logger = console;

export const unplugin = createUnplugin((options: CsfPluginOptions) => {
return {
name: 'unplugin-csf',
transformInclude(id) {
return STORIES_REGEX.test(id);
},
transform(code) {
try {
const csf = loadCsf(code, { makeTitle: (userTitle) => userTitle || 'default' }).parse();
enrichCsf(csf);
return formatCsf(csf);
} catch (err: any) {
logger.warn(err.message);
return code;
}
},
};
});

export const { vite, rollup, webpack, esbuild } = unplugin;
15 changes: 15 additions & 0 deletions code/lib/csf-plugin/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"strict": true
},
"include": ["src/**/*"],
"exclude": [
"src/**/*.test.*",
"src/**/tests/**/*",
"src/**/__tests__/**/*",
"src/**/*.stories.*",
"src/**/*.mockdata.*",
"src/**/__testfixtures__/**"
]
}
1 change: 1 addition & 0 deletions code/lib/csf-tools/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"devDependencies": {
"@babel/generator": "^7.12.11",
"@babel/parser": "^7.12.11",
"@babel/template": "^7.12.11",
"@babel/traverse": "^7.12.11",
"@types/fs-extra": "^9.0.6",
"js-yaml": "^3.14.1",
Expand Down
1 change: 0 additions & 1 deletion code/lib/csf-tools/src/CsfFile.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { dedent } from 'ts-dedent';
import yaml from 'js-yaml';
import { loadCsf } from './CsfFile';

// @ts-expect-error (Converted from ts-ignore)
expect.addSnapshotSerializer({
print: (val: any) => yaml.dump(val).trimEnd(),
test: (val) => typeof val !== 'string',
Expand Down
22 changes: 22 additions & 0 deletions code/lib/csf-tools/src/CsfFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,28 @@ export class CsfFile {
this._meta = meta;
}

getStoryExport(key: string) {
let node = this._storyExports[key] as t.Node;
node = t.isVariableDeclarator(node) ? node.init : node;
if (t.isCallExpression(node)) {
const { callee, arguments: bindArguments } = node;
if (
t.isMemberExpression(callee) &&
t.isIdentifier(callee.object) &&
t.isIdentifier(callee.property) &&
callee.property.name === 'bind' &&
(bindArguments.length === 0 ||
(bindArguments.length === 1 &&
t.isObjectExpression(bindArguments[0]) &&
bindArguments[0].properties.length === 0))
) {
const { name } = callee.object;
node = this._templates[name];
}
}
return node;
}

parse() {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const self = this;
Expand Down
Loading