Skip to content

Commit

Permalink
Improve sourcemaps (#437)
Browse files Browse the repository at this point in the history
Turns out we weren't creating good sourcemaps, especially in dev.  It seems that whereas rollup only uses the `mappings`, I guess that vite/esbuild uses the `sources` field of the sourcemap as well, and without passing the `source` option to MagicString's `generateMap`, we were losing the connection.  So, this adds the `id` as the source, and also enables `hires` (high resolution) so that columns are correct and not just lines (useful for code coverage, for example).

I also added MagicString to some of our other plugins which weren't using it.

The most obvious changes are in the react and svelte projects.  Vue is a bit improved, but we're still losing the story file sourcemaps for some reason.

To test, fire up an example project (in dev especially, but good to check prod builds too), look in the sources tab in devtools, and poke around, looking for sourcemapped versions of the files.  You should see them in this branch, but not nearly as many, if any, in main.
  • Loading branch information
IanVS committed Jul 13, 2022
1 parent c055857 commit b93d332
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 23 deletions.
9 changes: 5 additions & 4 deletions packages/builder-vite/inject-export-order-plugin.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { parse } from 'es-module-lexer';
import MagicString from 'magic-string';

export const injectExportOrderPlugin = {
name: 'storybook-vite-inject-export-order-plugin',
Expand All @@ -17,12 +18,12 @@ export const injectExportOrderPlugin = {
// user has defined named exports already
return;
}

const s = new MagicString(code);
const orderedExports = exports.filter((e) => e !== 'default');

s.append(`;export const __namedExportsOrder = ${JSON.stringify(orderedExports)};`);
return {
code: `${code};\nexport const __namedExportsOrder = ${JSON.stringify(orderedExports)};`,
map: null,
code: s.toString(),
map: s.generateMap({ hires: true, source: id }),
};
},
};
14 changes: 11 additions & 3 deletions packages/builder-vite/plugins/mdx-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,26 @@ export function mdxPlugin(options: Options): Plugin {
);
reactRefresh = reactRefreshPlugins.find((p) => p.transform);
},
async transform(code, id, options) {
async transform(src, id, options) {
if (id.match(/\.mdx?$/)) {
// @ts-ignore
const { compile } = features?.previewMdx2
? await import('@storybook/mdx2-csf')
: await import('@storybook/mdx1-csf');

const mdxCode = String(await compile(code, { skipCsf: !isStorybookMdx(id) }));
const mdxCode = String(await compile(src, { skipCsf: !isStorybookMdx(id) }));

const modifiedCode = injectRenderer(mdxCode, Boolean(features?.previewMdx2));

return reactRefresh?.transform!.call(this, modifiedCode, `${id}.jsx`, options);
const result = await reactRefresh?.transform!.call(this, modifiedCode, `${id}.jsx`, options);

if (!result) return modifiedCode;

if (typeof result === 'string') return result;

const { code, map: resultMap } = result;

return { code, map: !resultMap || typeof resultMap === 'string' ? resultMap : { ...resultMap, sources: [id] } };
}
},
};
Expand Down
2 changes: 1 addition & 1 deletion packages/builder-vite/plugins/react-docgen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export function reactDocgen({ include = /\.(mjs|tsx?|jsx?)$/, exclude = [/node_m

return {
code: s.toString(),
map: s.generateMap(),
map: s.generateMap({ hires: true, source: id }),
};
} catch (e) {
// Usually this is just an error from react-docgen that it couldn't find a component
Expand Down
2 changes: 1 addition & 1 deletion packages/builder-vite/plugins/svelte-docgen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export function svelteDocgen(svelteOptions: Record<string, any>): Plugin {

return {
code: s.toString(),
map: s.generateMap(),
map: s.generateMap({ hires: true, source: id }),
};
}
},
Expand Down
2 changes: 1 addition & 1 deletion packages/builder-vite/plugins/vue-docgen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export function vueDocgen(): Plugin {

return {
code: s.toString(),
map: s.generateMap(),
map: s.generateMap({ hires: true, source: id }),
};
}
},
Expand Down
27 changes: 17 additions & 10 deletions packages/builder-vite/source-loader-plugin.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Plugin } from 'vite';
import sourceLoaderTransform from '@storybook/source-loader';
import type { ExtendedOptions } from './types';
import MagicString from 'magic-string';

