react-native-bundle-discovery 2.6.0 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # react-native-bundle-discovery
2
+
3
+ ## 2.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#16](https://github.com/retyui/react-native-bundle-discovery/pull/16) [`ac2af30`](https://github.com/retyui/react-native-bundle-discovery/commit/ac2af3063e3c4031ee026b58d4039e56f7152383) Thanks [@retyui](https://github.com/retyui)! - Rewrite in TypeScript and ship compiled JavaScript from `dist/` (with type definitions for `react-native-bundle-discovery` and the Rozenite plugin). Package entry points are unchanged; deep imports of internal files (e.g. `react-native-bundle-discovery/webpack.js`, `react-native-bundle-discovery-ui/.discoveryrc.js`) moved under `dist/`.
package/README.md CHANGED
@@ -1,72 +1,92 @@
1
1
  # react-native-bundle-discovery
2
2
 
3
- [![react-native-bundle-discovery on npm](https://badgen.net/npm/v/react-native-bundle-discovery)](https://www.npmjs.com/package/react-native-bundle-discovery)
4
- [![react-native-bundle-discovery downloads](https://badgen.net/npm/dm/react-native-bundle-discovery)](https://www.npmtrends.com/react-native-bundle-discovery)
5
-
6
- A simple package that helps developers visualize and analyze the bundle size of React Native apps.
7
- With this tool, you can easily explore your app's codebase, identify large or heavy packages, and inspect the structure of modules and code within your project.
8
-
9
- <img width="800" alt="" src="./assets/img.png" />
10
-
11
- ### Packages:
12
-
13
- - `react-native-bundle-discovery` - simple JS library to generate a JSON report of the bundle.
14
- - `react-native-bundle-discovery-ui` - UI to visualize the bundle report.
15
- - `react-native-bundle-discovery-cli` - CLI to analyze the bundle report.
16
- - `react-native-bundle-discovery-rozenite-plugin` - Rozenite plugin to integrate UI tool to [React Native DevTools](https://reactnative.dev/docs/react-native-devtools).
17
-
18
- ---
19
-
20
- ### Setup:
21
-
22
- There are two ways to install the package:
23
-
24
- 1. As in independent tool (UI + CLI)
25
- 2. Or as a [Rozenite](_rozenite/README.md) plugin (see: [_rozenite/README.md](_rozenite/README.md))
26
-
27
- > 🚀 If you've migrated to [Re.Pack](https://re-pack.dev/), you can still use this package to analyze 📊 JS bundles 📦 generated by Re.Pack.
3
+ [![npm version](https://badgen.net/npm/v/react-native-bundle-discovery)](https://www.npmjs.com/package/react-native-bundle-discovery)
4
+ [![npm downloads](https://badgen.net/npm/dm/react-native-bundle-discovery)](https://www.npmtrends.com/react-native-bundle-discovery)
5
+ [![license](https://badgen.net/npm/license/react-native-bundle-discovery)](https://www.npmjs.com/package/react-native-bundle-discovery)
6
+
7
+ Visualize and analyze the JS bundle of your React Native app. Find heavy packages, duplicates and deprecated
8
+ dependencies, inspect every module, and catch bundle size regressions in CI.
9
+
10
+ <img width="800" alt="Bundle Discovery UI" src="./assets/img.png" />
11
+
12
+ ## Contents
13
+
14
+ - [Features](#features)
15
+ - [Packages](#packages)
16
+ - [Quick start](#quick-start)
17
+ - [Other setups](#other-setups)
18
+ - [Usage](#usage)
19
+ - [UI](#ui)
20
+ - [CLI](#cli)
21
+ - [Bundle size checks in CI](#bundle-size-checks-in-ci)
22
+ - [API](#api)
23
+ - [`createSerializer`](#createserializeroptions)
24
+ - [`createResolveRequest`](#createresolverequestoptions)
25
+ - [Similar projects](#similar-projects)
26
+ - [Support the project](#support-the-project)
27
+ - [License](#license)
28
+
29
+ ## Features
30
+
31
+ - 📊 Interactive UI to explore packages, modules and their source/bundled code
32
+ - 💡 Optimization recommendations (duplicates, deprecated / outdated / dev-only packages, and more)
33
+ - 🔍 CLI to list the heaviest packages and modules
34
+ - 🆚 Compare two reports and fail CI on bundle size regressions
35
+ - 🧩 Works with Metro, [Re.Pack](./Re.Pack.md) and [React Native DevTools](./packages/rozenite-plugin/README.md) (via Rozenite)
36
+
37
+ ## Packages
38
+
39
+ | Package | What it does | Required |
40
+ | ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------- | -------- |
41
+ | `react-native-bundle-discovery` | Generates a JSON report (`metro-stats.json`) of your bundle | ✅ Yes |
42
+ | `react-native-bundle-discovery-ui` | Shows the report in the browser | Optional |
43
+ | `react-native-bundle-discovery-cli` | Analyzes and compares reports in the terminal / CI | Optional |
44
+ | [`react-native-bundle-discovery-rozenite-plugin`](./packages/rozenite-plugin/README.md) | Shows the UI inside [React Native DevTools](https://reactnative.dev/docs/react-native-devtools) | Optional |
45
+
46
+ ## Quick start
47
+
48
+ This setup is for a standard **Metro** project.
49
+ Using Re.Pack or Rozenite? See [Other setups](#other-setups).
50
+
51
+ > [!TIP]
52
+ > **Using an AI coding agent?** Skip the manual steps below. Point your agent (Claude Code, Cursor, Codex, etc.)
53
+ > at the [`setup-react-native-bundle-discovery`](./skills/setup-react-native-bundle-discovery/SKILL.md) skill.
54
+ > It installs the package and sets up Metro or Re.Pack for you:
28
55
  >
29
- > 💡 Learn more: 📖 [Re.Pack.md](./Re.Pack.md)
56
+ > ```bash
57
+ > npx skills add retyui/react-native-bundle-discovery
58
+ > ```
30
59
 
31
- #### 1. Install (independent tool)
60
+ ### 1. Install
32
61
 
33
62
  ```bash
34
- yarn add -D react-native-bundle-discovery # required for generating the JSON report
35
- yarn add -D react-native-bundle-discovery-ui # optional: used for visualizing the report in the browser
36
- yarn add -D react-native-bundle-discovery-cli # optional: used for analysis of the report in the CLI
63
+ yarn add -D react-native-bundle-discovery # required: generates the report
64
+ yarn add -D react-native-bundle-discovery-ui # optional: browser UI
65
+ yarn add -D react-native-bundle-discovery-cli # optional: CLI
37
66
  ```
38
67
 
39
- Add to your `metro.config.js`:
68
+ ### 2. Configure Metro
40
69
 
41
70
  ```diff
42
71
  // metro.config.js
43
- const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');
44
- +const {createSerializer} = require('react-native-bundle-discovery');
45
-
46
- +const mySerializer = createSerializer({
47
- + includeCode: true, // Useful if you want to compare source/bundle code (but a report file will be larger)
48
- + projectRoot: __dirname,
49
- + //^^^ ⚠️ WARNING: In a monorepo setup, this should point to the monorepo root,
50
- + // not the individual package directory.
51
- +});
72
+ const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
73
+ +const { createSerializer } = require('react-native-bundle-discovery');
52
74
 
53
75
  -const config = {};
54
76
  +const config = {
55
- serializer: { customSerializer: mySerializer },
56
- };
77
+ + serializer: {
78
+ + customSerializer: createSerializer({
79
+ + projectRoot: __dirname, // ⚠️ In a monorepo, use the monorepo root instead
80
+ + }),
81
+ + },
82
+ +};
57
83
 
58
84
  module.exports = mergeConfig(getDefaultConfig(__dirname), config);
59
85
  ```
60
86
 
61
- #### 2. Install (as plugin for Rozenite)
62
-
63
- See: [_rozenite/README.md](_rozenite/README.md)
64
-
65
- ---
87
+ See all options in [`createSerializer`](#createserializeroptions).
66
88
 
67
- ### 3. Build the app
68
-
69
- For example, for iOS you can run the following command, and it will generate the `metro-stats.json` file in the root of your project:
89
+ ### 3. Build a release bundle
70
90
 
71
91
  ```bash
72
92
  npx react-native bundle \
@@ -77,122 +97,153 @@ npx react-native bundle \
77
97
  --assets-dest ios/assets
78
98
  ```
79
99
 
80
- ### 4. Commands
100
+ This writes `metro-stats.json` to your project root.
101
+
102
+ ### 4. Explore the report
103
+
104
+ ```bash
105
+ npx react-native-bundle-discovery-ui metro-stats.json # open in the browser
106
+ npx react-native-bundle-discovery-cli metro-stats.json # get recommendations in the terminal
107
+ ```
108
+
109
+ ## Other setups
110
+
111
+ | Setup | Guide |
112
+ | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
113
+ | Re.Pack (Rspack / Webpack) | [Re.Pack.md](./Re.Pack.md) |
114
+ | React Native DevTools | [Rozenite plugin](./packages/rozenite-plugin/README.md) |
115
+ | AI coding agent | Point your agent at the [`setup-react-native-bundle-discovery`](./skills/setup-react-native-bundle-discovery/SKILL.md) skill |
81
116
 
82
- #### CLI package
117
+ ## Usage
83
118
 
84
- You need to install `react-native-bundle-discovery-cli`
119
+ ### UI
120
+
121
+ Requires `react-native-bundle-discovery-ui`.
122
+
123
+ ```bash
124
+ # Start a local server (default port: 8079)
125
+ npx react-native-bundle-discovery-ui metro-stats.json [--port <port>]
126
+
127
+ # Build a static HTML report (default output: .bundle-discovery)
128
+ npx react-native-bundle-discovery-ui build metro-stats.json [--output <path>]
129
+ ```
130
+
131
+ ### CLI
132
+
133
+ Requires `react-native-bundle-discovery-cli`. Run any command with `--help` to see all options.
134
+
135
+ | Command | Description |
136
+ | ---------- | --------------------------------------------- |
137
+ | _(none)_ | Show recommended optimizations for the bundle |
138
+ | `packages` | List all packages in the bundle |
139
+ | `modules` | List the heaviest modules |
140
+ | `compare` | Compare two reports |
85
141
 
86
142
  ```bash
87
- # Display all recommended optimizations for the bundle
143
+ # Recommended optimizations
88
144
  npx react-native-bundle-discovery-cli metro-stats.json
89
145
 
90
- # Display all packages in the bundle report
146
+ # All packages
91
147
  npx react-native-bundle-discovery-cli packages metro-stats.json [--sort size|name] [--format json|table|default]
92
148
 
93
- # Display the heaviest modules in the bundle report (default limit: 50, --limit 0 shows all)
94
- # --filter accepts plain text (case-insensitive) or a regexp: --filter '/\.json/i'
149
+ # Heaviest modules (default --limit: 50, use 0 to show all)
150
+ # --filter accepts plain text (case-insensitive) or a regexp, e.g. --filter '/\.json/i'
95
151
  npx react-native-bundle-discovery-cli modules metro-stats.json [--limit 50] [--filter <text|/regexp/>] [--sort size|name] [--format json|table|default]
96
152
 
97
- # Compare two bundle reports: total size, added/removed/changed modules and packages,
153
+ # Diff two reports: total size, added/removed/changed modules and packages,
98
154
  # version changes, new duplicates and new deprecated packages
99
155
  npx react-native-bundle-discovery-cli compare --before main-stats.json --after pr-stats.json [--limit 50] [--format json|markdown|default]
100
156
  ```
101
157
 
102
- ##### Bundle size checks in CI
158
+ ### Bundle size checks in CI
159
+
160
+ `compare` exits with code `1` when any check fails:
103
161
 
104
- `compare` exits with code `1` when one of the checks fails:
162
+ | Option | Fails when | Example |
163
+ | -------------------- | ------------------------------------------------------------- | ------------------------------- |
164
+ | `--fail-on-increase` | The bundle grows more than the limit (bytes or % of "before") | `50KB`, `0.5MB`, `51200`, `5%` |
165
+ | `--max-size` | The "after" bundle is bigger than the limit | `3MB` |
166
+ | `--fail-on` | New duplicate and/or deprecated packages appear | `new-duplicates,new-deprecated` |
105
167
 
106
168
  ```bash
107
- # --fail-on-increase: max growth, in bytes (50KB, 0.5MB, 51200) or percent of the "before" size (5%)
108
- # --max-size: absolute limit for the "after" bundle
109
- # --fail-on: fail when new duplicate or new deprecated packages appear
110
169
  npx react-native-bundle-discovery-cli compare --before main-stats.json --after pr-stats.json \
111
170
  --fail-on-increase 50KB \
112
171
  --max-size 3MB \
113
172
  --fail-on new-duplicates,new-deprecated
114
173
  ```
115
174
 
116
- On GitHub Actions no extra setup is needed: the markdown report is added to the job summary
117
- and failed checks are shown as error annotations. Use `--format markdown` to get the same report for a PR comment.
175
+ **GitHub Actions** works out of the box: the markdown report is added to the job summary and failed checks
176
+ are shown as error annotations.
118
177
 
119
178
  ```yaml
120
- - run: npx react-native-bundle-discovery-cli compare --before main-stats0.json --after metro-stats1.json --fail-on-increase 5%
179
+ - run: npx react-native-bundle-discovery-cli compare --before main-stats.json --after pr-stats.json --fail-on-increase 5%
121
180
  ```
122
181
 
123
- #### UI package
182
+ To post the report as a PR comment, use `--format markdown`.
124
183
 
125
- You need to install `react-native-bundle-discovery-ui`
184
+ ## API
126
185
 
127
- ```bash
128
- # Start server to view the report in the browser (default port: 8079)
129
- npx react-native-bundle-discovery-ui metro-stats.json [--port <port>]
130
-
131
- # Build the report into a static HTML file
132
- npx react-native-bundle-discovery-ui build metro-stats.json
133
- ```
134
-
135
- ---
186
+ Exported from `react-native-bundle-discovery`.
136
187
 
137
- ### `react-native-bundle-discovery` JS API
188
+ ### `createSerializer(options)`
138
189
 
139
- #### `createSerializer(options: Options)`
190
+ Creates a Metro serializer that writes the JSON report. Use it as `serializer.customSerializer` (see [Quick start](#2-configure-metro)).
140
191
 
141
- | Prop | Default value | Description |
142
- | ---------------------- | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
143
- | serializer: Function | Default serializer | A custom serializer function. If not provided, a default serializer is used. |
144
- | projectRoot: string | Required | The root directory of the project. ⚠️ In a monorepo setup, this should point to the monorepo root, not the individual package directory. |
145
- | outputJsonPath: string | `<root>/metro-stats.json` | The path where the JSON report will be saved. Defaults to `metro-stats.json` in project root. |
146
- | includeCode: boolean | `true` | Whether to include the source and output code in the JSON report. |
192
+ | Option | Type | Default | Description |
193
+ | ----------------------- | ---------- | -------------------------------- | ----------------------------------------------------------------------------------------- |
194
+ | `projectRoot` | `string` | **Required** | Project root. ⚠️ In a monorepo, use the monorepo root, not the app package directory. |
195
+ | `outputJsonPath` | `string` | `<projectRoot>/metro-stats.json` | Where to save the report. |
196
+ | `includeCode` | `boolean` | `true` | Include source and bundled code of each module in the report (larger file). |
197
+ | `includeEnvs` | `string[]` | `[]` | Names of environment variables to include in the report. |
198
+ | `fetchPackagesMetadata` | `boolean` | `true` | Fetch package metadata (publish date, deprecation, latest version) from the npm registry. |
199
+ | `silent` | `boolean` | `false` | Disable log output. |
200
+ | `serializer` | `Function` | Metro default serializer | Custom serializer to wrap. |
147
201
 
148
- **⚠️ Be cautious sharing reports with `includeCode` enabled**
202
+ > [!WARNING]
203
+ > With `includeCode: true` (the default) the report **contains your source code**.
204
+ > If your code is proprietary, be careful who you share the report with.
149
205
 
150
- Enabling this option significantly increases report size and **embeds the source code** of your assets.
206
+ ### `createResolveRequest(options)`
151
207
 
152
- If your code is proprietary 🔒, share these reports responsibly 🤝!
208
+ Creates a Metro `resolveRequest` that removes unnecessary React Native modules from **release** bundles
209
+ (dev builds are not affected). The CLI recommends these options when they apply to your bundle.
153
210
 
154
- ---
155
-
156
- ### `createResolveRequest(options: ResolveRequestOptions)`
157
-
158
- | Prop | Default value | Description |
159
- | ------------------------------ | ------------- | ----------------------------------------------------------------------------------------------------------------------------- |
160
- | removePromisePolyfill: boolean | `false` | Remove the Promise polyfill as Hermes provide own impl. (issue: [#57702](https://github.com/react/react-native/issues/57702)) |
161
- | removeUTFSequence: boolean | `false` | Remove useless undocumented RN module. |
162
-
163
- Helper that creates a custom resolve request function to filter out unnecessary modules from the bundle.
164
- You can get recommendations during the analysis of the bundle report using the CLI tool.
211
+ | Option | Type | Default | Description |
212
+ | ------------------- | --------- | ------- | -------------------------------------------------------------------------------- |
213
+ | `removeUTFSequence` | `boolean` | `false` | Remove the unused `react-native/Libraries/UTFSequence.js` module. |
214
+ | `removeNewRenderer` | `boolean` | `false` | Remove the Fabric renderer. Enable only if the New Architecture is **disabled**. |
165
215
 
166
216
  ```js
167
217
  // metro.config.js
168
218
  const { createResolveRequest } = require("react-native-bundle-discovery");
169
- const resolveRequest = createResolveRequest({
170
- removePromisePolyfill: true,
171
- removeUTFSequence: true,
172
- });
219
+
173
220
  const config = {
174
221
  resolver: {
175
- resolveRequest,
222
+ resolveRequest: createResolveRequest({
223
+ removeUTFSequence: true,
224
+ }),
176
225
  },
177
226
  };
178
227
  ```
179
228
 
180
- ### Financial Contributors
229
+ ## Similar projects
181
230
 
182
- Become a financial contributor at [OpenCollective](https://opencollective.com/react-native-bundle-discovery) or [GitHub Sponsors](https://github.com/sponsors/retyui)
231
+ - [expo-atlas](https://github.com/expo/atlas)
232
+ - [expo-atlas-without-expo](https://github.com/v3ron/expo-atlas-without-expo)
233
+ - [react-native-bundle-visualizer](https://github.com/callstack/react-native-bundle-visualizer)
234
+ - [webpack-bundle-analyzer](https://github.com/webpack-contrib/webpack-bundle-analyzer)
235
+ - [bundle-stats](https://github.com/relative-ci/bundle-stats/tree/master/packages/cli#readme)
236
+ - [statoscope](https://github.com/statoscope/statoscope)
183
237
 
184
- ### Other
238
+ Built with [Discovery.js](https://github.com/discoveryjs/discovery)
239
+ ([views showcase](https://discoveryjs.github.io/discovery/#views-showcase),
240
+ [Jora syntax](https://discoveryjs.github.io/jora/#article:jora-syntax-operators)).
185
241
 
186
- **Similar projects:**
242
+ ## Support the project
187
243
 
188
- - [expo-atlas](https://github.com/expo/atlas) [![expo-atlas downloads](https://badgen.net/npm/dm/expo-atlas)](https://www.npmtrends.com/expo-atlas) [![expo-atlas install size](https://packagephobia.com/badge?p=expo-atlas)](https://packagephobia.com/result?p=expo-atlas)
189
- - [expo-atlas-without-expo](https://github.com/v3ron/expo-atlas-without-expo) [![expo-atlas-without-expo downloads](https://badgen.net/npm/dm/expo-atlas-without-expo)](https://www.npmtrends.com/expo-atlas-without-expo) [![expo-atlas-without-expo install size](https://packagephobia.com/badge?p=expo-atlas-without-expo)](https://packagephobia.com/result?p=expo-atlas-without-expo)
190
- - [react-native-bundle-visualizer](https://github.com/callstack/react-native-bundle-visualizer) [![react-native-bundle-visualizer downloads](https://badgen.net/npm/dm/react-native-bundle-visualizer)](https://www.npmtrends.com/react-native-bundle-visualizer)[![react-native-bundle-visualizer install size](https://packagephobia.com/badge?p=react-native-bundle-visualizer)](https://packagephobia.com/result?p=react-native-bundle-visualizer)
191
- - [webpack-bundle-analyzer](https://github.com/webpack-contrib/webpack-bundle-analyzer) [![webpack-bundle-analyzer downloads](https://badgen.net/npm/dm/webpack-bundle-analyzer)](https://www.npmtrends.com/webpack-bundle-analyzer)[![webpack-bundle-analyzer install size](https://packagephobia.com/badge?p=webpack-bundle-analyzer)](https://packagephobia.com/result?p=webpack-bundle-analyzer)
192
- - [bundle-stats](https://github.com/relative-ci/bundle-stats/tree/master/packages/cli#readme) [![bundle-stats downloads](https://badgen.net/npm/dm/bundle-stats)](https://www.npmtrends.com/bundle-stats)[![bundle-stats install size](https://packagephobia.com/badge?p=bundle-stats)](https://packagephobia.com/result?p=bundle-stats)
193
- - [statoscope](https://github.com/statoscope/statoscope) [![@statoscope/cli downloads](https://badgen.net/npm/dm/@statoscope/cli)](https://www.npmtrends.com/@statoscope/cli)[![@statoscope/cli install size](https://packagephobia.com/badge?p=@statoscope/cli)](https://packagephobia.com/result?p=@statoscope/cli)
244
+ Become a financial contributor on [OpenCollective](https://opencollective.com/react-native-bundle-discovery)
245
+ or [GitHub Sponsors](https://github.com/sponsors/retyui).
194
246
 
195
- **Built using [Discovery.js](https://github.com/discoveryjs/discovery):**
247
+ ## License
196
248
 
197
- - Build blocks for pages: https://discoveryjs.github.io/discovery/#views-showcase
198
- - Jora syntax: https://discoveryjs.github.io/jora/#article:jora-syntax-operators
249
+ MIT
@@ -0,0 +1,262 @@
1
+ import { Buffer } from "node:buffer";
2
+ //#region src/types.d.ts
3
+ /**
4
+ * Shape of the `metro-stats.json` report.
5
+ * Mirrors the report types of the (private) monorepo `shared` package; kept local so the
6
+ * published `.d.ts` is self-contained.
7
+ */
8
+ interface PackageMetadata {
9
+ createdAt: string | null;
10
+ deprecated: string | false;
11
+ isLatest: boolean;
12
+ latestVersion: string | null;
13
+ }
14
+ interface SizeInfo {
15
+ sizeInBytes: number;
16
+ }
17
+ interface CodeInfo extends SizeInfo {
18
+ code: string;
19
+ lineCount: number;
20
+ }
21
+ interface ReportPackage {
22
+ name: string;
23
+ absolutePath: string;
24
+ version: string;
25
+ metadata?: PackageMetadata | null;
26
+ }
27
+ interface ReportModuleDependency {
28
+ absolutePath: string;
29
+ name: string;
30
+ }
31
+ interface ReportModule {
32
+ path: string;
33
+ source: CodeInfo;
34
+ output: CodeInfo;
35
+ dependencies: ReportModuleDependency[];
36
+ }
37
+ interface TransformOptions {
38
+ customTransformOptions?: Record<string, unknown>;
39
+ dev: boolean;
40
+ minify: boolean;
41
+ platform: string;
42
+ type?: string;
43
+ unstable_transformProfile?: string;
44
+ [key: string]: unknown;
45
+ }
46
+ //#endregion
47
+ //#region src/parseUtils.d.ts
48
+ type Modules = Record<string, string>;
49
+ interface ParseBundleOptions {
50
+ sourceType?: "script" | "module";
51
+ expectedModuleIds?: (string | number)[];
52
+ }
53
+ declare function parseBundle(bundlePath: string, opts?: ParseBundleOptions): {
54
+ modules: Modules;
55
+ src: string;
56
+ runtimeSrc: string;
57
+ };
58
+ //#endregion
59
+ //#region src/webpack.d.ts
60
+ /** Options passed to `stats.toJson()` (https://webpack.js.org/configuration/stats/) */
61
+ type StatsOptions = Record<string, unknown>;
62
+ /** Minimal shape of the (normalized) Webpack/Rspack compiler options used by the plugin */
63
+ interface CompilerOptions {
64
+ context?: string;
65
+ mode?: string;
66
+ name?: string;
67
+ output: {
68
+ path?: string;
69
+ };
70
+ optimization?: {
71
+ minimize?: boolean;
72
+ };
73
+ }
74
+ /** Minimal shape of a Webpack/Rspack `Stats` object */
75
+ interface Stats {
76
+ toJson(options: StatsOptions): unknown;
77
+ }
78
+ /** Minimal shape of a Webpack/Rspack `Compiler` */
79
+ interface Compiler {
80
+ options: CompilerOptions;
81
+ hooks: {
82
+ done: {
83
+ tap(name: string, callback: (stats: Stats) => void): void;
84
+ };
85
+ };
86
+ }
87
+ interface StatsReason {
88
+ type?: string;
89
+ modulePath?: string;
90
+ moduleNameForCondition?: string;
91
+ resolvedModule?: string;
92
+ moduleIdentifier?: string;
93
+ userRequest?: string;
94
+ }
95
+ interface StatsModule {
96
+ id?: string | number;
97
+ type?: string;
98
+ path?: string;
99
+ identifier?: string;
100
+ nameForCondition?: string;
101
+ source?: string;
102
+ size?: number;
103
+ reasons?: StatsReason[];
104
+ }
105
+ interface StatsAsset {
106
+ name: string;
107
+ info: {
108
+ javascriptModule?: boolean;
109
+ };
110
+ }
111
+ interface StatsJson {
112
+ builtAt?: number;
113
+ assets: StatsAsset[];
114
+ modules: StatsModule[];
115
+ }
116
+ type ParsedBundle = ReturnType<typeof parseBundle>;
117
+ interface WebpackReport {
118
+ kind: "webpack";
119
+ date: number;
120
+ entryPoint: string;
121
+ rootFolder: string;
122
+ transformOptions: TransformOptions;
123
+ modules: ReportModule[];
124
+ packages: ReportPackage[];
125
+ }
126
+ interface BundleDiscoveryPluginOptions {
127
+ /** Output file name (resolved against the compiler `context`). Defaults to `"metro-stats.json"`. */
128
+ filename?: string;
129
+ /** Extra options passed to `stats.toJson()`. */
130
+ options?: StatsOptions;
131
+ /** Whether the plugin is enabled. Defaults to `true`. */
132
+ enabled?: boolean;
133
+ /** Whether to fetch packages metadata (publish date, deprecation, latest version) from the npm registry. Defaults to `true`. */
134
+ fetchPackagesMetadata?: boolean;
135
+ }
136
+ /**
137
+ * Simple Webpack/Rspack plugin
138
+ * to adapt stats object https://webpack.js.org/api/stats/
139
+ * to metro-stats.json format used by `react-native-bundle-discovery`
140
+ */
141
+ export declare class BundleDiscoveryPlugin {
142
+ options: StatsOptions | undefined;
143
+ filename: string;
144
+ enabled: boolean;
145
+ fetchPackagesMetadata: boolean;
146
+ constructor({ filename, options, enabled, fetchPackagesMetadata }?: BundleDiscoveryPluginOptions);
147
+ extractSizesFromJsBundle(statAsset: StatsAsset, options: CompilerOptions): ParsedBundle | null;
148
+ apply(compiler: Compiler): void;
149
+ writeReport(statsJson: WebpackReport, outputPath: string): Promise<void>;
150
+ readSource(filePath: string): CodeInfo;
151
+ getPkgVersionFromPath(path: string): string | null;
152
+ getPackages(statsJson: StatsJson): ReportPackage[];
153
+ getEntryFile(statsJson: StatsJson, rootFolder: string): string;
154
+ getModuleOutput(mdl: StatsModule, bundleModules: ParsedBundle | null): CodeInfo;
155
+ formatStat(statsJson: StatsJson, bundleModules: ParsedBundle | null, compilerOptions: CompilerOptions): WebpackReport;
156
+ buildImportsMapFromReasons(statsJson: StatsJson, compilerOptions: CompilerOptions): Map<string, ReportModuleDependency[]>;
157
+ findCommonRoot(paths: string[]): string;
158
+ }
159
+ //#endregion
160
+ //#region src/index.d.ts
161
+ /** Minimal shape of a Metro module (`Module` from `metro/src/DeltaBundler/types`) */
162
+ interface MetroModule {
163
+ path: string;
164
+ getSource(): Buffer;
165
+ output: ReadonlyArray<{
166
+ data: {
167
+ code: string;
168
+ lineCount: number;
169
+ };
170
+ }>;
171
+ dependencies?: Map<string, {
172
+ absolutePath?: string | null;
173
+ data: {
174
+ name: string;
175
+ };
176
+ }>;
177
+ }
178
+ /** Minimal shape of a Metro graph (`ReadOnlyGraph` from `metro/src/DeltaBundler/types`) */
179
+ interface MetroGraph {
180
+ dependencies: Map<string, MetroModule>;
181
+ transformOptions: TransformOptions;
182
+ }
183
+ /** Minimal shape of Metro serializer options */
184
+ interface MetroSerializerOptions {
185
+ processModuleFilter?: (module: MetroModule) => boolean;
186
+ sentryBundleCallback?: (bundle: unknown) => unknown;
187
+ [key: string]: unknown;
188
+ }
189
+ type MetroSerializerResult = string | {
190
+ code: string;
191
+ map: string;
192
+ } | Promise<string | {
193
+ code: string;
194
+ map: string;
195
+ }>;
196
+ type MetroSerializer = (entryPoint: string, preModules: ReadonlyArray<MetroModule>, graph: MetroGraph, options: MetroSerializerOptions) => MetroSerializerResult;
197
+ interface CreateSerializerOptions {
198
+ /** A custom serializer function. If not provided, a default serializer is used. */
199
+ serializer?: MetroSerializer;
200
+ /** The root directory of the project. Must exist. */
201
+ projectRoot: string;
202
+ /** The path where the JSON report will be saved. Defaults to "metro-stats.json" in the project root. */
203
+ outputJsonPath?: string;
204
+ /** Whether to include the source and output code in the JSON report. Defaults to `true`. */
205
+ includeCode?: boolean;
206
+ /** Whether to suppress log messages. Defaults to `false`. */
207
+ silent?: boolean;
208
+ /** A list of environment variable names to include in the JSON report. Defaults to `[]`. */
209
+ includeEnvs?: string[];
210
+ /** Whether to fetch packages metadata (publish date, deprecation, latest version) from the npm registry. Defaults to `true`. */
211
+ fetchPackagesMetadata?: boolean;
212
+ }
213
+ /**
214
+ * Creates a custom serializer function for Metro bundler, which generates a JSON report
215
+ * and optionally modifies the serialization process.
216
+ *
217
+ * @param options - Configuration options for the serializer.
218
+ * @returns A custom serializer function to be used by Metro.
219
+ * @throws Throws an error if the project root does not exist.
220
+ */
221
+ declare function createSerializer({ serializer, projectRoot, outputJsonPath, includeCode, silent, includeEnvs, fetchPackagesMetadata }?: CreateSerializerOptions): MetroSerializer;
222
+ /** Minimal shape of a Metro resolution result */
223
+ type MetroResolution = {
224
+ type: string;
225
+ filePath?: string;
226
+ };
227
+ /** Minimal shape of a Metro resolution context */
228
+ interface MetroResolutionContext {
229
+ dev: boolean;
230
+ resolveRequest(context: MetroResolutionContext, moduleName: string, platform: string | null): MetroResolution;
231
+ }
232
+ /**
233
+ * Usage:
234
+ *
235
+ * ```js
236
+ * // metro.config.js
237
+ * const { createResolveRequest } = require("react-native-bundle-discovery");
238
+ * const resolveRequest = createResolveRequest({
239
+ * removePromisePolyfill: true,
240
+ * });
241
+ * const config = {
242
+ * resolver: {
243
+ * resolveRequest,
244
+ * },
245
+ * };
246
+ * ```
247
+ */
248
+ declare const createResolveRequest: ({ removeNewRenderer, removeUTFSequence }?: {
249
+ removeNewRenderer?: boolean;
250
+ removeUTFSequence?: boolean;
251
+ }) => (context: MetroResolutionContext, moduleName: string, platform: string | null) => MetroResolution;
252
+ /**
253
+ * @deprecated Use `createResolveRequest` instead.
254
+ */
255
+ declare const createProcessModuleFilter: ({ removePromisePolyfill, removeUTFSequence }?: {
256
+ removePromisePolyfill?: boolean;
257
+ removeUTFSequence?: boolean;
258
+ }) => (module: {
259
+ path: string;
260
+ }) => boolean;
261
+ //#endregion
262
+ export { createProcessModuleFilter, createResolveRequest, createSerializer };