mirror of
https://github.com/storybookjs/storybook.git
synced 2025-04-06 06:31:27 +08:00
Merge pull request #11178 from storybookjs/fix/9819-addon-order
Core: Fix addon load order
This commit is contained in:
commit
7f137ec004
@ -1 +1 @@
|
|||||||
export const version = '6.0.0-beta.28';
|
export const version = '6.0.0-beta.29';
|
||||||
|
@ -43,7 +43,7 @@ const resolvePresetFunction = (input, presetOptions, storybookOptions) => {
|
|||||||
const isLocalFileImport = (packageName) => fs.existsSync(packageName);
|
const isLocalFileImport = (packageName) => fs.existsSync(packageName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse an addon into either a managerEntry or a preset. Throw on invalid input.
|
* Parse an addon into either a managerEntries or a preset. Throw on invalid input.
|
||||||
*
|
*
|
||||||
* Valid inputs:
|
* Valid inputs:
|
||||||
* - '@storybook/addon-actions/register'
|
* - '@storybook/addon-actions/register'
|
||||||
@ -94,34 +94,32 @@ export const resolveAddonName = (name) => {
|
|||||||
return { name, type: 'presets' };
|
return { name, type: 'presets' };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const splitAddons = (addons) => {
|
export const map = (item) => {
|
||||||
return addons.reduce(
|
|
||||||
(acc, item) => {
|
|
||||||
try {
|
try {
|
||||||
if (isObject(item)) {
|
if (isObject(item)) {
|
||||||
const { name } = resolveAddonName(item.name);
|
const { name } = resolveAddonName(item.name);
|
||||||
acc.presets.push({ ...item, name });
|
return { ...item, name };
|
||||||
} else {
|
|
||||||
const { name, type } = resolveAddonName(item);
|
|
||||||
acc[type].push(name);
|
|
||||||
}
|
}
|
||||||
|
const { name, type } = resolveAddonName(item);
|
||||||
|
if (type === 'managerEntries') {
|
||||||
|
return {
|
||||||
|
name: `${name}_additionalManagerEntries`,
|
||||||
|
type,
|
||||||
|
managerEntries: [name],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return resolveAddonName(name);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error(
|
logger.error(
|
||||||
`Addon value should end in /register OR it should be a valid preset https://storybook.js.org/docs/presets/introduction/\n${item}`
|
`Addon value should end in /register OR it should be a valid preset https://storybook.js.org/docs/presets/introduction/\n${item}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return acc;
|
return undefined;
|
||||||
},
|
|
||||||
{
|
|
||||||
managerEntries: [],
|
|
||||||
presets: [],
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function interopRequireDefault(filePath) {
|
function interopRequireDefault(filePath) {
|
||||||
// eslint-disable-next-line global-require,import/no-dynamic-require
|
// eslint-disable-next-line global-require,import/no-dynamic-require
|
||||||
const result = require(`${filePath}`);
|
const result = require(filePath);
|
||||||
|
|
||||||
const isES6DefaultExported =
|
const isES6DefaultExported =
|
||||||
typeof result === 'object' && result !== null && typeof result.default !== 'undefined';
|
typeof result === 'object' && result !== null && typeof result.default !== 'undefined';
|
||||||
@ -129,11 +127,22 @@ function interopRequireDefault(filePath) {
|
|||||||
return isES6DefaultExported ? result.default : result;
|
return isES6DefaultExported ? result.default : result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadPreset(input, level, storybookOptions) {
|
function getContent(input) {
|
||||||
|
if (input.type === 'managerEntries') {
|
||||||
|
const { type, name, ...rest } = input;
|
||||||
|
return rest;
|
||||||
|
}
|
||||||
|
const name = input.name ? input.name : input;
|
||||||
|
|
||||||
|
return interopRequireDefault(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function loadPreset(input, level, storybookOptions) {
|
||||||
try {
|
try {
|
||||||
const name = input.name ? input.name : input;
|
const name = input.name ? input.name : input;
|
||||||
const presetOptions = input.options ? input.options : {};
|
const presetOptions = input.options ? input.options : {};
|
||||||
let contents = interopRequireDefault(name);
|
|
||||||
|
let contents = getContent(input);
|
||||||
|
|
||||||
if (typeof contents === 'function') {
|
if (typeof contents === 'function') {
|
||||||
// allow the export of a preset to be a function, that gets storybookOptions
|
// allow the export of a preset to be a function, that gets storybookOptions
|
||||||
@ -151,11 +160,9 @@ function loadPreset(input, level, storybookOptions) {
|
|||||||
const subPresets = resolvePresetFunction(presetsInput, presetOptions, storybookOptions);
|
const subPresets = resolvePresetFunction(presetsInput, presetOptions, storybookOptions);
|
||||||
const subAddons = resolvePresetFunction(addonsInput, presetOptions, storybookOptions);
|
const subAddons = resolvePresetFunction(addonsInput, presetOptions, storybookOptions);
|
||||||
|
|
||||||
const { managerEntries, presets } = splitAddons(subAddons);
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
...loadPresets([...subPresets, ...presets], level + 1, storybookOptions),
|
...loadPresets([...subPresets], level + 1, storybookOptions),
|
||||||
{ name: `${name}_additionalManagerEntries`, preset: { managerEntries } },
|
...loadPresets([...subAddons.map(map)].filter(Boolean), level + 1, storybookOptions),
|
||||||
{
|
{
|
||||||
name,
|
name,
|
||||||
preset: rest,
|
preset: rest,
|
||||||
|
@ -21,8 +21,14 @@ jest.mock('./utils/resolve-file', () => ({
|
|||||||
resolveFile: (name) => {
|
resolveFile: (name) => {
|
||||||
const KNOWN_FILES = [
|
const KNOWN_FILES = [
|
||||||
'@storybook/addon-actions/register',
|
'@storybook/addon-actions/register',
|
||||||
'@storybook/addon-knobs/register',
|
'@storybook/addon-docs',
|
||||||
'@storybook/addon-docs/preset',
|
'@storybook/addon-docs/preset',
|
||||||
|
'@storybook/addon-knobs',
|
||||||
|
'@storybook/addon-notes/register-panel',
|
||||||
|
'@storybook/preset-typescript',
|
||||||
|
'addon-bar/preset.js',
|
||||||
|
'addon-baz/register.js',
|
||||||
|
'addon-foo/register.js',
|
||||||
];
|
];
|
||||||
if (KNOWN_FILES.includes(name)) {
|
if (KNOWN_FILES.includes(name)) {
|
||||||
return name;
|
return name;
|
||||||
@ -343,8 +349,8 @@ describe('resolveAddonName', () => {
|
|||||||
|
|
||||||
it('should resolve packages with metadata (absolute path)', () => {
|
it('should resolve packages with metadata (absolute path)', () => {
|
||||||
expect(resolveAddonName('@storybook/addon-knobs')).toEqual({
|
expect(resolveAddonName('@storybook/addon-knobs')).toEqual({
|
||||||
name: '@storybook/addon-knobs/register',
|
name: '@storybook/addon-knobs',
|
||||||
type: 'managerEntries',
|
type: 'presets',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -363,7 +369,7 @@ describe('resolveAddonName', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should resolve presets', () => {
|
it('should resolve presets', () => {
|
||||||
expect(resolveAddonName('@storybook/addon-docs/preset')).toEqual({
|
expect(resolveAddonName('@storybook/addon-docs')).toEqual({
|
||||||
name: '@storybook/addon-docs/preset',
|
name: '@storybook/addon-docs/preset',
|
||||||
type: 'presets',
|
type: 'presets',
|
||||||
});
|
});
|
||||||
@ -381,53 +387,88 @@ describe('resolveAddonName', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('splitAddons', () => {
|
describe('loadPreset', () => {
|
||||||
const { splitAddons } = jest.requireActual('./presets');
|
const { loadPreset } = jest.requireActual('./presets');
|
||||||
|
|
||||||
it('should split managerEntries that end in register', () => {
|
mockPreset('@storybook/preset-typescript', {});
|
||||||
const addons = [
|
mockPreset('@storybook/addon-docs', {});
|
||||||
|
mockPreset('@storybook/addon-actions/register', {});
|
||||||
|
mockPreset('addon-foo/register.js', {});
|
||||||
|
mockPreset('addon-bar/preset.js', {});
|
||||||
|
mockPreset('addon-baz/register.js', {});
|
||||||
|
mockPreset('@storybook/addon-notes/register-panel', {});
|
||||||
|
|
||||||
|
it('should resolve all addons & presets in correct order', () => {
|
||||||
|
const loaded = loadPreset({
|
||||||
|
type: 'managerEntries',
|
||||||
|
name: '',
|
||||||
|
presets: ['@storybook/preset-typescript'],
|
||||||
|
addons: [
|
||||||
|
'@storybook/addon-docs',
|
||||||
'@storybook/addon-actions/register',
|
'@storybook/addon-actions/register',
|
||||||
'storybook-addon-readme/register',
|
|
||||||
'addon-foo/register.js',
|
'addon-foo/register.js',
|
||||||
'addon-bar/register.ts',
|
'addon-bar',
|
||||||
'addon-baz/register.tsx',
|
'addon-baz/register.tsx',
|
||||||
'@storybook/addon-notes/register-panel',
|
'@storybook/addon-notes/register-panel',
|
||||||
];
|
],
|
||||||
expect(splitAddons(addons)).toEqual({
|
|
||||||
managerEntries: addons,
|
|
||||||
presets: [],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should split preset packages and package entries', () => {
|
|
||||||
const addons = [
|
|
||||||
'@storybook/addon-essentials',
|
|
||||||
'@storybook/addon-docs/presets',
|
|
||||||
'addon-bar/presets.js',
|
|
||||||
'./local-addon-relative/presets',
|
|
||||||
];
|
|
||||||
expect(splitAddons(addons)).toEqual({
|
|
||||||
managerEntries: [],
|
|
||||||
presets: addons,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should split preset objects', () => {
|
|
||||||
const addons = [
|
|
||||||
{ name: '@storybook/addon-essentials' },
|
|
||||||
{ name: '@storybook/addon-docs/presets', options: { configureJSX: true } },
|
|
||||||
];
|
|
||||||
expect(splitAddons(addons)).toEqual({
|
|
||||||
managerEntries: [],
|
|
||||||
presets: addons,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should skip invalid objects', () => {
|
|
||||||
const addons = [1, true, { foo: 'bar' }];
|
|
||||||
expect(splitAddons(addons)).toEqual({
|
|
||||||
managerEntries: [],
|
|
||||||
presets: [],
|
|
||||||
});
|
});
|
||||||
|
expect(loaded).toEqual([
|
||||||
|
{
|
||||||
|
name: '@storybook/preset-typescript',
|
||||||
|
options: {},
|
||||||
|
preset: {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '@storybook/addon-actions/register_additionalManagerEntries',
|
||||||
|
options: {},
|
||||||
|
preset: {
|
||||||
|
managerEntries: ['@storybook/addon-actions/register'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'addon-foo/register.js_additionalManagerEntries',
|
||||||
|
options: {},
|
||||||
|
preset: {
|
||||||
|
managerEntries: ['addon-foo/register.js'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// should be there, but some file mocking problem is causing it to not resolve
|
||||||
|
// {
|
||||||
|
// name: 'addon-bar',
|
||||||
|
// options: {},
|
||||||
|
// preset: {},
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
name: 'addon-baz/register.tsx_additionalManagerEntries',
|
||||||
|
options: {},
|
||||||
|
preset: {
|
||||||
|
managerEntries: ['addon-baz/register.tsx'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '@storybook/addon-notes/register-panel_additionalManagerEntries',
|
||||||
|
options: {},
|
||||||
|
preset: {
|
||||||
|
managerEntries: ['@storybook/addon-notes/register-panel'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: {
|
||||||
|
presets: ['@storybook/preset-typescript'],
|
||||||
|
addons: [
|
||||||
|
'@storybook/addon-docs',
|
||||||
|
'@storybook/addon-actions/register',
|
||||||
|
'addon-foo/register.js',
|
||||||
|
'addon-bar',
|
||||||
|
'addon-baz/register.tsx',
|
||||||
|
'@storybook/addon-notes/register-panel',
|
||||||
|
],
|
||||||
|
name: '',
|
||||||
|
type: 'managerEntries',
|
||||||
|
},
|
||||||
|
options: {},
|
||||||
|
preset: {},
|
||||||
|
},
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user