const storyPattern = /\.stories\.[jt]sx?$/;
const storySourcePattern = /var __STORY__ = "(.*)"/;
Expand All @@ -21,10 +22,13 @@ export function sourceLoaderPlugin(config: ExtendedOptions): Plugin | Plugin[] {
async transform(src: string, id: string) {
if (id.match(storyPattern)) {
const code: string = await sourceLoaderTransform.call(mockClassLoader(id), src);
const s = new MagicString(src);
// Entirely replace with new code
s.overwrite(0, src.length, code);

return {
code,
map: { mappings: '' },
code: s.toString(),
map: s.generateMap({ hires: true, source: id }),
};
}
},
Expand Down Expand Up @@ -53,9 +57,13 @@ export function sourceLoaderPlugin(config: ExtendedOptions): Plugin | Plugin[] {
code = replaceAll(code, sourceString, storySourceReplacement);
}

const s = new MagicString(src);
// Entirely replace with new code
s.overwrite(0, src.length, code);

return {
code,
map: { mappings: '' },
code: s.toString(),
map: s.generateMap(),
};
}
},
Expand All @@ -68,19 +76,18 @@ export function sourceLoaderPlugin(config: ExtendedOptions): Plugin | Plugin[] {
},
async transform(src: string, id: string) {
if (id.match(storyPattern)) {
let code;
const s = new MagicString(src);
const map = storySources.get(config);
const storySourceStatement = map?.get(id);
// Put the previously-extracted source back in
if (storySourceStatement) {
code = replaceAll(src, storySourceReplacement, storySourceStatement);
} else {
code = src;
const newCode = replaceAll(src, storySourceReplacement, storySourceStatement);
s.overwrite(0, src.length, newCode);
}

return {
code,
map: { mappings: '' },
code: s.toString(),
map: s.generateMap(),
};
}
},
Expand Down
12 changes: 9 additions & 3 deletions packages/builder-vite/svelte/csf-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import { extractStories } from '@storybook/addon-svelte-csf/dist/cjs/parser/extr
const parser = require.resolve('@storybook/addon-svelte-csf/dist/esm/parser/collect-stories').replace(/[/\\]/g, '/');
import type { Options } from '@sveltejs/vite-plugin-svelte';
import * as svelte from 'svelte/compiler';
import MagicString from 'magic-string';

export default function csfPlugin(svelteOptions?: Options) {
return {
name: 'storybook-addon-svelte-csf',
enforce: 'post',
async transform(code: string, id: string) {
if (/\.stories\.svelte$/.test(id)) {
const s = new MagicString(code);
const component = getNameFromFilename(id);
let source = readFileSync(id).toString();
if (svelteOptions && svelteOptions.preprocess) {
Expand All @@ -23,22 +25,26 @@ export default function csfPlugin(svelteOptions?: Options) {
.map(([id]) => `export const ${id} = __storiesMetaData.stories[${JSON.stringify(id)}];`)
.join('\n');

const codeWithoutDefaultExport = code.replace('export default ', '// export default ');
s.replace('export default', '// export default');

const namedExportsOrder = Object.entries<any>(stories)
.filter(([, def]) => !def.template)
.map(([id]) => id);

const output = [
codeWithoutDefaultExport,
'',
`import parser from '${parser}';`,
`const __storiesMetaData = parser(${component}, ${JSON.stringify(all)});`,
'export default __storiesMetaData.meta;',
`export const __namedExportsOrder = ${JSON.stringify(namedExportsOrder)};`,
storyDef,
].join('\n');

s.append(output);

return {
code: output,
code: s.toString(),
map: s.generateMap({ hires: true, source: id }),
};
}
},
Expand Down

0 comments on commit b93d332

Please sign in to comment.