From 6edfa92a7e1496b4c05d7458c03de37dd9747a73 Mon Sep 17 00:00:00 2001 From: Arya Emami Date: Thu, 16 May 2024 14:20:53 -0500 Subject: [PATCH] Copy `size-limit` config from `react-redux` --- packages/toolkit/.size-limit.mts | 324 ++++++++++++------------------- 1 file changed, 124 insertions(+), 200 deletions(-) diff --git a/packages/toolkit/.size-limit.mts b/packages/toolkit/.size-limit.mts index a6999b566b..04a4c8ae96 100644 --- a/packages/toolkit/.size-limit.mts +++ b/packages/toolkit/.size-limit.mts @@ -1,208 +1,132 @@ -const webpack = require('webpack') -let { join } = require('path') - -const esmSuffixes = ['modern.mjs' /*, 'browser.mjs', 'legacy-esm.js'*/] -const cjsSuffixes = [/*'development.cjs',*/ 'production.min.cjs'] - -function withRtkPath(suffix, cjs = false) { - /** - * @param {string} name - */ - function alias(name) { - return `${cjs ? 'cjs/' : ''}${name}.${suffix}` - } - /** - * @param {webpack.Configuration} config - */ - return (config) => { - config.plugins.push( - new webpack.NormalModuleReplacementPlugin( - /@reduxjs\/toolkit\/query\/react/, - join(__dirname, 'dist/query/react/rtk-query-react.modern.mjs'), - ), - new webpack.NormalModuleReplacementPlugin( - /@reduxjs\/toolkit\/query/, - join(__dirname, 'dist/query/rtk-query.modern.mjs'), - ), - new webpack.NormalModuleReplacementPlugin( - /@reduxjs\/toolkit\/react/, - join(__dirname, 'dist/react/redux-toolkit-react.modern.mjs'), - ), - new webpack.NormalModuleReplacementPlugin( - /@reduxjs\/toolkit/, - join(__dirname, 'dist/redux-toolkit.modern.mjs'), - ), - new webpack.NormalModuleReplacementPlugin( - /rtk-query-react.modern.mjs/, - (r) => { - const old = r.request - r.request = r.request.replace( - /rtk-query-react.modern.mjs$/, - alias('rtk-query-react'), - ) - //console.log(old, '=>', r.request) - }, - ), - new webpack.NormalModuleReplacementPlugin(/rtk-query.modern.mjs/, (r) => { - const old = r.request - r.request = r.request.replace( - /rtk-query.modern.mjs$/, - alias('rtk-query'), - ) - //console.log(old, '=>', r.request) - }), - new webpack.NormalModuleReplacementPlugin( - /redux-toolkit-react.modern.mjs$/, - (r) => { - const old = r.request - r.request = r.request.replace( - /redux-toolkit-react.modern.mjs$/, - alias('redux-toolkit-react'), - ) - //console.log(old, '=>', r.request) - }, - ), - new webpack.NormalModuleReplacementPlugin( - /redux-toolkit.modern.mjs$/, - (r) => { - const old = r.request - r.request = r.request.replace( - /redux-toolkit.modern.mjs$/, - alias('redux-toolkit'), - ) - //console.log(old, '=>', r.request) - }, - ), - ) +import type { Check, SizeLimitConfig } from 'size-limit' +import type { Configuration } from 'webpack' - if (suffix === 'production.min.cjs') { - ;(config.resolve ??= {}).mainFields = ['main', 'module'] - } - ;(config.optimization ??= {}).nodeEnv = 'production' - return config - } -} +/** + * An array of all possible Node environments. + */ +const allNodeEnvs = ['production'] as const -const ignoreAll = [ - '@reduxjs/toolkit', - '@reduxjs/toolkit/query', - 'immer', - 'redux', - 'reselect', - 'redux-thunk', -] - -const entryPoints = [ - { - name: `1. entry point: @reduxjs/toolkit`, - path: 'dist/redux-toolkit.modern.mjs', - }, - { - name: `1. entry point: @reduxjs/toolkit/react`, - path: 'dist/react/redux-toolkit-react.modern.mjs', - }, - { - name: `1. entry point: @reduxjs/toolkit/query`, - path: 'dist/query/rtk-query.modern.mjs', - }, - { - name: `1. entry point: @reduxjs/toolkit/query/react`, - path: 'dist/query/react/rtk-query-react.modern.mjs', - }, - { - name: `2. entry point: @reduxjs/toolkit (without dependencies)`, - path: 'dist/redux-toolkit.modern.mjs', - ignore: ignoreAll, - }, - { - name: `2. entry point: @reduxjs/toolkit/react (without dependencies)`, - path: 'dist/react/redux-toolkit-react.modern.mjs', - ignore: ignoreAll, - }, - { - name: `2. entry point: @reduxjs/toolkit/query (without dependencies)`, - path: 'dist/query/rtk-query.modern.mjs', - ignore: ignoreAll, - }, - { - name: `2. entry point: @reduxjs/toolkit/query/react (without dependencies)`, - path: 'dist/query/react/rtk-query-react.modern.mjs', - ignore: ignoreAll, - }, -] - -module.exports = entryPoints - .flatMap((e) => - esmSuffixes.map((suffix) => ({ - ...e, - name: e.name + ` (${suffix})`, - modifyWebpackConfig: withRtkPath(suffix), - })), - ) - .concat( - entryPoints.flatMap((e) => - cjsSuffixes.map((suffix) => ({ - ...e, - name: e.name + ` (cjs, ${suffix})`, - modifyWebpackConfig: withRtkPath(suffix, true), - })), - ), +/** + * Represents a specific environment for a Node.js application. + */ +type NodeEnv = (typeof allNodeEnvs)[number] + +/** + * Gets all import configurations for a given entry point. + * This function dynamically imports the specified entry point and + * generates a size limit configuration for each named export found + * within the module. It includes configurations for named imports, + * wildcard imports, and the default import. + * + * @param entryPoint - The entry point to import. + * @param index - The index of the entry point in the list. + * @returns A promise that resolves to a size limit configuration object. + */ +const getAllImportsForEntryPoint = async ( + entryPoint: string, + index: number, +): Promise => { + const allNamedImports = Object.keys(await import(entryPoint)).filter( + (namedImport) => namedImport !== 'default', ) - .concat( - [ - { - name: `3. createSlice`, - import: { '@reduxjs/toolkit': '{ createSlice }' }, - }, - { - name: `3. createAsyncThunk`, - import: { '@reduxjs/toolkit': '{ createAsyncThunk }' }, - }, - { - name: `3. buildCreateSlice and asyncThunkCreator`, - import: { - '@reduxjs/toolkit': '{ buildCreateSlice, asyncThunkCreator }', - }, - }, - { - name: `3. createEntityAdapter`, - import: { '@reduxjs/toolkit': '{ createEntityAdapter }' }, - }, - { - name: `3. configureStore`, - import: { '@reduxjs/toolkit': '{ configureStore }' }, - }, - { - name: `3. combineSlices`, - import: { '@reduxjs/toolkit': '{ combineSlices }' }, - }, - { - name: `3. createDynamicMiddleware`, - import: { '@reduxjs/toolkit': '{ createDynamicMiddleware }' }, - }, - { - name: `3. createDynamicMiddleware (react)`, - import: { '@reduxjs/toolkit/react': '{ createDynamicMiddleware }' }, - }, - { - name: `3. createListenerMiddleware`, - import: { '@reduxjs/toolkit': '{ createListenerMiddleware }' }, - }, - { - name: `3. createApi`, - import: { '@reduxjs/toolkit/query': '{ createApi }' }, - }, + + return allNamedImports + .map((namedImport) => ({ + path: entryPoint, + name: `${index + 1}. import { ${namedImport} } from "${entryPoint}"`, + import: `{ ${namedImport} }`, + })) + .concat([ { - name: `3. createApi (react)`, - import: { '@reduxjs/toolkit/query/react': '{ createApi }' }, + path: entryPoint, + name: `${index + 1}. import * from "${entryPoint}"`, + import: '*', }, { - name: `3. fetchBaseQuery`, - import: { '@reduxjs/toolkit/query': '{ fetchBaseQuery }' }, + path: entryPoint, + name: `${index + 1}. import "${entryPoint}"`, }, - ].map((e) => ({ - ...e, - name: e.name + ` (.modern.mjs)`, - modifyWebpackConfig: withRtkPath('modern.mjs'), - })), + ]) +} + +/** + * Sets the `NODE_ENV` for a given Webpack configuration. + * + * @param nodeEnv - The `NODE_ENV` to set (either 'development' or 'production'). + * @returns A function that modifies the Webpack configuration. + */ +const setNodeEnv = (nodeEnv: NodeEnv) => { + const modifyWebpackConfig = ((config: Configuration) => { + ;(config.optimization ??= {}).nodeEnv = nodeEnv + + return config + }) satisfies Check['modifyWebpackConfig'] + + return modifyWebpackConfig +} + +/** + * Gets all import configurations with a specified `NODE_ENV`. + * + * @param nodeEnv - The `NODE_ENV` to set (either 'development' or 'production'). + * @returns A promise that resolves to a size limit configuration object. + */ +const getAllImportsWithNodeEnv = async (nodeEnv: NodeEnv) => { + const allPackageEntryPoints = [ + './dist/redux-toolkit.modern.mjs', + './dist/react/redux-toolkit-react.modern.mjs', + './dist/query/rtk-query.modern.mjs', + './dist/query/react/rtk-query-react.modern.mjs', + ] + + const allImportsFromAllEntryPoints = ( + await Promise.all(allPackageEntryPoints.map(getAllImportsForEntryPoint)) + ).flat() + + const modifyWebpackConfig = setNodeEnv(nodeEnv) + + const allImportsWithNodeEnv = allImportsFromAllEntryPoints.map( + (importsFromEntryPoint) => ({ + ...importsFromEntryPoint, + name: `${importsFromEntryPoint.name} ('${nodeEnv}' mode)`, + modifyWebpackConfig, + }), ) + + return allImportsWithNodeEnv +} + +/** + * Gets the size limit configuration for all `NODE_ENV`s. + * + * @returns A promise that resolves to the size limit configuration object. + */ +const getSizeLimitConfig = async (): Promise => { + const packageJson = ( + await import('./package.json', { with: { type: 'json' } }) + ).default + + const sizeLimitConfig = ( + await Promise.all(allNodeEnvs.map(getAllImportsWithNodeEnv)) + ).flat() + + if ('dependencies' in packageJson) { + const dependencies = Object.keys(packageJson.dependencies ?? {}) + + const sizeLimitConfigWithoutDependencies = sizeLimitConfig.map( + (check) => ({ + ...check, + name: `${check.name} (excluding dependencies)`, + ignore: dependencies, + }), + ) + + return sizeLimitConfigWithoutDependencies + } + + return sizeLimitConfig +} + +const sizeLimitConfig: Promise = getSizeLimitConfig() + +export default sizeLimitConfig