Skip to content

Commit

Permalink
fix: read builder config
Browse files Browse the repository at this point in the history
  • Loading branch information
JSerFeng committed Nov 15, 2023
1 parent b63b282 commit f2281d2
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 75 deletions.
6 changes: 6 additions & 0 deletions .changeset/hungry-balloons-hear.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@modern-js/storybook-builder': patch
---

feat(storybook): add adapter for storybook addons, read builderConfig
feat(storybook): 为 storybook addons 添加一些适配逻辑,读取builderConfig
78 changes: 5 additions & 73 deletions packages/storybook/builder/src/core.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { createBuilder } from '@modern-js/builder';
import { createBuilder, mergeBuilderConfig } from '@modern-js/builder';
import { loadConfig } from '@modern-js/core';
import type { Options } from '@storybook/types';
import type { Compiler } from '@modern-js/builder-shared/webpack-dev-middleware';
import type { PluginItem } from '@babel/core';
import { applyOptionsChain, logger } from '@modern-js/utils';
import type { BuilderConfig, BuilderOptions } from './types';
import { getConfigFileName, getProvider, runWithErrorMsg } from './utils';
import { pluginStorybook } from './plugin-storybook';
Expand All @@ -29,9 +27,10 @@ export async function getCompiler(
(await presets.apply<BuilderConfig | void>('modern', loadedConfig)) ||
loadedConfig;

await addonAdapter(finalConfig, options);

const provider = await getProvider(bundler, finalConfig);
const provider = await getProvider(
bundler,
mergeBuilderConfig(finalConfig, builderOptions.builderConfig) || {},
);

if (!provider) {
throw new Error(`@modern-js/builder-${bundler}-provider not found `);
Expand All @@ -53,70 +52,3 @@ export async function getCompiler(

return builder.createCompiler() as Promise<Compiler>;
}

/**
* Some addons expose babel plugins and presets, or modify webpack
*/
async function addonAdapter(finalConfig: BuilderConfig, options: Options) {
const { presets } = options;
const babelOptions = await presets.apply('babel', {}, { ...options });

finalConfig.tools ??= {};
finalConfig.tools.babel = config => {
const getPluginName = (plugin: PluginItem) =>
Array.isArray(plugin) ? plugin[0] : plugin;
const getOptions = (plugin: PluginItem) =>
Array.isArray(plugin) ? plugin[1] : null;

const replaceOrInsert = (plugin: PluginItem, plugins: PluginItem[]) => {
const pluginName = getPluginName(plugin);

const append = [];
for (let i = 0; i < plugins.length; i++) {
if (getPluginName(plugins[i]) === pluginName) {
if (getOptions(plugin)) {
logger.info(
'Detected duplicated babel plugin, overrides with the new one',
);
plugins[i] = plugin;
}
} else {
append.push(plugin);
}
}

plugins.push(...append);
};

const currentPlugins = config.plugins || [];

// O(n * n) but the number of plugins should be small
for (const plugin of babelOptions.plugins || []) {
replaceOrInsert(plugin, currentPlugins);
}

return {
...config,
...babelOptions,
plugins: currentPlugins,
presets: config.presets,
};
};

finalConfig.tools ??= {};

// @ts-expect-error tools.webpack not present in rspack config, but it's OK, we only
// adapt webpack addon now
finalConfig.tools.webpack = applyOptionsChain(
// @ts-expect-error tools.webpack not present in rspack config, but it's OK, we only
finalConfig.tools.webpack,
async (defaultConfig: any) => {
const finalDefaultConfig = await presets.apply(
'webpackFinal',
defaultConfig,
options,
);
return finalDefaultConfig;
},
);
}
86 changes: 84 additions & 2 deletions packages/storybook/builder/src/plugin-storybook.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
/* eslint-disable max-lines */
import { isAbsolute, join, resolve } from 'path';
import { slash, watch, globby, applyOptionsChain } from '@modern-js/utils';
import {
slash,
watch,
globby,
applyOptionsChain,
logger,
} from '@modern-js/utils';
import {
BuilderPlugin,
SharedBuilderConfig,
Expand All @@ -22,7 +28,7 @@ import {
loadPreviewOrConfigFile,
} from '@storybook/core-common';
import { globals } from '@storybook/preview/globals';

import type { PluginItem } from '@babel/core';
import type {
BuilderPluginAPI as WebpackAPI,
WebpackConfig,
Expand Down Expand Up @@ -119,6 +125,8 @@ export const pluginStorybook: (
};

if ('modifyWebpackConfig' in api) {
addonAdapter(api, options);

api.modifyWebpackConfig(modifyConfig);
api.modifyWebpackChain(async chain => {
await applyDocgenWebpack(chain, options);
Expand Down Expand Up @@ -472,3 +480,77 @@ async function watchStories(
);
return watcher;
}

/**
* Some addons expose babel plugins and presets, or modify webpack
*/
function addonAdapter(api: WebpackAPI | RspackAPI, options: Options) {
const { presets } = options;

api.modifyBuilderConfig(async finalConfig => {
const babelOptions = await presets.apply('babel', {}, { ...options });
finalConfig.tools ??= {};
const userConfig = finalConfig.tools.babel;
finalConfig.tools.babel = (config, utils) => {
const getPluginName = (plugin: PluginItem) =>
Array.isArray(plugin) ? plugin[0] : plugin;
const getOptions = (plugin: PluginItem) =>
Array.isArray(plugin) ? plugin[1] : null;

const replaceOrInsert = (plugin: PluginItem, plugins: PluginItem[]) => {
const pluginName = getPluginName(plugin);

const append = [];
for (let i = 0; i < plugins.length; i++) {
if (getPluginName(plugins[i]) === pluginName) {
if (getOptions(plugin)) {
logger.info(
`Detected duplicated babel plugin or presets: ${pluginName}, overrides with the new one`,
);
plugins[i] = plugin;
}
} else {
append.push(plugin);
}
}

plugins.push(...append);
};

const currentPlugins = config.plugins || [];
const currentPresets = config.presets || [];

// O(n * n) but the number of plugins should be small
for (const plugin of babelOptions.plugins || []) {
replaceOrInsert(plugin, currentPlugins);
}
for (const preset of babelOptions.presets || []) {
replaceOrInsert(preset, currentPresets);
}

const finalConfig = {
...config,
...babelOptions,
plugins: currentPlugins,
presets: currentPresets,
};

if (typeof userConfig === 'function') {
return userConfig(finalConfig, utils);
} else if (typeof userConfig === 'object') {
return { ...finalConfig, ...userConfig };
} else {
return finalConfig;
}
};
});

(api as WebpackAPI).modifyWebpackConfig(async config => {
const finalDefaultConfig = await presets.apply(
'webpackFinal',
config,
options,
);
return finalDefaultConfig;
});
}

0 comments on commit f2281d2

Please sign in to comment.