Skip to content

Commit

Permalink
Angular: Fix csf-plugin usage
Browse files Browse the repository at this point in the history
  • Loading branch information
valentinpalkovic committed Nov 1, 2023
1 parent e1cb740 commit b67f942
Show file tree
Hide file tree
Showing 13 changed files with 681 additions and 310 deletions.
29 changes: 17 additions & 12 deletions code/addons/docs/src/preset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import remarkExternalLinks from 'remark-external-links';
import { dedent } from 'ts-dedent';

import type { DocsOptions, Indexer, Options, StorybookConfig } from '@storybook/types';
import type { CsfPluginOptions } from '@storybook/csf-plugin';
import type { CsfOptions } from '@storybook/csf-plugin';
import type { JSXOptions, CompileOptions } from '@storybook/mdx2-csf';
import { global } from '@storybook/global';
import { loadCsf } from '@storybook/csf-tools';
Expand All @@ -27,7 +27,7 @@ async function webpack(
mdxBabelOptions?: any;
/** @deprecated */
sourceLoaderOptions: any;
csfPluginOptions: CsfPluginOptions | null;
csfPluginOptions: CsfOptions | null;
jsxOptions?: JSXOptions;
mdxPluginOptions?: CompileOptions;
} /* & Parameters<
Expand Down Expand Up @@ -92,17 +92,22 @@ async function webpack(

const result = {
...webpackConfig,
plugins: [
...(webpackConfig.plugins || []),

...(csfPluginOptions
? [(await import('@storybook/csf-plugin')).webpack(csfPluginOptions)]
: []),
],

module: {
...module,
rules: [
...(csfPluginOptions
? [
{
test: /\.(story|stories)\.[tj]sx?$/,
use: [
{
loader: require.resolve('@storybook/csf-plugin/webpack'),
options: csfPluginOptions,
},
],
},
]
: []),
...(module.rules || []),
{
test: /(stories|story)\.mdx$/,
Expand Down Expand Up @@ -141,7 +146,7 @@ export const createStoriesMdxIndexer = (legacyMdx1?: boolean): Indexer => ({
? await import('@storybook/mdx1-csf')
: await import('@storybook/mdx2-csf');
code = await compile(code, {});
const csf = loadCsf(code, { ...opts, fileName }).parse();
const csf = loadCsf(code, code, { ...opts, fileName }).parse();

const { indexInputs, stories } = csf;

Expand Down Expand Up @@ -194,4 +199,4 @@ const docsX = docs as any;

ensureReactPeerDeps();

export { webpackX as webpack, indexersX as experimental_indexers, docsX as docs };
export { webpackX as webpackFinal, indexersX as experimental_indexers, docsX as docs };
5 changes: 2 additions & 3 deletions code/builders/builder-vite/src/plugins/csf-plugin.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Plugin } from 'vite';
import { vite } from '@storybook/csf-plugin';
import CsfVitePlugin from '@storybook/csf-plugin/vite';
import type { StorybookConfig, Options } from '@storybook/types';

export async function csfPlugin(config: Options): Promise<Plugin> {
Expand All @@ -10,6 +10,5 @@ export async function csfPlugin(config: Options): Promise<Plugin> {
// @ts-expect-error - not sure what type to use here
addons.find((a) => [a, a.name].includes('@storybook/addon-docs'))?.options ?? {};

// TODO: looks like unplugin can return an array of plugins
return vite(docsOptions?.csfPluginOptions) as Plugin;
return CsfVitePlugin(docsOptions?.csfPluginOptions) as Plugin;
}
16 changes: 9 additions & 7 deletions code/lib/codemod/src/transforms/csf-2-to-3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ const isSimpleCSFStory = (init: t.Expression, annotations: t.ObjectProperty[]) =
annotations.length === 0 && t.isArrowFunctionExpression(init) && init.params.length === 0;

function removeUnusedTemplates(csf: CsfFile) {
Object.entries(csf._templates).forEach(([template, templateExpression]) => {
Object.entries(csf._originalTemplates).forEach(([template, templateExpression]) => {
const references: NodePath[] = [];
babel.traverse(csf._ast, {
Identifier: (path) => {
Expand All @@ -113,7 +113,7 @@ export default function transform(info: FileInfo, api: API, options: { parser?:
const makeTitle = (userTitle?: string) => {
return userTitle || 'FIXME';
};
const csf = loadCsf(info.source, { makeTitle });
const csf = loadCsf(info.source, info.source, { makeTitle });

try {
csf.parse();
Expand All @@ -132,10 +132,12 @@ export default function transform(info: FileInfo, api: API, options: { parser?:
const importHelper = new StorybookImportHelper(file, info);

const objectExports: Record<string, t.Statement> = {};
Object.entries(csf._storyExports).forEach(([key, decl]) => {
const annotations = Object.entries(csf._storyAnnotations[key]).map(([annotation, val]) => {
return t.objectProperty(t.identifier(renameAnnotation(annotation)), val as t.Expression);
});
Object.entries(csf._originalStoryExports).forEach(([key, decl]) => {
const annotations = Object.entries(csf._originalStoryAnnotations[key]).map(
([annotation, val]) => {
return t.objectProperty(t.identifier(renameAnnotation(annotation)), val as t.Expression);
}
);

if (t.isVariableDeclarator(decl)) {
const { init, id } = decl;
Expand All @@ -162,7 +164,7 @@ export default function transform(info: FileInfo, api: API, options: { parser?:
// export const A = Template.bind({});
const renderAnnotation = isReactGlobalRenderFn(
csf,
template ? csf._templates[template] : storyFn
template ? csf._originalTemplates[template] : storyFn
)
? []
: [t.objectProperty(t.identifier('render'), storyFn)];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ function migrateType(oldType: string) {

export default function transform(info: FileInfo, api: API, options: { parser?: string }) {
// TODO what do I need to with the title?
const csf = loadCsf(info.source, { makeTitle: (title) => title });
const csf = loadCsf(info.source, info.source, { makeTitle: (title) => title });
const fileNode = csf._ast;
// @ts-expect-error File is not yet exposed, see https://github.com/babel/babel/issues/11350#issuecomment-644118606
const file: BabelFile = new babel.File(
Expand Down
25 changes: 20 additions & 5 deletions code/lib/csf-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,24 @@
"license": "MIT",
"sideEffects": false,
"exports": {
".": {
"./index": {
"types": "./dist/index.d.ts",
"node": "./dist/index.js",
"require": "./dist/index.js",
"import": "./dist/index.mjs"
},
"./webpack": {
"types": "./dist/webpack.d.ts",
"node": "./dist/webpack.js",
"require": "./dist/webpack.js",
"import": "./dist/webpack.mjs"
},
"./vite": {
"types": "./dist/vite.d.ts",
"node": "./dist/vite.js",
"require": "./dist/vite.js",
"import": "./dist/vite.mjs"
},
"./package.json": "./package.json"
},
"main": "dist/index.js",
Expand All @@ -44,18 +56,21 @@
"prep": "../../../scripts/prepare/bundle.ts"
},
"dependencies": {
"@storybook/csf-tools": "workspace:*",
"unplugin": "^1.3.1"
"@storybook/csf-tools": "workspace:*"
},
"devDependencies": {
"typescript": "~4.9.3"
"typescript": "~4.9.3",
"vite": "^4.5.0",
"webpack": "^5.89.0"
},
"publishConfig": {
"access": "public"
},
"bundler": {
"entries": [
"./src/index.ts"
"./src/index.ts",
"./src/vite.ts",
"./src/webpack.ts"
],
"externals": [
"webpack",
Expand Down
39 changes: 2 additions & 37 deletions code/lib/csf-plugin/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,5 @@
import { createUnplugin } from 'unplugin';
import fs from 'fs/promises';
import { loadCsf, enrichCsf, formatCsf } from '@storybook/csf-tools';
import type { EnrichCsfOptions } from '@storybook/csf-tools';

export type CsfPluginOptions = EnrichCsfOptions;
export default {};

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

const logger = console;

export const unplugin = createUnplugin<CsfPluginOptions>((options) => {
return {
name: 'unplugin-csf',
enforce: 'pre',
loadInclude(id) {
return STORIES_REGEX.test(id);
},
async load(fname) {
const code = await fs.readFile(fname, 'utf-8');
try {
const csf = loadCsf(code, { makeTitle: (userTitle) => userTitle || 'default' }).parse();
enrichCsf(csf, options);
return formatCsf(csf, { sourceMaps: true });
} catch (err: any) {
// This can be called on legacy storiesOf files, so just ignore
// those errors. But warn about other errors.
if (!err.message?.startsWith('CSF:')) {
logger.warn(err.message);
}
return code;
}
},
};
});

export const { esbuild } = unplugin;
export const { webpack } = unplugin;
export const { rollup } = unplugin;
export const { vite } = unplugin;
export type CsfOptions = EnrichCsfOptions;
43 changes: 43 additions & 0 deletions code/lib/csf-plugin/src/vite.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { loadCsf, enrichCsf, formatCsf } from '@storybook/csf-tools';
import fs from 'fs/promises';
import type { Plugin } from 'vite';
import type { CsfOptions } from '.';

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

const logger = console;

function CsfVitePluginFn(options: CsfOptions = {}): Plugin {
return {
name: 'csf-vite-plugin',

async transform(code: string, id: string) {
if (!STORIES_REGEX.test(id)) {
return null;
}

try {
const originalCode = await fs.readFile(id, 'utf-8');
const csf = loadCsf(code, originalCode, {
makeTitle: (userTitle) => userTitle || 'default',
}).parse();
enrichCsf(csf, options);
const result = formatCsf(csf, { sourceMaps: true });
if (typeof result === 'string') {
return result;
}
return {
code: result.code,
map: result.map,
};
} catch (err: any) {
if (!err.message?.startsWith('CSF:')) {
logger.warn(err.message);
}
return null;
}
},
};
}

export default CsfVitePluginFn as any;
50 changes: 50 additions & 0 deletions code/lib/csf-plugin/src/webpack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import type { LoaderContext } from 'webpack';
import { loadCsf, enrichCsf, formatCsf } from '@storybook/csf-tools';
import fs from 'fs/promises';
import type { CsfOptions } from '.';

type LoaderFunction = (
this: LoaderContext<CsfOptions>,
source: string | Buffer,
sourceMap?: any,
meta?: any
) => void;

const logger = console;

const CsfWebpackLoaderFn: LoaderFunction = async function CsfWebpackLoaderFn(
source,
sourceMap,
meta
) {
// Indicate that the loader is asynchronous.
const callback = this.async();
const filename = this.resourcePath;

// Access the loader options
const options = this.getOptions() || {};

try {
const originalCode = await fs.readFile(filename, 'utf-8');
const csf = loadCsf(source as string, originalCode, {
makeTitle: (userTitle) => userTitle || 'default',
}).parse();
enrichCsf(csf, options);
const result = formatCsf(csf, { sourceMaps: true, inputSourceMap: sourceMap });

if (typeof result === 'string') {
callback(null, result);
} else {
callback(null, result.code, result.map || undefined);
}
} catch (err: any) {
// Handle errors.
if (!err.message?.startsWith('CSF:')) {
logger.warn(err.message);
}
// Pass the error to the callback function.
callback(err);
}
};

export default CsfWebpackLoaderFn as (source: string, sourceMap: any, meta: any) => void;
Loading

0 comments on commit b67f942

Please sign in to comment.