Maintain WP back-compat by using tuple of [bare, absolute]

This commit is contained in:
Ian VanSchooten 2022-11-08 10:13:08 -05:00
parent 50826f29ad
commit b79386896b
6 changed files with 62 additions and 29 deletions

View File

@ -2,14 +2,7 @@ import { isAbsolute, resolve } from 'path';
import { getRendererName } from '@storybook/core-common';
import { virtualPreviewFile, virtualStoriesFile } from './virtual-file-names';
import type { ExtendedOptions } from './types';
function resolveRelativePath(path: string) {
// resolve relative paths into absolute paths, but don't resolve "bare" imports
if (path?.startsWith('./') || path?.startsWith('../')) {
return resolve(path);
}
return path;
}
import { processPreviewAnnotation } from './utils/process-preview-annotation';
export async function generateIframeScriptCode(options: ExtendedOptions) {
const { presets } = options;
@ -22,7 +15,10 @@ export async function generateIframeScriptCode(options: ExtendedOptions) {
const absoluteFilesToImport = (files: string[], name: string) =>
files
.map((el, i) => `import ${name ? `* as ${name}_${i} from ` : ''}'${resolveRelativePath(el)}'`)
.map(
(el, i) =>
`import ${name ? `* as ${name}_${i} from ` : ''}'${processPreviewAnnotation(el)}'`
)
.join('\n');
const importArray = (name: string, length: number) =>

View File

@ -2,22 +2,21 @@ import { resolve } from 'path';
import { loadPreviewOrConfigFile, getFrameworkName } from '@storybook/core-common';
import { virtualStoriesFile, virtualAddonSetupFile } from './virtual-file-names';
import type { ExtendedOptions } from './types';
import { processPreviewAnnotation } from './utils/process-preview-annotation';
export async function generateModernIframeScriptCode(options: ExtendedOptions) {
const { presets, configDir } = options;
const frameworkName = await getFrameworkName(options);
const previewOrConfigFile = loadPreviewOrConfigFile({ configDir });
const previewAnnotations = await presets.apply('previewAnnotations', [], options);
const previewAnnotations = await presets.apply<(string | string[])[]>(
'previewAnnotations',
[],
options
);
const relativePreviewAnnotations = [...previewAnnotations, previewOrConfigFile]
.filter(Boolean)
.map((configEntry) => {
// resolve relative paths into absolute paths, but don't resolve "bare" imports
if (configEntry?.startsWith('./') || configEntry?.startsWith('../')) {
return resolve(configEntry);
}
return configEntry;
});
.map(processPreviewAnnotation);
// eslint-disable-next-line @typescript-eslint/no-shadow
const generateHMRHandler = (frameworkName: string): string => {

View File

@ -0,0 +1,21 @@
import { resolve } from 'path';
/**
* Preview annotations can take several forms, and vite needs them to be a bit more restrained.
* For node_modules, we want bare imports (so vite can process them), and for files in the user's source,
* we want absolute paths.
*/
export function processPreviewAnnotation(path: string | string[] | undefined) {
// If entry is a tuple, take the first, which is the non-absolute path.
// This is so that webpack can use an absolute path (the second item in the tuple), and
// continue supporting super-addons in pnp/pnpm without requiring them to re-export their
// sub-addons as we do in addon-essentials.
if (Array.isArray(path)) {
return path[0];
}
// resolve relative paths into absolute paths, but don't resolve "bare" imports
if (path?.startsWith('./') || path?.startsWith('../')) {
return resolve(path);
}
return path;
}

View File

@ -82,7 +82,15 @@ export default async (
const docsOptions = await presets.apply<DocsOptions>('docs');
const previewAnnotations = [
...(await presets.apply('previewAnnotations', [], options)),
...(await presets.apply('previewAnnotations', [], options)).map((entry) => {
// If entry is a tuple, take the second, which is the absolute path.
// This is to maintain back-compat with community addons that bundle other addons.
// The vite builder uses the first element of the tuple, which is the bare import.
if (Array.isArray(entry)) {
return entry[1];
}
return entry;
}),
loadPreviewOrConfigFile(options),
].filter(Boolean);
const entries = (await presets.apply('entries', [], options)) as string[];

View File

@ -86,16 +86,19 @@ export const resolveAddonName = (
return undefined;
};
const path = name;
// This is used to maintain back-compat with community addons that do not re-export their sub-addons but reference
// the sub-addon name directly. We need to turn it into an absolute path so that webpack can serve it up correctly
// when yarn pnp or pnpm is being used. Vite will be broken in such cases, because it does not process absolute paths,
// and it will try to import from the bare import, breaking in pnp/pnpm.
const absolutizeExport = (exportName: string) => {
return resolve(`${name}${exportName}`);
};
// We don't want to resolve an import path (e.g. '@addons/foo/preview') to the file on disk,
// because you are not allowed to import arbitrary files in packages in Vite.
// Instead we check if the export exists and "absolutize" it.
const managerFile = checkExists(`/manager`);
const registerFile = checkExists(`/register`) || checkExists(`/register-panel`);
const managerFile = absolutizeExport(`/manager`);
const registerFile = absolutizeExport(`/register`) || absolutizeExport(`/register-panel`);
const previewFile = checkExists(`/preview`);
// Presets are imported by node, so therefore fine to be a path on disk (at this stage anyway)
const presetFile = resolve(`${path}/preset`);
const previewFileAbsolute = absolutizeExport('/preview');
const presetFile = absolutizeExport(`/preset`);
if (!(managerFile || previewFile) && presetFile) {
return {
@ -117,9 +120,15 @@ export const resolveAddonName = (
return {
type: 'virtual',
name: path,
name,
...(managerEntries.length ? { managerEntries } : {}),
...(previewFile ? { previewAnnotations: [previewFile] } : {}),
...(previewFile
? {
previewAnnotations: [
previewFileAbsolute ? [previewFile, previewFileAbsolute] : [previewFile],
],
}
: {}),
...(presetFile ? { presets: [{ name: presetFile, options }] } : {}),
};
}

View File

@ -466,7 +466,7 @@ export interface CoreCommon_ResolvedAddonVirtual {
type: 'virtual';
name: string;
managerEntries?: string[];
previewAnnotations?: string[];
previewAnnotations?: (string | string[])[];
presets?: (string | { name: string; options?: any })[];
}