Make presets loadable in main.js addons array

This commit is contained in:
Michael Shilman 2019-12-25 21:26:53 +08:00
parent d721e098b7
commit 423665b094
9 changed files with 83 additions and 24 deletions

View File

@ -99,7 +99,7 @@ export function webpack(webpackConfig: any = {}, options: any = {}) {
return result;
}
export function addons(entry: any[] = [], options: any) {
export function managerEntries(entry: any[] = [], options: any) {
return [...entry, require.resolve('../../register')];
}

View File

@ -11,7 +11,7 @@ const PRESET_METHODS = [
'webpack',
'webpackFinal',
'managerWebpack',
'addons',
'managerEntries',
'entries',
'config',
];

View File

@ -22,7 +22,7 @@ const isInstalled = (addon: string) => {
const makeAddon = (key: string) => `@storybook/addon-${key}`;
export function addons(entry: any[] = [], options: PresetOptions = {}) {
export function managerEntries(entry: any[] = [], options: PresetOptions = {}) {
const registerAddons = ['backgrounds', 'viewport']
.filter(key => (options as any)[key] !== false)
.map(key => makeAddon(key))

View File

@ -2,7 +2,7 @@ type KnobsOptions = {
addDecorator?: boolean;
};
export function addons(entry: any[] = [], options: any) {
export function managerEntries(entry: any[] = [], options: any) {
return [...entry, require.resolve('../register')];
}

View File

@ -24,8 +24,8 @@ function webpack(webpackConfig = {}, options = {}) {
};
}
function addons(entry = []) {
function managerEntries(entry = []) {
return [...entry, require.resolve('@storybook/addon-storysource/register')];
}
module.exports = { webpack, addons };
module.exports = { webpack, managerEntries };

View File

@ -86,7 +86,7 @@ The addon config `addons` allows you to add addons to Storybook from within a pr
For example, the Storysource preset contains the following code:
```js
export function addons(entry = []) {
export function managerEntries(entry = []) {
return [...entry, require.resolve('@storybook/addon-storysource/register')];
}
```
@ -95,8 +95,8 @@ This is equivalent to [registering the addon manually](../../addons/using-addons
```js
module.exports = {
addons: ['@storybook/addon-storysource/register']
}
addons: ['@storybook/addon-storysource/register'],
};
```
### Entries
@ -128,7 +128,7 @@ module.exports = {
return config;
},
addons: [],
}
};
```
## Sharing advanced configuration
@ -162,7 +162,7 @@ module.exports = {
return config;
},
addons: [],
}
};
```
Place your `my-preset.js` file where ever you want, if you want to share if far and wide you'll want to make it it's own package.
Place your `my-preset.js` file where ever you want, if you want to share if far and wide you'll want to make it it's own package.

View File

@ -5,12 +5,10 @@ export async function managerWebpack(_, options) {
return createDevConfig(options);
}
export async function managerEntries(_, options) {
const { presets, managerEntry = '../../client/manager' } = options;
export async function managerEntries(installedAddons, options) {
const { managerEntry = '../../client/manager' } = options;
const entries = [require.resolve('../common/polyfills')];
const installedAddons = await presets.apply('addons', [], options);
if (installedAddons && installedAddons.length) {
entries.push(...installedAddons);
}
@ -20,8 +18,4 @@ export async function managerEntries(_, options) {
return entries;
}
export async function addons(_, options) {
return loadCustomAddons(options);
}
export * from '../common/common-preset';

View File

@ -4,7 +4,7 @@ import dedent from 'ts-dedent';
const isObject = val => val != null && typeof val === 'object' && Array.isArray(val) === false;
const isFunction = val => typeof val === 'function';
const sanitizeSubPresets = (input, presetOptions, storybookOptions) => {
const resolvePresetFunction = (input, presetOptions, storybookOptions) => {
if (isFunction(input)) {
return input({ ...storybookOptions, ...presetOptions });
}
@ -15,6 +15,29 @@ const sanitizeSubPresets = (input, presetOptions, storybookOptions) => {
return [];
};
export const splitAddons = addons => {
return addons.reduce(
(acc, item) => {
if (typeof item === 'string' && item.match(/register$/)) {
acc.managerEntries.push(item);
} else if (typeof item === 'string' || (isObject(item) && item.name)) {
acc.presets.push(item);
} else {
logger.error(
'Addon value should end in /register OR it should be a valid preset https://storybook.js.org/docs/presets/introduction/',
item
);
}
return acc;
},
{
managerEntries: [],
presets: [],
}
);
};
function interopRequireDefault(filePath) {
// eslint-disable-next-line global-require,import/no-dynamic-require
const result = require(`${filePath}`);
@ -37,11 +60,16 @@ function loadPreset(input, level, storybookOptions) {
}
if (isObject(contents)) {
const { presets: subPresetsInput, ...rest } = contents;
const subPresets = sanitizeSubPresets(subPresetsInput, presetOptions, storybookOptions);
const { addons: addonsInput, presets: presetsInput, ...rest } = contents;
const subPresets = resolvePresetFunction(presetsInput, presetOptions, storybookOptions);
const subAddons = resolvePresetFunction(addonsInput, presetOptions, storybookOptions);
const { managerEntries, presets } = splitAddons(subAddons);
return [
...loadPresets(subPresets, level + 1, storybookOptions),
...loadPresets([...subPresets, ...presets], level + 1, storybookOptions),
{ name: `${name}_additionalManagerEntries`, preset: { managerEntries } },
{
name,
preset: rest,

View File

@ -316,3 +316,40 @@ describe('presets', () => {
jest.resetModules();
});
});
describe('splitAddons', () => {
const { splitAddons } = require.requireActual('./presets');
it('should split managerEntries that end in register', () => {
const addons = ['@storybook/addon-actions/register', '@storybook-addon-readme/register'];
expect(splitAddons(addons)).toEqual({
managerEntries: addons,
presets: [],
});
});
it('should split preset packages and package entries', () => {
const addons = ['@storybook/addon-essentials', '@storybook/addon-docs/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: [],
});
});
});