From 1c55d956074949cd23c57354df71873caead0d38 Mon Sep 17 00:00:00 2001 From: Alexander Komarov Date: Fri, 6 Oct 2023 21:59:36 +0300 Subject: [PATCH] =?UTF-8?q?feat(arui-scripts):=20=D0=B4=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20findPlugin=20=D1=85?= =?UTF-8?q?=D0=B5=D0=BB=D0=BF=D0=B5=D1=80=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/arui-scripts/.eslintrc.js | 2 + .../util/__tests__/find-plugin.tests.ts | 120 ++++++++++++++++++ .../src/configs/util/apply-overrides.ts | 9 ++ .../src/configs/util/find-plugin.ts | 118 +++++++++++++++++ .../src/configs/webpack.client.dev.ts | 2 + .../src/configs/webpack.client.prod.ts | 2 + .../src/configs/webpack.server.dev.ts | 3 +- .../src/configs/webpack.server.prod.ts | 3 +- 8 files changed, 257 insertions(+), 2 deletions(-) create mode 100644 packages/arui-scripts/src/configs/util/__tests__/find-plugin.tests.ts create mode 100644 packages/arui-scripts/src/configs/util/find-plugin.ts diff --git a/packages/arui-scripts/.eslintrc.js b/packages/arui-scripts/.eslintrc.js index 37c6adde..3142e2e8 100644 --- a/packages/arui-scripts/.eslintrc.js +++ b/packages/arui-scripts/.eslintrc.js @@ -9,5 +9,7 @@ module.exports = { rules: { 'import/no-default-export': 'warn', 'import/no-named-as-default': 'warn', + // чтобы могли использовать for и генераторы + 'no-restricted-syntax': 'off', }, }; diff --git a/packages/arui-scripts/src/configs/util/__tests__/find-plugin.tests.ts b/packages/arui-scripts/src/configs/util/__tests__/find-plugin.tests.ts new file mode 100644 index 00000000..c76f48e0 --- /dev/null +++ b/packages/arui-scripts/src/configs/util/__tests__/find-plugin.tests.ts @@ -0,0 +1,120 @@ +import { createSingleClientWebpackConfig } from '../../webpack.client'; +import { createServerConfig } from '../../webpack.server'; +import { findPlugin } from '../find-plugin'; + +const getPlugins = ( + plugins: any, + name: string, + property: (...props: any[]) => Record, +) => + plugins.map((plugin: unknown) => { + if (plugin?.constructor.name === name) { + const typedPlugin = plugin as any; + + return { + ...typedPlugin, + ...property(typedPlugin), + }; + } + + return plugin; + }); + +describe('override plugins with findPlugin', () => { + describe("client's findPlugin", () => { + it('should return original client dev config with modified MiniCssExtractPlugin: options.ignoreOrder = false', () => { + const devConfig = createSingleClientWebpackConfig('dev', './index.ts'); + + const [MiniCssExtractPlugin] = findPlugin<'client'>()( + devConfig, + 'MiniCssExtractPlugin', + ); + + MiniCssExtractPlugin.options.ignoreOrder = false; + + expect(devConfig).toMatchObject({ + ...devConfig, + plugins: getPlugins(devConfig.plugins, 'MiniCssExtractPlugin', (pluginOptions) => ({ + ...pluginOptions, + options: { + ...pluginOptions.options, + ignoreOrder: false, + }, + })), + }); + }); + + it('should return original client prod config with modified WebpackManifestPlugin: options.fileName = super-app-manifest.json', () => { + const prodConfig = createSingleClientWebpackConfig('prod', './index.ts'); + + const [WebpackManifestPlugin] = findPlugin<'client'>()( + prodConfig, + 'WebpackManifestPlugin', + ); + + WebpackManifestPlugin.options = { + ...WebpackManifestPlugin.options, + fileName: 'super-app-manifest.json', + }; + + expect(prodConfig).toMatchObject({ + ...prodConfig, + plugins: getPlugins( + prodConfig.plugins, + 'WebpackManifestPlugin', + (pluginOptions) => ({ + ...pluginOptions, + options: { + ...pluginOptions.options, + fileName: 'super-app-manifest.json', + }, + }), + ), + }); + }); + }); + + describe("server's findPlugin", () => { + it('should return original server dev config with modified BannerPlugin: options.banner = "sell garage"', () => { + const devConfig = createServerConfig('dev'); + + const [BannerPlugin] = findPlugin<'server'>()(devConfig, 'BannerPlugin'); + + BannerPlugin.options.banner = 'sell garage'; + + expect(devConfig).toMatchObject({ + ...devConfig, + plugins: getPlugins(devConfig.plugins, 'BannerPlugin', (pluginOptions) => ({ + ...pluginOptions, + options: { + ...pluginOptions.options, + banner: 'sell garage', + }, + })), + }); + }); + + it('should return original server dev config with modified WatchMissingNodeModulesPlugin: nodeModulesPath = ./123', () => { + const devConfig = createServerConfig('dev'); + + const [WatchMissingNodeModulesPlugin] = findPlugin<'server'>()( + devConfig, + 'WatchMissingNodeModulesPlugin', + ); + + WatchMissingNodeModulesPlugin.nodeModulesPath = './123'; + + expect(devConfig).toMatchObject({ + ...devConfig, + plugins: getPlugins( + devConfig.plugins, + 'WatchMissingNodeModulesPlugin', + (pluginOptions) => ({ + ...pluginOptions, + nodeModulesPath: './123', + }), + ), + }); + }); + }); +}); diff --git a/packages/arui-scripts/src/configs/util/apply-overrides.ts b/packages/arui-scripts/src/configs/util/apply-overrides.ts index d487abe1..511d949e 100644 --- a/packages/arui-scripts/src/configs/util/apply-overrides.ts +++ b/packages/arui-scripts/src/configs/util/apply-overrides.ts @@ -7,6 +7,7 @@ import { AppContextWithConfigs } from '../app-configs/types'; import { createSingleClientWebpackConfig } from '../webpack.client'; import { findLoader } from './find-loader'; +import { findPlugin } from './find-plugin'; type Overrides = { webpack: WebpackConfiguration | WebpackConfiguration[]; @@ -43,6 +44,12 @@ type BoundCreateSingleClientWebpackConfig = OmitFirstArg> +}; + +type ServerWebpackAdditionalArgs = { + findLoader: typeof findLoader; + findPlugin: ReturnType>; }; /** @@ -53,6 +60,8 @@ type OverridesAdditionalArgs = { webpackClient: ClientWebpackAdditionalArgs; webpackDev: ClientWebpackAdditionalArgs; webpackClientDev: ClientWebpackAdditionalArgs; + webpackServer: ServerWebpackAdditionalArgs; + webpackServerDev: ServerWebpackAdditionalArgs; }; type OverrideFunction< diff --git a/packages/arui-scripts/src/configs/util/find-plugin.ts b/packages/arui-scripts/src/configs/util/find-plugin.ts new file mode 100644 index 00000000..d86e2bf8 --- /dev/null +++ b/packages/arui-scripts/src/configs/util/find-plugin.ts @@ -0,0 +1,118 @@ +import { Cluster } from 'cluster'; + +import { ReactRefreshPluginOptions } from '@pmmmwh/react-refresh-webpack-plugin/types/lib/types'; +import AssetsPlugin from 'assets-webpack-plugin'; +import CaseSensitivePathsPlugin from 'case-sensitive-paths-webpack-plugin'; +import CompressionPlugin from 'compression-webpack-plugin'; +import { ForkTsCheckerWebpackPluginOptions } from 'fork-ts-checker-webpack-plugin/lib/ForkTsCheckerWebpackPluginOptions'; +import MiniCssExtractPlugin from 'mini-css-extract-plugin'; +import { RunScriptWebpackPlugin } from 'run-script-webpack-plugin'; +import webpack from 'webpack'; +import { WebpackDeduplicationPlugin } from 'webpack-deduplication-plugin'; +import { WebpackManifestPlugin } from 'webpack-manifest-plugin'; + +/* + вариации плагинов клиента + Сюда не попали: + 1. ModuleFederationPlugin +*/ +type PluginsListClient = { + AssetsWebpackPlugin: { + options: AssetsPlugin.Options; + }; + DefinePlugin: { + definitions: Record; + }; + MiniCssExtractPlugin: { + options: MiniCssExtractPlugin.PluginOptions; + runtimeOptions: MiniCssExtractPlugin.RuntimeOptions; + }; + ForkTsCheckerWebpackPlugin: { + options: ForkTsCheckerWebpackPluginOptions; + }; + IgnorePlugin: { + options: + | { + contextRegExp?: RegExp; + resourceRegExp: RegExp; + } + | { + checkResource: (resource: string, context: string) => boolean; + }; + checkIgnore: (resolveData: webpack.ResolveData) => undefined | false; + }; + WebpackDeduplicationPlugin: WebpackDeduplicationPlugin; + ReactRefreshPlugin: { + options: ReactRefreshPluginOptions; + }; + CaseSensitivePathsPlugin: { + options: CaseSensitivePathsPlugin.Options; + logger: { + [K in keyof Console]: Console[K]; + }; + }; + WebpackManifestPlugin: { + options: ConstructorParameters[number]; + }; + CompressionPlugin: { + options: ConstructorParameters[number]; + }; + NormalModuleReplacementPlugin: webpack.NormalModuleReplacementPlugin; +}; + +/* + вариации плагинов сервера + сюда не попали: + 1. HotModuleReplacementPlugin + 2. NoEmitOnErrorsPlugin + */ +type PluginsListServer = { + BannerPlugin: { + options: webpack.BannerPlugin['options']; + }; + RunScriptWebpackPlugin: { + options: ConstructorParameters[number]; + }; + ReloadServerPlugin: { + done: (...props: unknown[]) => unknown | null; + workers: Array; + }; + CaseSensitivePathsPlugin: { + options: CaseSensitivePathsPlugin.Options; + logger: { + [K in keyof Console]: Console[K]; + }; + }; + WatchMissingNodeModulesPlugin: { + nodeModulesPath: string; + }; +}; + +type SelectedPluginsList = Type extends 'client' + ? PluginsListClient + : PluginsListServer; + +/** + * + * @param config конфигурация webpack + * @param pluginName имя плагина + * @returns плагин или плагины, которые подошли под условие из testRule + */ +export function findPlugin() { + return >( + config: webpack.Configuration, + pluginName: PluginName, + ) => { + if (!config.plugins || !pluginName) return []; + + const result: Array[PluginName]> = []; + + for (const plugin of config.plugins) { + if (plugin?.constructor.name === pluginName) { + result.push(plugin as any); + } + } + + return result; + }; +} diff --git a/packages/arui-scripts/src/configs/webpack.client.dev.ts b/packages/arui-scripts/src/configs/webpack.client.dev.ts index e53593ab..4e70f1bf 100644 --- a/packages/arui-scripts/src/configs/webpack.client.dev.ts +++ b/packages/arui-scripts/src/configs/webpack.client.dev.ts @@ -1,5 +1,6 @@ import applyOverrides from './util/apply-overrides'; import { findLoader } from './util/find-loader'; +import { findPlugin } from './util/find-plugin'; import { createClientWebpackConfig, createSingleClientWebpackConfig } from './webpack.client'; const config = applyOverrides( @@ -8,6 +9,7 @@ const config = applyOverrides( { createSingleClientWebpackConfig: createSingleClientWebpackConfig.bind(null, 'dev'), findLoader, + findPlugin: findPlugin<'client'>(), }, ); diff --git a/packages/arui-scripts/src/configs/webpack.client.prod.ts b/packages/arui-scripts/src/configs/webpack.client.prod.ts index 68ccef7b..bccb42c6 100644 --- a/packages/arui-scripts/src/configs/webpack.client.prod.ts +++ b/packages/arui-scripts/src/configs/webpack.client.prod.ts @@ -1,5 +1,6 @@ import applyOverrides from './util/apply-overrides'; import { findLoader } from './util/find-loader'; +import { findPlugin } from './util/find-plugin'; import { createClientWebpackConfig, createSingleClientWebpackConfig } from './webpack.client'; const config = applyOverrides( @@ -8,6 +9,7 @@ const config = applyOverrides( { createSingleClientWebpackConfig: createSingleClientWebpackConfig.bind(null, 'prod'), findLoader, + findPlugin: findPlugin<'client'>(), }, ); diff --git a/packages/arui-scripts/src/configs/webpack.server.dev.ts b/packages/arui-scripts/src/configs/webpack.server.dev.ts index ad7e6ee3..a787f38b 100644 --- a/packages/arui-scripts/src/configs/webpack.server.dev.ts +++ b/packages/arui-scripts/src/configs/webpack.server.dev.ts @@ -1,11 +1,12 @@ import applyOverrides from './util/apply-overrides'; import { findLoader } from './util/find-loader'; +import { findPlugin } from './util/find-plugin'; import { createServerConfig } from './webpack.server'; const config = applyOverrides( ['webpack', 'webpackServer', 'webpackDev', 'webpackServerDev'], createServerConfig('dev'), - { findLoader }, + { findLoader, findPlugin: findPlugin<'server'>() }, ); export default config; diff --git a/packages/arui-scripts/src/configs/webpack.server.prod.ts b/packages/arui-scripts/src/configs/webpack.server.prod.ts index 240d9ff4..c488f534 100644 --- a/packages/arui-scripts/src/configs/webpack.server.prod.ts +++ b/packages/arui-scripts/src/configs/webpack.server.prod.ts @@ -1,11 +1,12 @@ import applyOverrides from './util/apply-overrides'; import { findLoader } from './util/find-loader'; +import { findPlugin } from './util/find-plugin'; import { createServerConfig } from './webpack.server'; const config = applyOverrides( ['webpack', 'webpackServer', 'webpackProd', 'webpackServerProd'], createServerConfig('prod'), - { findLoader }, + { findLoader, findPlugin: findPlugin<'server'>() }, ); export default config;