Skip to content

Commit 24702bd

Browse files
committed
Add size-limit config
1 parent 2c83045 commit 24702bd

File tree

3 files changed

+733
-13
lines changed

3 files changed

+733
-13
lines changed

.size-limit.mts

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
import type { Check, SizeLimitConfig } from 'size-limit'
2+
import type { Configuration } from 'webpack'
3+
4+
/**
5+
* An array of all possible Node environments.
6+
*/
7+
const allNodeEnvs = ['development', 'production'] as const
8+
9+
/**
10+
* Represents a specific environment for a Node.js application.
11+
*/
12+
type NodeEnv = (typeof allNodeEnvs)[number]
13+
14+
/**
15+
* Set of entry points from the `package.json` file.
16+
*/
17+
const packageJsonEntryPoints = new Set<string>()
18+
19+
/**
20+
* Recursively collects entry points from the `package.json` exports field.
21+
*
22+
* @param packageJsonExports - The exports field from `package.json`.
23+
* @returns A set of package entry points.
24+
*/
25+
const collectPackageJsonExports = (
26+
packageJsonExports:
27+
| string
28+
| Record<string, any>
29+
| null
30+
| typeof import('./package.json').exports,
31+
) => {
32+
if (
33+
typeof packageJsonExports === 'string' &&
34+
packageJsonExports.endsWith('js')
35+
) {
36+
packageJsonEntryPoints.add(
37+
packageJsonExports.startsWith('./')
38+
? packageJsonExports
39+
: `./${packageJsonExports}`,
40+
)
41+
} else if (packageJsonExports && typeof packageJsonExports === 'object') {
42+
Object.values(packageJsonExports).forEach(collectPackageJsonExports)
43+
}
44+
45+
return packageJsonEntryPoints
46+
}
47+
48+
/**
49+
* Gets all package entry points from the `package.json` file.
50+
*
51+
* @returns A promise that resolves to an array of unique package entry points.
52+
*/
53+
const getAllPackageEntryPoints = async () => {
54+
const packageJson = (
55+
await import('./package.json', { with: { type: 'json' } })
56+
).default
57+
58+
const packageExports = collectPackageJsonExports(packageJson.exports)
59+
60+
return [...packageExports]
61+
}
62+
63+
/**
64+
* Gets all import configurations for a given entry point.
65+
* This function dynamically imports the specified entry point and
66+
* generates a size limit configuration for each named export found
67+
* within the module. It includes configurations for named imports,
68+
* wildcard imports, and the default import.
69+
*
70+
* @param entryPoint - The entry point to import.
71+
* @param index - The index of the entry point in the list.
72+
* @returns A promise that resolves to a size limit configuration object.
73+
*/
74+
const getAllImportsForEntryPoint = async (
75+
entryPoint: string,
76+
index: number,
77+
): Promise<SizeLimitConfig> => {
78+
const allNamedImports = Object.keys(await import(entryPoint)).filter(
79+
(namedImport) => namedImport !== 'default',
80+
)
81+
82+
return allNamedImports
83+
.map<Check>((namedImport) => ({
84+
path: entryPoint,
85+
name: `${index + 1}. import { ${namedImport} } from "${entryPoint}"`,
86+
import: `{ ${namedImport} }`,
87+
}))
88+
.concat([
89+
{
90+
path: entryPoint,
91+
name: `${index + 1}. import * from "${entryPoint}"`,
92+
import: '*',
93+
},
94+
{
95+
path: entryPoint,
96+
name: `${index + 1}. import "${entryPoint}"`,
97+
},
98+
])
99+
}
100+
101+
/**
102+
* Sets the `NODE_ENV` for a given Webpack configuration.
103+
*
104+
* @param nodeEnv - The `NODE_ENV` to set (either 'development' or 'production').
105+
* @returns A function that modifies the Webpack configuration.
106+
*/
107+
const setNodeEnv = (nodeEnv: NodeEnv) => {
108+
const modifyWebpackConfig = ((config: Configuration) => {
109+
;(config.optimization ??= {}).nodeEnv = nodeEnv
110+
111+
return config
112+
}) satisfies Check['modifyWebpackConfig']
113+
114+
return modifyWebpackConfig
115+
}
116+
117+
/**
118+
* Gets all import configurations with a specified `NODE_ENV`.
119+
*
120+
* @param nodeEnv - The `NODE_ENV` to set (either 'development' or 'production').
121+
* @returns A promise that resolves to a size limit configuration object.
122+
*/
123+
const getAllImportsWithNodeEnv = async (nodeEnv: NodeEnv) => {
124+
const allPackageEntryPoints = await getAllPackageEntryPoints()
125+
126+
const allImportsFromAllEntryPoints = (
127+
await Promise.all(allPackageEntryPoints.map(getAllImportsForEntryPoint))
128+
).flat()
129+
130+
const modifyWebpackConfig = setNodeEnv(nodeEnv)
131+
132+
const allImportsWithNodeEnv = allImportsFromAllEntryPoints.map<Check>(
133+
(importsFromEntryPoint) => ({
134+
...importsFromEntryPoint,
135+
name: `${importsFromEntryPoint.name} ('${nodeEnv}' mode)`,
136+
modifyWebpackConfig,
137+
}),
138+
)
139+
140+
return allImportsWithNodeEnv
141+
}
142+
143+
/**
144+
* Gets the size limit configuration for all `NODE_ENV`s.
145+
*
146+
* @returns A promise that resolves to the size limit configuration object.
147+
*/
148+
const getSizeLimitConfig = async (): Promise<SizeLimitConfig> => {
149+
const packageJson = (
150+
await import('./package.json', { with: { type: 'json' } })
151+
).default
152+
153+
const sizeLimitConfig = (
154+
await Promise.all(allNodeEnvs.map(getAllImportsWithNodeEnv))
155+
).flat()
156+
157+
if ('dependencies' in packageJson) {
158+
const dependencies = Object.keys(packageJson.dependencies ?? {})
159+
160+
const sizeLimitConfigWithoutDependencies = sizeLimitConfig.map<Check>(
161+
(check) => ({
162+
...check,
163+
name: `${check.name} (excluding dependencies)`,
164+
ignore: dependencies,
165+
}),
166+
)
167+
168+
return sizeLimitConfig.concat(sizeLimitConfigWithoutDependencies)
169+
}
170+
171+
return sizeLimitConfig
172+
}
173+
174+
const sizeLimitConfig: Promise<SizeLimitConfig> = getSizeLimitConfig()
175+
176+
export default sizeLimitConfig

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
"test": "vitest --run --typecheck",
4848
"test:watch": "vitest --watch",
4949
"type-tests": "tsc --noEmit -p tsconfig.test.json",
50+
"size": "size-limit",
5051
"coverage": "codecov"
5152
},
5253
"peerDependencies": {
@@ -79,6 +80,8 @@
7980
"@babel/preset-typescript": "^7.24.7",
8081
"@microsoft/api-extractor": "^7.47.0",
8182
"@reduxjs/toolkit": "^2.2.5",
83+
"@size-limit/file": "^11.1.4",
84+
"@size-limit/webpack": "^11.1.4",
8285
"@testing-library/dom": "^10.1.0",
8386
"@testing-library/jest-dom": "^6.4.5",
8487
"@testing-library/react": "^16.0.0",
@@ -102,6 +105,7 @@
102105
"react-test-renderer": "18.3.1",
103106
"redux": "^5.0.1",
104107
"rimraf": "^5.0.7",
108+
"size-limit": "^11.1.4",
105109
"tsup": "7.0.0",
106110
"typescript": "^5.5.4",
107111
"typescript-eslint": "^7.12.0",

0 commit comments

Comments
 (0)