Skip to content

Commit fee3902

Browse files
committed
perf: patch zod barrel to remove unused locales (-144 KB)
- Add yarn patch for zod that removes `export * as locales` from all barrel entry points (classic, core, mini — ESM and CJS) - Only English locale is used; other 49 locale files were dead weight in the bundle
1 parent 619ec70 commit fee3902

3 files changed

Lines changed: 165 additions & 2 deletions

File tree

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
diff --git a/v4/classic/external.cjs b/v4/classic/external.cjs
2+
index ee133825d44ab44b86dd8aef6bd985653ebde06c..ea74468d20c2371f9c4d8941467e3b7fe93a00ef 100644
3+
--- a/v4/classic/external.cjs
4+
+++ b/v4/classic/external.cjs
5+
@@ -29,7 +29,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
6+
return (mod && mod.__esModule) ? mod : { "default": mod };
7+
};
8+
Object.defineProperty(exports, "__esModule", { value: true });
9+
-exports.coerce = exports.iso = exports.ZodISODuration = exports.ZodISOTime = exports.ZodISODate = exports.ZodISODateTime = exports.locales = exports.fromJSONSchema = exports.toJSONSchema = exports.NEVER = exports.util = exports.TimePrecision = exports.flattenError = exports.formatError = exports.prettifyError = exports.treeifyError = exports.regexes = exports.clone = exports.$brand = exports.$input = exports.$output = exports.config = exports.registry = exports.globalRegistry = exports.core = void 0;
10+
+exports.coerce = exports.iso = exports.ZodISODuration = exports.ZodISOTime = exports.ZodISODate = exports.ZodISODateTime = exports.fromJSONSchema = exports.toJSONSchema = exports.NEVER = exports.util = exports.TimePrecision = exports.flattenError = exports.formatError = exports.prettifyError = exports.treeifyError = exports.regexes = exports.clone = exports.$brand = exports.$input = exports.$output = exports.config = exports.registry = exports.globalRegistry = exports.core = void 0;
11+
exports.core = __importStar(require("../core/index.cjs"));
12+
__exportStar(require("./schemas.cjs"), exports);
13+
__exportStar(require("./checks.cjs"), exports);
14+
@@ -60,7 +60,7 @@ var json_schema_processors_js_1 = require("../core/json-schema-processors.cjs");
15+
Object.defineProperty(exports, "toJSONSchema", { enumerable: true, get: function () { return json_schema_processors_js_1.toJSONSchema; } });
16+
var from_json_schema_js_1 = require("./from-json-schema.cjs");
17+
Object.defineProperty(exports, "fromJSONSchema", { enumerable: true, get: function () { return from_json_schema_js_1.fromJSONSchema; } });
18+
-exports.locales = __importStar(require("../locales/index.cjs"));
19+
+// locales removed from barrel
20+
// iso
21+
// must be exported from top-level
22+
// https://github.com/colinhacks/zod/issues/4491
23+
diff --git a/v4/classic/external.js b/v4/classic/external.js
24+
index 9567900bbb57099481c0ea5864fbf697d62021a5..98ee2af29038deca6c38c46c24d5fb14725e40f0 100644
25+
--- a/v4/classic/external.js
26+
+++ b/v4/classic/external.js
27+
@@ -11,7 +11,7 @@ config(en());
28+
export { globalRegistry, registry, config, $output, $input, $brand, clone, regexes, treeifyError, prettifyError, formatError, flattenError, TimePrecision, util, NEVER, } from "../core/index.js";
29+
export { toJSONSchema } from "../core/json-schema-processors.js";
30+
export { fromJSONSchema } from "./from-json-schema.js";
31+
-export * as locales from "../locales/index.js";
32+
+// locales removed from barrel
33+
// iso
34+
// must be exported from top-level
35+
// https://github.com/colinhacks/zod/issues/4491
36+
diff --git a/v4/core/index.cjs b/v4/core/index.cjs
37+
index c3fa303104a191d142a5212f69e7954cba3606a7..44bdc3437c6a88971c1c85b63024213880fe0fff 100644
38+
--- a/v4/core/index.cjs
39+
+++ b/v4/core/index.cjs
40+
@@ -26,7 +26,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
41+
return result;
42+
};
43+
Object.defineProperty(exports, "__esModule", { value: true });
44+
-exports.JSONSchema = exports.JSONSchemaGenerator = exports.toJSONSchema = exports.locales = exports.regexes = exports.util = void 0;
45+
+exports.JSONSchema = exports.JSONSchemaGenerator = exports.toJSONSchema = exports.regexes = exports.util = void 0;
46+
__exportStar(require("./core.cjs"), exports);
47+
__exportStar(require("./parse.cjs"), exports);
48+
__exportStar(require("./errors.cjs"), exports);
49+
@@ -35,7 +35,7 @@ __exportStar(require("./checks.cjs"), exports);
50+
__exportStar(require("./versions.cjs"), exports);
51+
exports.util = __importStar(require("./util.cjs"));
52+
exports.regexes = __importStar(require("./regexes.cjs"));
53+
-exports.locales = __importStar(require("../locales/index.cjs"));
54+
+// locales removed from barrel
55+
__exportStar(require("./registries.cjs"), exports);
56+
__exportStar(require("./doc.cjs"), exports);
57+
__exportStar(require("./api.cjs"), exports);
58+
diff --git a/v4/core/index.js b/v4/core/index.js
59+
index d334515bf004600f2e55ff85e3730f1b2f2ff703..4ff979844ba18d012893064b01889bf70ec245c8 100644
60+
--- a/v4/core/index.js
61+
+++ b/v4/core/index.js
62+
@@ -6,7 +6,7 @@ export * from "./checks.js";
63+
export * from "./versions.js";
64+
export * as util from "./util.js";
65+
export * as regexes from "./regexes.js";
66+
-export * as locales from "../locales/index.js";
67+
+// locales removed from barrel
68+
export * from "./registries.js";
69+
export * from "./doc.js";
70+
export * from "./api.js";
71+
diff --git a/v4/mini/external.cjs b/v4/mini/external.cjs
72+
index 0d0079d94d94010b51abe23042418adbc6077b7f..fd3acb42a12dde65f383eb2c3f46a9108dd8c865 100644
73+
--- a/v4/mini/external.cjs
74+
+++ b/v4/mini/external.cjs
75+
@@ -26,7 +26,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
76+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
77+
};
78+
Object.defineProperty(exports, "__esModule", { value: true });
79+
-exports.coerce = exports.ZodMiniISODuration = exports.ZodMiniISOTime = exports.ZodMiniISODate = exports.ZodMiniISODateTime = exports.iso = exports.locales = exports.toJSONSchema = exports.NEVER = exports.util = exports.TimePrecision = exports.flattenError = exports.formatError = exports.prettifyError = exports.treeifyError = exports.regexes = exports.clone = exports.$brand = exports.$input = exports.$output = exports.config = exports.registry = exports.globalRegistry = exports.core = void 0;
80+
+exports.coerce = exports.ZodMiniISODuration = exports.ZodMiniISOTime = exports.ZodMiniISODate = exports.ZodMiniISODateTime = exports.iso = exports.toJSONSchema = exports.NEVER = exports.util = exports.TimePrecision = exports.flattenError = exports.formatError = exports.prettifyError = exports.treeifyError = exports.regexes = exports.clone = exports.$brand = exports.$input = exports.$output = exports.config = exports.registry = exports.globalRegistry = exports.core = void 0;
81+
exports.core = __importStar(require("../core/index.cjs"));
82+
__exportStar(require("./parse.cjs"), exports);
83+
__exportStar(require("./schemas.cjs"), exports);
84+
@@ -49,7 +49,7 @@ Object.defineProperty(exports, "util", { enumerable: true, get: function () { re
85+
Object.defineProperty(exports, "NEVER", { enumerable: true, get: function () { return index_js_1.NEVER; } });
86+
var json_schema_processors_js_1 = require("../core/json-schema-processors.cjs");
87+
Object.defineProperty(exports, "toJSONSchema", { enumerable: true, get: function () { return json_schema_processors_js_1.toJSONSchema; } });
88+
-exports.locales = __importStar(require("../locales/index.cjs"));
89+
+// locales removed from barrel
90+
/** A special constant with type `never` */
91+
// export const NEVER = {} as never;
92+
// iso
93+
diff --git a/v4/mini/external.js b/v4/mini/external.js
94+
index d6523c153e213be110c21b370164b5eca1cdf744..7a1addf9ce6e331e56c943867bf04cf199745145 100644
95+
--- a/v4/mini/external.js
96+
+++ b/v4/mini/external.js
97+
@@ -4,7 +4,7 @@ export * from "./schemas.js";
98+
export * from "./checks.js";
99+
export { globalRegistry, registry, config, $output, $input, $brand, clone, regexes, treeifyError, prettifyError, formatError, flattenError, TimePrecision, util, NEVER, } from "../core/index.js";
100+
export { toJSONSchema } from "../core/json-schema-processors.js";
101+
-export * as locales from "../locales/index.js";
102+
+// locales removed from barrel
103+
/** A special constant with type `never` */
104+
// export const NEVER = {} as never;
105+
// iso

docs/bundle-optimization-react-aria.md

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Bundle Optimization: barrel import patches (react-aria, react-stately)
1+
# Bundle Optimization: barrel import patches (react-aria, react-stately, zod)
22

33
## The Problem
44

@@ -53,6 +53,60 @@ This is the correct long-term fix, but alone it was not enough because `@rocket.
5353
| Main JS (minified) | 3688 KB | 3199 KB | **-489 KB (-13%)** |
5454
| Main JS (gzip) | 939 KB | 841 KB | **-98 KB (-10%)** |
5555

56+
---
57+
58+
## Zod v4 locale barrel
59+
60+
### The Problem
61+
62+
Zod v4 re-exports all 50 locale files from its main entry point:
63+
64+
```js
65+
// zod/v4/classic/external.js
66+
export * as locales from "../locales/index.js";
67+
```
68+
69+
This means `import { z } from 'zod'` pulls in error messages for Arabic, Hebrew, Thai, Russian, and 46 other languages — even though Rocket.Chat only uses the English locale (loaded by default via `config(en())`).
70+
71+
**Measured impact:** 147 KB (50 locale files) out of 278 KB total for zod — **53% of the zod bundle was unused locale data**.
72+
73+
### The Solution
74+
75+
A `yarn patch` on `zod@4.3.6` removes the `export * as locales` line from the barrel. The English locale (`en.js`) remains loaded since it's imported separately by `config(en())`. All other locales remain available for explicit import if needed:
76+
77+
```typescript
78+
// Still works:
79+
import pt from 'zod/v4/locales/pt';
80+
import { config } from 'zod';
81+
config(pt());
82+
```
83+
84+
### What requires attention
85+
86+
#### Upgrading zod
87+
88+
When upgrading zod, the patch must be re-created:
89+
90+
1. Remove the old patch reference from `package.json` resolutions
91+
2. Delete `.yarn/patches/zod-*.patch`
92+
3. Run `yarn install`
93+
4. Run `yarn patch zod@npm:<new-version>`
94+
5. Remove the `export * as locales` line from `v4/classic/external.js`
95+
6. Remove the `exports.locales` require from `v4/classic/external.cjs`
96+
7. Run `yarn patch-commit -s <patch-folder>`
97+
98+
#### If zod locales are needed at runtime
99+
100+
If a feature requires localized zod error messages (e.g., form validation in the user's language), import the specific locale directly instead of relying on the barrel:
101+
102+
```typescript
103+
import de from 'zod/v4/locales/de';
104+
import { config } from 'zod';
105+
config(de());
106+
```
107+
108+
This loads only the one locale needed (~3 KB) instead of all 50 (~147 KB).
109+
56110
## What requires attention
57111

58112
### Adding new react-aria hooks or components
@@ -97,6 +151,8 @@ If there are new exports, add them to the yarn patch.
97151

98152
The react-aria/react-stately yarn patches are a workaround. The proper fix is for `@rocket.chat/fuselage` to import from sub-packages directly instead of the barrel, which eliminates the need for those patches entirely. Once that is done, only the direct sub-package imports in source code are needed.
99153

154+
The zod patch is a workaround for a design choice in zod v4 (`export * as locales` in the main barrel). This may be addressed upstream — track https://github.com/colinhacks/zod for changes to the locale export strategy.
155+
100156
## How to analyze the bundle
101157

102158
Meteor generates a `.stats.json` file alongside each build. To inspect it:

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@
4646
"yoga-layout@npm:^3.2.1": "patch:yoga-layout@npm%3A3.2.1#~/.yarn/patches/yoga-layout-npm-3.2.1-51ec934670.patch",
4747
"@react-pdf/layout@npm:^4.4.2": "patch:@react-pdf/layout@npm%3A4.4.2#~/.yarn/patches/@react-pdf-layout-npm-4.4.2-6c2e3312fa.patch",
4848
"react-aria@npm:~3.37.0": "patch:react-aria@npm%3A3.37.0#~/.yarn/patches/react-aria-npm-3.37.0-83959bd2fa.patch",
49-
"react-stately@npm:~3.35.0": "patch:react-stately@npm%3A3.17.0#~/.yarn/patches/react-stately-npm-3.17.0-264cc7a43c.patch"
49+
"react-stately@npm:~3.35.0": "patch:react-stately@npm%3A3.17.0#~/.yarn/patches/react-stately-npm-3.17.0-264cc7a43c.patch",
50+
"zod@npm:^3.25.0 || ^4.0.0": "patch:zod@npm%3A4.3.6#~/.yarn/patches/zod-npm-4.3.6-a096e305e6.patch",
51+
"zod@npm:~4.3.6": "patch:zod@npm%3A4.3.6#~/.yarn/patches/zod-npm-4.3.6-a096e305e6.patch"
5052
},
5153
"dependencies": {
5254
"@types/stream-buffers": "^3.0.8",

0 commit comments

Comments
 (0)