Skip to content

Commit

Permalink
Fix CSF Plugin for Angular
Browse files Browse the repository at this point in the history
  • Loading branch information
valentinpalkovic committed Dec 4, 2023
1 parent 4a90af1 commit ca523d3
Show file tree
Hide file tree
Showing 11 changed files with 1,701 additions and 358 deletions.
32 changes: 21 additions & 11 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, PresetProperty } 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 @@ -202,4 +207,9 @@ const optimizeViteDeps = [
'markdown-to-jsx',
];

export { webpackX as webpack, indexersX as experimental_indexers, docsX as docs, optimizeViteDeps };
export {
webpackX as webpackFinal,
indexersX as experimental_indexers,
docsX as docs,
optimizeViteDeps,
};
6 changes: 3 additions & 3 deletions code/builders/builder-vite/src/plugins/csf-plugin.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Plugin } from 'vite';
import { vite } from '@storybook/csf-plugin';
import type { Options } from '@storybook/types';
// @ts-expect-error - The tsconfig.json in code sets moduleResolution: Node. But to respect `exports` fields from package.json's, we would need to set the moduleResolution field to either "Node16" or "nodenext", which introduces another wave of errors
import CsfVitePlugin from '@storybook/csf-plugin/vite';

export async function csfPlugin(config: Options): Promise<Plugin> {
const { presets } = config;
Expand All @@ -10,6 +11,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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ const getStorySortParameterMock = getStorySortParameter as jest.Mock<

const csfIndexer = async (fileName: string, opts: any) => {
const code = (await fs.readFile(fileName, 'utf-8')).toString();
return loadCsf(code, { ...opts, fileName }).parse();
return loadCsf(code, 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();
return loadCsf(code, code, { ...opts, fileName }).parse();
};

const options: StoryIndexGeneratorOptions = {
Expand Down Expand Up @@ -1168,7 +1168,7 @@ describe('StoryIndexGenerator with deprecated indexer API', () => {
test: /\.stories\.(m?js|ts)x?$/,
createIndex: async (fileName, options) => {
const code = (await fs.readFile(fileName, 'utf-8')).toString();
const csf = loadCsf(code, { ...options, fileName }).parse();
const csf = loadCsf(code, code, { ...options, fileName }).parse();

// eslint-disable-next-line no-underscore-dangle
return Object.entries(csf._stories).map(([exportName, story]) => ({
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": "node --loader ../../../scripts/node_modules/esbuild-register/loader.js -r ../../../scripts/node_modules/esbuild-register/register.js ../../../scripts/prepare/bundle.ts"
},
"dependencies": {
"@storybook/csf-tools": "workspace:*",
"unplugin": "^1.3.1"
"@storybook/csf-tools": "workspace:*"
},
"devDependencies": {
"typescript": "^5.3.2"
"typescript": "^5.3.2",
"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;
44 changes: 44 additions & 0 deletions code/lib/csf-plugin/src/vite.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
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(originalCode, {
makeTitle: (userTitle) => userTitle || 'default',
}).parse();
enrichCsf(csf, options);
const result = formatCsf(csf, { sourceMaps: true });
if (typeof result === 'string') {
return result;
}
return {
code: `${code}\n${result.code}`,
};
} catch (err: any) {
if (!err.message?.startsWith('CSF:')) {
logger.warn(err.message);
}
return {
code,
};
}
},
};
}

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(originalCode, {
makeTitle: (userTitle) => userTitle || 'default',
}).parse();
enrichCsf(csf, options);
const result = formatCsf(csf, { sourceMaps: true });

if (typeof result === 'string') {
callback(null, `${source}\n${result}`, sourceMap);
} else {
callback(null, `${source}\n${result.code}`, sourceMap);
}
} catch (err: any) {
// Handle errors.
if (!err.message?.startsWith('CSF:')) {
logger.warn(err.message);
}

callback(null, source, sourceMap);
}
};

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

0 comments on commit ca523d3

Please sign in to comment.