get package info for builder
MODIFY
bin-src/lib/getPrebuiltStorybookMetadata.ts
bin-src/lib/getPrebuiltStorybookMetadata.ts
import { readFile } from 'jsonfile';
import { Context } from '../types';
+import { builders } from './builders';
import { supportedAddons } from './supportedAddons';
import { viewLayers } from './viewLayers';
+import packageDoesNotExist from '../ui/messages/errors/noViewLayerPackage';
+import { resolvePackageJson } from './getStorybookMetadata';
+import { timeout } from './promises';
/*
In Storybook 6.5+, when building a Storybook, a project.json file is generated,
containing metadata (sb builder, addons, viewLayer and viewLayer version) for the
particular setup.
*/
+type BuilderConfig =
+ | string
+ | {
+ name: string;
+ };
export interface SBProjectJson {
addons: Record<string, { version: string; options: any }>;
- builder?: {
- name: string;
- };
+ builder?: BuilderConfig;
framework: {
name: string;
};
+ storybookVersion: string;
storybookPackages?: Record<string, { version: string }>;
}
+const getBuilder = (sbProjectJson: SBProjectJson): { name: string; packageVersion: string } => {
+ let name: string;
+ if (sbProjectJson.builder) {
+ const { builder } = sbProjectJson;
+ name = typeof builder === 'string' ? sbProjectJson.builder : sbProjectJson.builder.name;
+ return {
+ name,
+ packageVersion: sbProjectJson.storybookPackages[builders[name]].version,
+ };
+ }
+
+ // Stroybook uses Webpack4 if no builder is explicitly set.
+ return {
+ name: 'webpack4',
+ packageVersion: sbProjectJson.storybookVersion,
+ };
+};
+
export const getStorybookMetadataFromProjectJson = async (
projectJsonPath: string
): Promise<Partial<Context['storybook']>> => {
@@ -27,17 +53,12 @@ export const getStorybookMetadataFromProjectJson = async (
const viewLayerPackage = Object.keys(viewLayers).find(
(viewLayer) => viewLayers[viewLayer] === sbProjectJson.framework.name
);
+ const builder = getBuilder(sbProjectJson);
+
return {
- viewLayer: sbProjectJson.framework.name ?? '',
+ viewLayer: sbProjectJson.framework.name ?? null,
version: sbProjectJson.storybookPackages[viewLayerPackage].version,
- builder: sbProjectJson?.builder
- ? {
- name:
- typeof sbProjectJson.builder === 'string'
- ? sbProjectJson.builder
- : sbProjectJson?.builder.name,
- }
- : { name: 'webpack4' },
+ builder,
addons: Object.keys(sbProjectJson.addons).map((addon) => ({
name: supportedAddons[addon],
packageName: addon,

MODIFY
bin-src/lib/getStorybookInfo.test.ts
bin-src/lib/getStorybookInfo.test.ts
@@ -18,7 +18,7 @@ jest.mock('./getPrebuiltStorybookMetadata', () => {
packageVersion: '6.5.5',
},
],
- builder: { name: 'webpack5' },
+ builder: { name: 'webpack5', packageVersion: '6.5.6' },
version: '6.5.5',
viewLayer: 'react',
})),
@@ -52,7 +52,7 @@ describe('getStorybookInfo', () => {
expect.objectContaining({
viewLayer: 'react',
version: expect.any(String),
- builder: { name: 'webpack5', version: '6.5.6' },
+ builder: { name: 'webpack5', packageVersion: '6.5.6' },
})
);
});
@@ -91,7 +91,7 @@ describe('getStorybookInfo', () => {
expect.objectContaining({
viewLayer: 'react',
version: expect.any(String),
- builder: { name: 'webpack5', version: '6.5.6' },
+ builder: { name: 'webpack5', packageVersion: '6.5.6' },
})
);
expect(log.info).toHaveBeenCalledWith(
@@ -108,7 +108,7 @@ describe('getStorybookInfo', () => {
expect.objectContaining({
viewLayer: 'react',
version: '3.2.1',
- builder: { name: 'webpack5', version: '6.5.6' },
+ builder: { name: 'webpack5', packageVersion: '6.5.6' },
})
);
});
@@ -119,7 +119,7 @@ describe('getStorybookInfo', () => {
expect.objectContaining({
viewLayer: 'react',
version: '3.2.1',
- builder: { name: 'webpack5', version: '6.5.6' },
+ builder: { name: 'webpack5', packageVersion: '6.5.6' },
})
);
});
@@ -172,7 +172,7 @@ describe('getStorybookInfo', () => {
packageVersion: '6.5.5',
},
],
- builder: { name: 'webpack5' },
+ builder: { name: 'webpack5', packageVersion: '6.5.6' },
version: '6.5.5',
viewLayer: 'react',
});

