Skip to content

Commit

Permalink
Merge pull request #11178 from storybookjs/fix/9819-addon-order
Browse files Browse the repository at this point in the history
Core: Fix addon load order
  • Loading branch information
shilman authored Jun 16, 2020
2 parents 66e6413 + 7c7d37e commit 7f137ec
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 81 deletions.
2 changes: 1 addition & 1 deletion lib/api/src/version.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export const version = '6.0.0-beta.28';
export const version = '6.0.0-beta.29';
67 changes: 37 additions & 30 deletions lib/core/src/server/presets.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const resolvePresetFunction = (input, presetOptions, storybookOptions) => {
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:
* - '@storybook/addon-actions/register'
Expand Down Expand Up @@ -94,46 +94,55 @@ export const resolveAddonName = (name) => {
return { name, type: 'presets' };
};

export const splitAddons = (addons) => {
return addons.reduce(
(acc, item) => {
try {
if (isObject(item)) {
const { name } = resolveAddonName(item.name);
acc.presets.push({ ...item, name });
} else {
const { name, type } = resolveAddonName(item);
acc[type].push(name);
}
} catch (err) {
logger.error(
`Addon value should end in /register OR it should be a valid preset https://storybook.js.org/docs/presets/introduction/\n${item}`
);
}
return acc;
},
{
managerEntries: [],
presets: [],
export const map = (item) => {
try {
if (isObject(item)) {
const { name } = resolveAddonName(item.name);
return { ...item, name };
}
const { name, type } = resolveAddonName(item);
if (type === 'managerEntries') {
return {
name: `${name}_additionalManagerEntries`,
type,
managerEntries: [name],
};
}
);
return resolveAddonName(name);
} catch (err) {
logger.error(
`Addon value should end in /register OR it should be a valid preset https://storybook.js.org/docs/presets/introduction/\n${item}`
);
}
return undefined;
};

function interopRequireDefault(filePath) {
// eslint-disable-next-line global-require,import/no-dynamic-require
const result = require(`${filePath}`);
const result = require(filePath);

const isES6DefaultExported =
typeof result === 'object' && result !== null && typeof result.default !== 'undefined';

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 {
const name = input.name ? input.name : input;
const presetOptions = input.options ? input.options : {};
let contents = interopRequireDefault(name);

let contents = getContent(input);

if (typeof contents === 'function') {
// allow the export of a preset to be a function, that gets storybookOptions
Expand All @@ -151,11 +160,9 @@ function loadPreset(input, level, storybookOptions) {
const subPresets = resolvePresetFunction(presetsInput, presetOptions, storybookOptions);
const subAddons = resolvePresetFunction(addonsInput, presetOptions, storybookOptions);

const { managerEntries, presets } = splitAddons(subAddons);

return [
...loadPresets([...subPresets, ...presets], level + 1, storybookOptions),
{ name: `${name}_additionalManagerEntries`, preset: { managerEntries } },
...loadPresets([...subPresets], level + 1, storybookOptions),
...loadPresets([...subAddons.map(map)].filter(Boolean), level + 1, storybookOptions),
{
name,
preset: rest,
Expand Down
141 changes: 91 additions & 50 deletions lib/core/src/server/presets.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,14 @@ jest.mock('./utils/resolve-file', () => ({
resolveFile: (name) => {
const KNOWN_FILES = [
'@storybook/addon-actions/register',
'@storybook/addon-knobs/register',
'@storybook/addon-docs',
'@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)) {
return name;
Expand Down Expand Up @@ -343,8 +349,8 @@ describe('resolveAddonName', () => {

it('should resolve packages with metadata (absolute path)', () => {
expect(resolveAddonName('@storybook/addon-knobs')).toEqual({
name: '@storybook/addon-knobs/register',
type: 'managerEntries',
name: '@storybook/addon-knobs',
type: 'presets',
});
});

Expand All @@ -363,7 +369,7 @@ describe('resolveAddonName', () => {
});

it('should resolve presets', () => {
expect(resolveAddonName('@storybook/addon-docs/preset')).toEqual({
expect(resolveAddonName('@storybook/addon-docs')).toEqual({
name: '@storybook/addon-docs/preset',
type: 'presets',
});
Expand All @@ -381,53 +387,88 @@ describe('resolveAddonName', () => {
});
});

describe('splitAddons', () => {
const { splitAddons } = jest.requireActual('./presets');
describe('loadPreset', () => {
const { loadPreset } = jest.requireActual('./presets');

it('should split managerEntries that end in register', () => {
const addons = [
'@storybook/addon-actions/register',
'storybook-addon-readme/register',
'addon-foo/register.js',
'addon-bar/register.ts',
'addon-baz/register.tsx',
'@storybook/addon-notes/register-panel',
];
expect(splitAddons(addons)).toEqual({
managerEntries: addons,
presets: [],
});
});
mockPreset('@storybook/preset-typescript', {});
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 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: [],
});
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',
'addon-foo/register.js',
'addon-bar',
'addon-baz/register.tsx',
'@storybook/addon-notes/register-panel',
],
});
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: {},
},
]);
});
});

0 comments on commit 7f137ec

Please sign in to comment.