MODIFY
bin-src/lib/getStorybookMetadata.ts
bin-src/lib/getStorybookMetadata.ts
@@ -11,7 +11,7 @@ import { timeout, raceFulfilled } from './promises';
import { supportedAddons } from './supportedAddons';
import { builders } from './builders';
-const resolvePackageJson = (pkg: string) => {
+export const resolvePackageJson = (pkg: string) => {
try {
// we bundle this app for node, meaning all require calls are replaced by webpack.
// in this case we want to use node's actual require functionality!
@@ -108,8 +108,13 @@ const findViewlayer = async ({ env, log, options, packageJson }) => {
]);
};
-const findAddons = async (deps, mainConfig) => {
+const findAddons = async (ctx, mainConfig) => {
if (mainConfig?.addons) {
+ const allDependencies = {
+ ...ctx.packageJson?.dependencies,
+ ...ctx.packageJson?.devDependencies,
+ ...ctx.packageJson?.peerDependencies,
+ };
return {
addons: mainConfig.addons.map((addon) => {
let name: string;
@@ -122,7 +127,7 @@ const findAddons = async (deps, mainConfig) => {
return {
name: supportedAddons[name],
packageName: name,
- version: deps[name],
+ packageVersion: allDependencies[name],
};
}),
};
@@ -150,7 +155,7 @@ const findConfigFlags = async ({ options, packageJson }) => {
};
};
-const findBuilder = async (mainConfig) => {
+export const findBuilder = async (mainConfig) => {
let name: string;
if (mainConfig?.core.builder) {
const { builder } = mainConfig.core;
@@ -161,7 +166,7 @@ const findBuilder = async (mainConfig) => {
return Promise.race([
resolvePackageJson(builders[name])
- .then((json) => ({ builder: { name, version: json.version } }))
+ .then((json) => ({ builder: { name, packageVersion: json.version } }))
.catch(() => Promise.reject(new Error(packageDoesNotExist(builders[name])))),
timeout(10000),
]);
@@ -171,14 +176,9 @@ export const getStorybookMetadata = async (ctx: Context) => {
const configDir = ctx.options.storybookConfigDir ?? '.storybook';
const r = typeof __non_webpack_require__ !== 'undefined' ? __non_webpack_require__ : require;
const mainConfig = await r(path.resolve(configDir, 'main'));
- const allDependencies = {
- ...ctx.packageJson?.dependencies,
- ...ctx.packageJson?.devDependencies,
- ...ctx.packageJson?.peerDependencies,
- };
const info = await Promise.all([
- findAddons(allDependencies, mainConfig),
+ findAddons(ctx, mainConfig),
findConfigFlags(ctx),
findViewlayer(ctx),
findBuilder(mainConfig),

MODIFY
bin-src/types.ts
bin-src/types.ts
@@ -172,6 +172,8 @@ export interface Context {
}[];
builder: {
name: string;
+ packageName?: string;
+ packageVersion?: string;
};
};
spawnParams: {

MODIFY
bin-src/ui/tasks/storybookInfo.stories.ts
bin-src/ui/tasks/storybookInfo.stories.ts
@@ -9,7 +9,7 @@ export default {
const storybook = {
version: '5.3.0',
viewLayer: 'web-components',
- builder: 'webpack4',
+ builder: { name: 'webpack4', packageVersion: '5.3.0' },
addons: [],
};
const addons = [{ name: 'actions' }, { name: 'docs' }, { name: 'design-assets' }];

MODIFY
bin-src/ui/tasks/storybookInfo.ts
bin-src/ui/tasks/storybookInfo.ts
@@ -8,7 +8,9 @@ const capitalize = (string: string) =>
const infoMessage = ({ addons, version, viewLayer, builder }: Context['storybook']) => {
const info = version && viewLayer ? `Storybook ${version} for ${capitalize(viewLayer)}` : '';
- const builderInfo = builder ? `${info}; using the ${builder.name} builder` : info;
+ const builderInfo = builder
+ ? `${info}; using the ${builder.name} builder (${builder.packageVersion})`
+ : info;
return addons?.length
? `${builderInfo}; supported addons found: ${addons
.map((addon) => capitalize(addon.name))

get package info for builder