rollipop 1.0.0-alpha.21 → 1.0.0-alpha.23

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.
Files changed (161) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/{chunk-DEq-mXcV.js → _virtual/_rolldown/runtime.js} +1 -1
  3. package/dist/commands.d.ts +2 -4
  4. package/dist/commands.js +10 -3957
  5. package/dist/common/code.js +21 -0
  6. package/dist/common/constants.js +5 -0
  7. package/dist/common/env.js +33 -0
  8. package/dist/common/logger.d.ts +34 -0
  9. package/dist/common/logger.js +82 -0
  10. package/dist/common/logo.js +54 -0
  11. package/dist/common/progress-bar.js +167 -0
  12. package/dist/common/transformer.js +13 -0
  13. package/dist/common/types.d.ts +10 -0
  14. package/dist/config/compose-override.js +18 -0
  15. package/dist/config/defaults.d.ts +74 -0
  16. package/dist/config/defaults.js +74 -0
  17. package/dist/config/define-config.d.ts +13 -0
  18. package/dist/config/define-config.js +6 -0
  19. package/dist/config/index.d.ts +5 -0
  20. package/dist/config/index.js +5 -0
  21. package/dist/config/load-config.d.ts +19 -0
  22. package/dist/config/load-config.js +73 -0
  23. package/dist/config/merge-config.d.ts +12 -0
  24. package/dist/config/merge-config.js +20 -0
  25. package/dist/config/types.d.ts +452 -0
  26. package/dist/constants.d.ts +35 -0
  27. package/dist/constants.js +146 -0
  28. package/dist/core/assets.d.ts +91 -0
  29. package/dist/core/assets.js +244 -0
  30. package/dist/core/bundler.d.ts +15 -0
  31. package/dist/core/bundler.js +80 -0
  32. package/dist/core/env.d.ts +11 -0
  33. package/dist/core/env.js +36 -0
  34. package/dist/core/fs/data.js +9 -0
  35. package/dist/core/fs/storage.d.ts +15 -0
  36. package/dist/core/fs/storage.js +31 -0
  37. package/dist/core/plugins/babel-plugin.d.ts +22 -0
  38. package/dist/core/plugins/babel-plugin.js +74 -0
  39. package/dist/core/plugins/context.d.ts +10 -0
  40. package/dist/core/plugins/context.js +24 -0
  41. package/dist/core/plugins/dev-server-plugin.d.ts +13 -0
  42. package/dist/core/plugins/dev-server-plugin.js +27 -0
  43. package/dist/core/plugins/index.d.ts +13 -0
  44. package/dist/core/plugins/index.js +18 -0
  45. package/dist/core/plugins/prelude-plugin.d.ts +10 -0
  46. package/dist/core/plugins/prelude-plugin.js +23 -0
  47. package/dist/core/plugins/react-native-plugin.d.ts +36 -0
  48. package/dist/core/plugins/react-native-plugin.js +81 -0
  49. package/dist/core/plugins/reporter-plugin.d.ts +11 -0
  50. package/dist/core/plugins/reporter-plugin.js +87 -0
  51. package/dist/core/plugins/shared/filters.js +5 -0
  52. package/dist/core/plugins/swc-plugin.d.ts +26 -0
  53. package/dist/core/plugins/swc-plugin.js +108 -0
  54. package/dist/core/plugins/types.d.ts +18 -0
  55. package/dist/core/plugins/utils/source.js +10 -0
  56. package/dist/core/plugins/utils/transform-utils.js +56 -0
  57. package/dist/core/rolldown.js +313 -0
  58. package/dist/core/settings.js +19 -0
  59. package/dist/core/types.d.ts +83 -0
  60. package/dist/filter.d.ts +1 -0
  61. package/dist/filter.js +2 -0
  62. package/dist/hmr-runtime.iife.js +5 -5
  63. package/dist/index.d.ts +24 -1221
  64. package/dist/index.js +19 -4029
  65. package/dist/internal/react-native.js +24 -0
  66. package/dist/logger.js +5 -0
  67. package/dist/node/cli-utils.d.ts +10 -0
  68. package/dist/node/cli-utils.js +28 -0
  69. package/dist/node/cli.d.ts +6 -0
  70. package/dist/node/cli.js +23 -0
  71. package/dist/node/commands/agent/action.js +91 -0
  72. package/dist/node/commands/agent/command.js +10 -0
  73. package/dist/node/commands/agent/index.js +2 -0
  74. package/dist/node/commands/bundle/action.js +33 -0
  75. package/dist/node/commands/bundle/command.js +96 -0
  76. package/dist/node/commands/bundle/index.js +2 -0
  77. package/dist/node/commands/start/action.js +37 -0
  78. package/dist/node/commands/start/command.js +93 -0
  79. package/dist/node/commands/start/debugger.js +79 -0
  80. package/dist/node/commands/start/index.js +2 -0
  81. package/dist/node/commands/start/setup-interactive-mode.d.ts +20 -0
  82. package/dist/node/commands/start/setup-interactive-mode.js +107 -0
  83. package/dist/node/constants.js +4 -0
  84. package/dist/node/logger.js +5 -0
  85. package/dist/node/types.d.ts +23 -0
  86. package/dist/node/utils.js +23 -0
  87. package/dist/package.js +4 -0
  88. package/dist/runtime.js +1 -1
  89. package/dist/server/bundle.d.ts +12 -0
  90. package/dist/server/bundle.js +55 -0
  91. package/dist/server/bundler-pool.d.ts +51 -0
  92. package/dist/server/bundler-pool.js +197 -0
  93. package/dist/server/common/schema.js +19 -0
  94. package/dist/server/constants.d.ts +6 -0
  95. package/dist/server/constants.js +6 -0
  96. package/dist/server/create-dev-server.d.ts +6 -0
  97. package/dist/server/create-dev-server.js +185 -0
  98. package/dist/server/error.js +9 -0
  99. package/dist/server/events/event-bus.d.ts +12 -0
  100. package/dist/server/events/event-bus.js +16 -0
  101. package/dist/server/events/types.d.ts +37 -0
  102. package/dist/server/events/types.js +6 -0
  103. package/dist/server/index.d.ts +3 -0
  104. package/dist/server/index.js +3 -0
  105. package/dist/server/logger.js +33 -0
  106. package/dist/server/mcp/context.js +14 -0
  107. package/dist/server/mcp/server.js +86 -0
  108. package/dist/server/mcp/tools/app-log-diagnostics.js +37 -0
  109. package/dist/server/mcp/tools/build-diagnostics.js +97 -0
  110. package/dist/server/mcp/tools/build-info.js +33 -0
  111. package/dist/server/mcp/tools/device-diagnostics.js +52 -0
  112. package/dist/server/mcp/tools/index.js +277 -0
  113. package/dist/server/middlewares/request-logger.js +15 -0
  114. package/dist/server/middlewares/serve-assets.js +49 -0
  115. package/dist/server/middlewares/serve-bundle.js +72 -0
  116. package/dist/server/middlewares/sse.js +34 -0
  117. package/dist/server/middlewares/symbolicate.js +71 -0
  118. package/dist/server/sse/adapter.js +74 -0
  119. package/dist/server/sse/event-bus.js +26 -0
  120. package/dist/server/symbolicate.js +93 -0
  121. package/dist/server/types.d.ts +125 -0
  122. package/dist/server/wss/hmr-server.js +209 -0
  123. package/dist/server/wss/server.d.ts +9 -0
  124. package/dist/server/wss/server.js +70 -0
  125. package/dist/{runtime.d.cts → types/hmr.d.ts} +1 -12
  126. package/dist/types.d.ts +78 -0
  127. package/dist/utils/babel.js +11 -0
  128. package/dist/utils/build-options.js +17 -0
  129. package/dist/utils/bundle.js +6 -0
  130. package/dist/utils/config.d.ts +5 -0
  131. package/dist/utils/config.js +32 -0
  132. package/dist/utils/dev-server.js +51 -0
  133. package/dist/utils/env.js +7 -0
  134. package/dist/utils/errors.js +9 -0
  135. package/dist/utils/hash.js +8 -0
  136. package/dist/utils/id.js +28 -0
  137. package/dist/utils/node-resolve.js +42 -0
  138. package/dist/utils/promise.js +15 -0
  139. package/dist/utils/reporters.js +120 -0
  140. package/dist/utils/reset-cache.d.ts +8 -0
  141. package/dist/utils/reset-cache.js +25 -0
  142. package/dist/utils/response.js +91 -0
  143. package/dist/utils/run-build.d.ts +8 -0
  144. package/dist/utils/run-build.js +7 -0
  145. package/dist/utils/run-server.d.ts +6 -0
  146. package/dist/utils/run-server.js +20 -0
  147. package/dist/utils/runtime-target.js +9 -0
  148. package/dist/utils/serialize.js +10 -0
  149. package/dist/utils/server.js +6 -0
  150. package/dist/utils/storage.js +6 -0
  151. package/dist/utils/string.js +6 -0
  152. package/dist/utils/swc.js +10 -0
  153. package/dist/utils/terminal.js +86 -0
  154. package/dist/utils/url.js +23 -0
  155. package/package.json +56 -68
  156. package/dist/commands.cjs +0 -4008
  157. package/dist/commands.d.cts +0 -5
  158. package/dist/pluginutils.d.ts +0 -1
  159. package/dist/pluginutils.js +0 -2
  160. package/dist/runtime.cjs +0 -34
  161. /package/dist/{chunk-DXpK5_cz.js → chunk-DJV587Yu.js} +0 -0
package/dist/commands.cjs DELETED
@@ -1,4008 +0,0 @@
1
- //#region \0rolldown/runtime.js
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __copyProps = (to, from, except, desc) => {
9
- if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
- key = keys[i];
11
- if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
- get: ((k) => from[k]).bind(null, key),
13
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
- });
15
- }
16
- return to;
17
- };
18
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
- value: mod,
20
- enumerable: true
21
- }) : target, mod));
22
- //#endregion
23
- require("@commander-js/extra-typings");
24
- let es_toolkit = require("es-toolkit");
25
- let chalk = require("chalk");
26
- chalk = __toESM(chalk);
27
- let gradient_string = require("gradient-string");
28
- gradient_string = __toESM(gradient_string);
29
- let node_path = require("node:path");
30
- node_path = __toESM(node_path);
31
- let dayjs = require("dayjs");
32
- dayjs = __toESM(dayjs);
33
- let node_readline = require("node:readline");
34
- node_readline = __toESM(node_readline);
35
- let node_tty = require("node:tty");
36
- let _inquirer_prompts = require("@inquirer/prompts");
37
- let node_fs = require("node:fs");
38
- node_fs = __toESM(node_fs);
39
- let url = require("url");
40
- url = __toESM(url);
41
- let _react_native_community_cli_server_api = require("@react-native-community/cli-server-api");
42
- let _react_native_dev_middleware = require("@react-native/dev-middleware");
43
- let fastify = require("fastify");
44
- fastify = __toESM(fastify);
45
- let mitt = require("mitt");
46
- mitt = __toESM(mitt);
47
- let node_http = require("node:http");
48
- node_http = __toESM(node_http);
49
- let node_events = require("node:events");
50
- node_events = __toESM(node_events);
51
- let _rollipop_rolldown = require("@rollipop/rolldown");
52
- _rollipop_rolldown = __toESM(_rollipop_rolldown);
53
- let _rollipop_rolldown_experimental = require("@rollipop/rolldown/experimental");
54
- _rollipop_rolldown_experimental = __toESM(_rollipop_rolldown_experimental);
55
- let node_crypto = require("node:crypto");
56
- node_crypto = __toESM(node_crypto);
57
- require("@node-rs/xxhash");
58
- let dedent = require("dedent");
59
- dedent = __toESM(dedent);
60
- let wrap_ansi = require("wrap-ansi");
61
- wrap_ansi = __toESM(wrap_ansi);
62
- let dotenv = require("dotenv");
63
- dotenv = __toESM(dotenv);
64
- let dotenv_expand = require("dotenv-expand");
65
- dotenv_expand = __toESM(dotenv_expand);
66
- let _rollipop_rolldown_pluginutils = require("@rollipop/rolldown-pluginutils");
67
- let fast_flow_transform = require("fast-flow-transform");
68
- fast_flow_transform = __toESM(fast_flow_transform);
69
- let image_size = require("image-size");
70
- let _babel_core = require("@babel/core");
71
- _babel_core = __toESM(_babel_core);
72
- let _swc_core = require("@swc/core");
73
- _swc_core = __toESM(_swc_core);
74
- let strip_ansi = require("strip-ansi");
75
- strip_ansi = __toESM(strip_ansi);
76
- let source_map = require("source-map");
77
- let _modelcontextprotocol_sdk_server_mcp_js = require("@modelcontextprotocol/sdk/server/mcp.js");
78
- let _modelcontextprotocol_sdk_server_streamableHttp_js = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
79
- let _modelcontextprotocol_sdk_types_js = require("@modelcontextprotocol/sdk/types.js");
80
- let fastify_plugin = require("fastify-plugin");
81
- fastify_plugin = __toESM(fastify_plugin);
82
- let zod = require("zod");
83
- let json_schema_to_ts = require("json-schema-to-ts");
84
- let mime = require("mime");
85
- mime = __toESM(mime);
86
- let ajv = require("ajv");
87
- ajv = __toESM(ajv);
88
- let _babel_code_frame = require("@babel/code-frame");
89
- let ws = require("ws");
90
- ws = __toESM(ws);
91
- let c12 = require("c12");
92
- c12 = __toESM(c12);
93
- //#region src/common/logo.ts
94
- const CANDY = `
95
- _....._
96
- .' _..._ '.
97
- / /\` __ \`\\ \\
98
- ; ; /\` \\ | ;
99
- | | | (_/ ; |
100
- ; ; \\_ _.' .;
101
- \\ '. \`\` _.'/
102
- '._\`"'"\`_.'`;
103
- const STICK = `
104
- / /\`\`
105
- / /
106
- /__/`;
107
- const DESCRIPTIONS = [
108
- "Rollipop",
109
- "Modern build toolkit for React Native",
110
- "Powered by Rolldown"
111
- ];
112
- const PRIMARY_COLOR = "#42A5F5";
113
- const BASE_GRADIENT_COLORS = [PRIMARY_COLOR, "#BBDEFB"];
114
- const PADDING = 20;
115
- function printLogo() {
116
- let maxLogoWidth = 0;
117
- const padding = " ".repeat(PADDING);
118
- const gradientColors = [...BASE_GRADIENT_COLORS];
119
- const styledCandy = CANDY.split("\n").map((line) => {
120
- maxLogoWidth = Math.max(line.length, maxLogoWidth);
121
- return (0, gradient_string.default)(gradientColors.reverse())(line);
122
- }).join("\n") + STICK;
123
- console.log(styledCandy.split("\n").map((line) => padding + line).join("\n"));
124
- console.log("");
125
- DESCRIPTIONS.forEach((description, index) => {
126
- const descriptionHalfLength = description.length / 2;
127
- const logoHalfWidth = maxLogoWidth / 2;
128
- const padding = " ".repeat(PADDING - descriptionHalfLength + logoHalfWidth);
129
- if (index === 0) console.log(padding + chalk.default.bold.hex(PRIMARY_COLOR)(description));
130
- else console.log(padding + description);
131
- });
132
- console.log("");
133
- }
134
- let _printed = false;
135
- const Logo = {
136
- print: printLogo,
137
- printOnce: () => {
138
- if (_printed) return;
139
- _printed = true;
140
- printLogo();
141
- }
142
- };
143
- const SHARED_DATA_PATH = ".rollipop";
144
- //#endregion
145
- //#region src/common/env.ts
146
- const TRUTHY_VALUES = [
147
- "yes",
148
- "on",
149
- "true",
150
- "enabled"
151
- ];
152
- const FALSY_VALUES = [
153
- "no",
154
- "off",
155
- "false",
156
- "disabled"
157
- ];
158
- function parseDebugKeys() {
159
- return Object.keys(process.env).filter((key) => /^debug_/i.test(key)).reduce((acc, key) => {
160
- const prop = key.slice(6).toLowerCase().replace(/_([a-z])/g, (_, key) => key.toUpperCase());
161
- let value = process.env[key];
162
- const lowerCase = typeof value === "string" ? value.toLowerCase() : value.toString();
163
- if (TRUTHY_VALUES.includes(lowerCase)) value = true;
164
- else if (FALSY_VALUES.includes(lowerCase)) value = false;
165
- else value = Boolean(Number(value));
166
- acc[prop] = value;
167
- return acc;
168
- }, {});
169
- }
170
- let debugKeys = null;
171
- function isDebugEnabled() {
172
- if (debugKeys == null) debugKeys = parseDebugKeys();
173
- return debugKeys["rollipop"] ?? false;
174
- }
175
- //#endregion
176
- //#region src/common/logger.ts
177
- var Logger = class Logger {
178
- static blocked = false;
179
- static queuedMessages = [];
180
- static Colors = {
181
- trace: chalk.default.gray,
182
- debug: chalk.default.blue,
183
- log: chalk.default.green,
184
- info: chalk.default.cyan,
185
- warn: chalk.default.yellow,
186
- error: chalk.default.red
187
- };
188
- format = "HH:mm:ss.SSS";
189
- debugEnabled;
190
- static block() {
191
- this.blocked = true;
192
- }
193
- static unblock(flush = true) {
194
- this.blocked = false;
195
- if (flush) for (const args of Logger.queuedMessages) console.log(...args);
196
- Logger.queuedMessages.length = 0;
197
- }
198
- constructor(scope) {
199
- this.scope = scope;
200
- this.debugEnabled = isDebugEnabled();
201
- }
202
- getFormat() {
203
- return this.format;
204
- }
205
- setFormat(format) {
206
- this.format = format;
207
- }
208
- getTimestamp() {
209
- return (0, dayjs.default)().format(this.getFormat());
210
- }
211
- print(logLevel, ...args) {
212
- const timestamp = chalk.default.gray(this.getTimestamp());
213
- const level = Logger.Colors[logLevel](logLevel);
214
- if (this.scope) args = [
215
- timestamp,
216
- level,
217
- chalk.default.magenta(this.scope),
218
- ...args
219
- ];
220
- else args = [
221
- timestamp,
222
- level,
223
- ...args
224
- ];
225
- if (Logger.blocked) Logger.queuedMessages.push(args);
226
- else console.log(...args);
227
- }
228
- trace(...args) {
229
- this.debugEnabled && this.print("trace", ...args);
230
- }
231
- debug(...args) {
232
- this.debugEnabled && this.print("debug", ...args);
233
- }
234
- log(...args) {
235
- this.print("log", ...args);
236
- }
237
- info(...args) {
238
- this.print("info", ...args);
239
- }
240
- warn(...args) {
241
- this.print("warn", ...args);
242
- }
243
- error(...args) {
244
- this.print("error", ...args);
245
- }
246
- child(scope) {
247
- (0, es_toolkit.invariant)(this.scope, "Logger must have a scope to create a child logger");
248
- return new Logger(`${this.scope}:${scope}`);
249
- }
250
- };
251
- //#endregion
252
- //#region src/node/logger.ts
253
- const logger$2 = new Logger("cli");
254
- //#endregion
255
- //#region src/node/utils.ts
256
- function parseBoolean(value) {
257
- return value === "true" || value === "1";
258
- }
259
- function resolvePath(value) {
260
- return node_path.default.resolve(value);
261
- }
262
- //#endregion
263
- //#region src/core/fs/data.ts
264
- function getSharedDataPath(basePath) {
265
- return node_path.default.join(basePath, SHARED_DATA_PATH);
266
- }
267
- //#endregion
268
- //#region src/core/settings.ts
269
- function getSettingsPath(basePath) {
270
- return node_path.default.join(getSharedDataPath(basePath), "settings.json");
271
- }
272
- function loadSettings(basePath) {
273
- const settingsPath = getSettingsPath(basePath);
274
- if (!node_fs.default.existsSync(settingsPath)) return {};
275
- return JSON.parse(node_fs.default.readFileSync(settingsPath, "utf-8"));
276
- }
277
- function saveSettings(basePath, settings) {
278
- const newSettings = (0, es_toolkit.merge)(loadSettings(basePath), settings);
279
- node_fs.default.writeFileSync(getSettingsPath(basePath), JSON.stringify(newSettings, null, 2));
280
- }
281
- //#endregion
282
- //#region src/node/commands/start/debugger.ts
283
- var DebuggerOpener = class DebuggerOpener {
284
- static MAX_TARGETS_SHOWN = 10;
285
- _prompting = false;
286
- settings;
287
- autoOpened = false;
288
- static setAutoOpenEnabled(projectRoot, enabled) {
289
- saveSettings(projectRoot, { devtools: { autoOpen: enabled } });
290
- }
291
- constructor(projectRoot, serverUrl) {
292
- this.projectRoot = projectRoot;
293
- this.serverUrl = serverUrl;
294
- this.settings = loadSettings(projectRoot);
295
- }
296
- async openDebuggerForTarget(target) {
297
- logger$2.debug(`Opening debugger for target: ${target.id}`);
298
- try {
299
- await fetch(new URL("/open-debugger?target=" + encodeURIComponent(target.id), this.serverUrl), { method: "POST" });
300
- } catch (error) {
301
- logger$2.error(`Failed to open debugger for ${target.title}`);
302
- logger$2.debug("Reason", error);
303
- }
304
- }
305
- async autoOpen() {
306
- if (this.autoOpened) return;
307
- this.autoOpened = true;
308
- if (this.isAutoOpenEnabled()) await this.open();
309
- }
310
- async open() {
311
- logger$2.debug("Fetching available debugging targets...");
312
- const response = await fetch(new URL("/json/list", this.serverUrl), { method: "POST" });
313
- if (response.status !== 200) throw new Error(`Unexpected status code: ${response.status}`);
314
- const targets = await response.json();
315
- if (!Array.isArray(targets)) throw new Error("Unexpected response format");
316
- logger$2.debug(`Found ${targets.length} debugging targets:`);
317
- if (targets.length === 0) logger$2.warn("No connected targets");
318
- else if (targets.length === 1) {
319
- const target = targets[0];
320
- await this.openDebuggerForTarget(target);
321
- } else {
322
- if (targets.length > DebuggerOpener.MAX_TARGETS_SHOWN) logger$2.warn(`More than ${DebuggerOpener.MAX_TARGETS_SHOWN} debug targets available, showing the first ${DebuggerOpener.MAX_TARGETS_SHOWN}.`);
323
- const slicedTargets = targets.slice(0, DebuggerOpener.MAX_TARGETS_SHOWN);
324
- Logger.block();
325
- this._prompting = true;
326
- try {
327
- const targetIndex = await (0, _inquirer_prompts.select)({
328
- message: "Multiple debug targets available, please select:",
329
- choices: slicedTargets.map((target, index) => ({
330
- value: index,
331
- name: `${target.title} (${target.description})`
332
- }))
333
- });
334
- await this.openDebuggerForTarget(slicedTargets[targetIndex]);
335
- } catch {} finally {
336
- Logger.unblock();
337
- this._prompting = false;
338
- }
339
- }
340
- }
341
- isPrompting() {
342
- return this._prompting;
343
- }
344
- isAutoOpenEnabled() {
345
- return this.settings.devtools?.autoOpen ?? false;
346
- }
347
- setAutoOpenEnabled(enabled) {
348
- const newSettings = this.settings = (0, es_toolkit.merge)(this.settings, { devtools: { autoOpen: enabled } });
349
- saveSettings(this.projectRoot, newSettings);
350
- }
351
- };
352
- //#endregion
353
- //#region src/node/commands/start/setup-interactive-mode.ts
354
- const CTRL_C = "";
355
- const CTRL_D = "";
356
- const BROADCAST_THROTTLE_DELAY = 500;
357
- function setupInteractiveMode(options) {
358
- const { devServer, extraCommands = [] } = options;
359
- if (!devServer.instance.server.listening) throw new Error("Dev server is not listening. Please call `devServer.instance.listen()` first.");
360
- if (!(process.stdin.isTTY && process.stdin instanceof node_tty.ReadStream)) {
361
- logger$2.warn("Interactive mode is not supported in non-interactive environments");
362
- return;
363
- }
364
- const debuggerOpener = new DebuggerOpener(devServer.config.root, devServer.instance.listeningOrigin);
365
- const defaultCommands = getDefaultCommands(devServer, debuggerOpener);
366
- const allCommands = [...defaultCommands, ...extraCommands];
367
- assertHasNoDuplicateCommands(defaultCommands, extraCommands);
368
- node_readline.default.emitKeypressEvents(process.stdin);
369
- process.stdin.setRawMode(true);
370
- devServer.on("device.connected", () => {
371
- debuggerOpener.autoOpen().catch(() => {
372
- logger$2.error("Failed to open debugger");
373
- });
374
- });
375
- process.stdin.on("keypress", (_, key) => {
376
- const { ctrl = false, shift = false } = key;
377
- const sequence = key.sequence?.toLowerCase();
378
- if (sequence == null || debuggerOpener.isPrompting()) return;
379
- if (ctrl && [CTRL_C, CTRL_D].includes(sequence)) {
380
- process.stdin.setRawMode(false);
381
- process.stdin.pause();
382
- process.emit("SIGINT");
383
- process.exit(0);
384
- }
385
- const targetCommand = allCommands.find((command) => command.key === sequence && (command.shift ?? false) === shift);
386
- if (targetCommand) targetCommand.handler.call({
387
- server: devServer,
388
- logger: logger$2
389
- });
390
- });
391
- console.log();
392
- allCommands.forEach((command, index) => {
393
- if (defaultCommands.length === index) console.log();
394
- const leadingLabel = command.shift ? "»" : "» Press";
395
- const shortcut = chalk.default.bold(shortcutLabel(command.key, command.shift));
396
- console.log(`${leadingLabel} ${shortcut} │ ${typeof command.description === "function" ? command.description() : command.description}`);
397
- });
398
- }
399
- function getDefaultCommands(devServer, debuggerOpener) {
400
- return [
401
- {
402
- key: "r",
403
- description: "Reload app",
404
- handler: (0, es_toolkit.throttle)(() => {
405
- logger$2.info("Reloading app...");
406
- devServer.message.broadcast("reload");
407
- }, BROADCAST_THROTTLE_DELAY)
408
- },
409
- {
410
- key: "j",
411
- description: "Open DevTools",
412
- handler: () => {
413
- debuggerOpener.open().catch(() => {
414
- logger$2.error("Failed to open debugger");
415
- });
416
- }
417
- },
418
- {
419
- key: "d",
420
- description: "Show developer menu",
421
- handler: (0, es_toolkit.throttle)(() => {
422
- logger$2.info("Showing developer menu...");
423
- devServer.message.broadcast("devMenu");
424
- }, BROADCAST_THROTTLE_DELAY)
425
- },
426
- {
427
- key: "d",
428
- shift: true,
429
- description: () => {
430
- const autoOpenEnabled = debuggerOpener.isAutoOpenEnabled();
431
- return `Toggle auto opening developer tools on startup (${chalk.default.bold(autoOpenEnabled ? "enabled" : "disabled")})`;
432
- },
433
- handler: () => {
434
- const newAutoOpenEnabled = !debuggerOpener.isAutoOpenEnabled();
435
- debuggerOpener.setAutoOpenEnabled(newAutoOpenEnabled);
436
- logger$2.info(`Auto opening developer tools: ${chalk.default.bold(newAutoOpenEnabled ? "enabled" : "disabled")}`);
437
- }
438
- }
439
- ];
440
- }
441
- function shortcutLabel(key, shift) {
442
- if (shift) return `shift+${key}`;
443
- return key;
444
- }
445
- function assertHasNoDuplicateCommands(defaultCommands, commands) {
446
- const defaultCommandKeys = defaultCommands.map(({ key, shift }) => shortcutLabel(key, shift));
447
- const duplicateKeys = commands.map(({ key, shift }) => shortcutLabel(key, shift)).filter((key) => defaultCommandKeys.includes(key));
448
- const invalidCommandKeys = commands.filter(({ key }) => key.length > 1).map(({ key, shift }) => shortcutLabel(key, shift));
449
- if (invalidCommandKeys.length > 0) throw new Error(`Invalid commands: ${invalidCommandKeys.join(", ")}`);
450
- if (duplicateKeys.length > 0) throw new Error(`Duplicate commands: ${duplicateKeys.join(", ")}`);
451
- }
452
- //#endregion
453
- //#region src/node/cli-utils.ts
454
- function createReactNativeCliCommand(commandDefinition) {
455
- return {
456
- name: commandDefinition.name,
457
- description: commandDefinition.description,
458
- options: commandDefinition.options?.map((option) => (0, es_toolkit.omit)(option, ["required"])),
459
- func: (_argv, cliConfig, args) => {
460
- Logo.printOnce();
461
- return commandDefinition.action.call({ platforms: Object.keys(cliConfig.platforms) }, args);
462
- }
463
- };
464
- }
465
- //#endregion
466
- //#region src/core/plugins/context.ts
467
- const pluginLogger = new Logger();
468
- function createPluginContext(name) {
469
- return {
470
- debug: (log) => {
471
- printPluginLog("debug", log, name);
472
- },
473
- info: (log) => {
474
- printPluginLog("info", log, name);
475
- },
476
- warn: (log) => {
477
- printPluginLog("warn", log, name);
478
- }
479
- };
480
- }
481
- function printPluginLog(level, log, pluginName = "unknown") {
482
- const pluginLabel = chalk.default.magenta(`plugin:${pluginName}`);
483
- if (typeof log === "string") pluginLogger[level](pluginLabel, log);
484
- else pluginLogger[level](pluginLabel, log.stack ?? log.message);
485
- }
486
- //#endregion
487
- //#region src/server/logger.ts
488
- const logger$1 = new Logger("dev-server");
489
- var DevServerLogger = class {
490
- level = "trace";
491
- trace(...args) {
492
- logger$1.trace(...args);
493
- }
494
- debug(...args) {
495
- logger$1.debug(...args);
496
- }
497
- info(...args) {
498
- logger$1.info(...args);
499
- }
500
- warn(...args) {
501
- logger$1.warn(...args);
502
- }
503
- error(...args) {
504
- logger$1.error(...args);
505
- }
506
- silent(...args) {
507
- logger$1.trace(chalk.default.gray("(silent)"), ...args);
508
- }
509
- fatal(...args) {
510
- logger$1.error(chalk.default.magenta("(fatal)"), ...args);
511
- }
512
- child(_bindings) {
513
- return this;
514
- }
515
- };
516
- //#endregion
517
- //#region src/utils/dev-server.ts
518
- async function assertDevServerStatus(options) {
519
- const { devServerUrl, projectRoot, port } = options;
520
- const status = await getDevServerStatus(devServerUrl, projectRoot);
521
- let shouldExit = false;
522
- switch (status) {
523
- case DevServerStatus.MATCHED_SERVER_RUNNING:
524
- logger$1.warn(`A dev server is already running for this project on port ${port}. Exiting.`);
525
- shouldExit = true;
526
- break;
527
- case DevServerStatus.PORT_TAKEN:
528
- logger$1.error(`Another process is running on port ${port}. Please terminate this process and try again, or use another port with "--port".`);
529
- shouldExit = true;
530
- break;
531
- }
532
- if (shouldExit) process.exit(1);
533
- }
534
- var DevServerStatus = /* @__PURE__ */ function(DevServerStatus) {
535
- DevServerStatus[DevServerStatus["NOT_RUNNING"] = 0] = "NOT_RUNNING";
536
- DevServerStatus[DevServerStatus["MATCHED_SERVER_RUNNING"] = 1] = "MATCHED_SERVER_RUNNING";
537
- DevServerStatus[DevServerStatus["PORT_TAKEN"] = 2] = "PORT_TAKEN";
538
- DevServerStatus[DevServerStatus["UNKNOWN"] = 3] = "UNKNOWN";
539
- return DevServerStatus;
540
- }(DevServerStatus || {});
541
- async function getDevServerStatus(devServerUrl, projectRoot) {
542
- const { hostname, port } = new URL(devServerUrl);
543
- try {
544
- if (!await isPortOccupied(hostname, port)) return DevServerStatus.NOT_RUNNING;
545
- const statusResponse = await fetch(`${devServerUrl}/status`);
546
- return await statusResponse.text() === "packager-status:running" && statusResponse.headers.get("X-React-Native-Project-Root") === projectRoot ? DevServerStatus.MATCHED_SERVER_RUNNING : DevServerStatus.PORT_TAKEN;
547
- } catch {
548
- return DevServerStatus.UNKNOWN;
549
- }
550
- }
551
- async function isPortOccupied(host, port) {
552
- let result = false;
553
- const server = node_http.default.createServer();
554
- return new Promise((resolve, reject) => {
555
- server.once("error", (error) => {
556
- server.close();
557
- if (error.code === "EADDRINUSE") result = true;
558
- else reject(error);
559
- });
560
- server.once("listening", () => {
561
- result = false;
562
- server.close();
563
- });
564
- server.once("close", () => resolve(result));
565
- server.listen({
566
- host,
567
- port
568
- });
569
- });
570
- }
571
- //#endregion
572
- //#region src/utils/build-options.ts
573
- const DEFAULT_BUILD_OPTIONS = {
574
- cache: true,
575
- minify: false
576
- };
577
- function resolveBuildOptions(config, buildOptions) {
578
- if (buildOptions.outfile) buildOptions.outfile = node_path.default.resolve(config.root, buildOptions.outfile);
579
- if ((buildOptions.sourcemap === true || buildOptions.sourcemap === "hidden") && buildOptions.sourcemapOutfile) buildOptions.sourcemapOutfile = node_path.default.resolve(config.root, buildOptions.sourcemapOutfile);
580
- return (0, es_toolkit.merge)(DEFAULT_BUILD_OPTIONS, {
581
- ...buildOptions,
582
- dev: buildOptions.dev ?? config.mode === "development"
583
- });
584
- }
585
- //#endregion
586
- //#region src/constants.ts
587
- const ROLLIPOP_VERSION = globalThis.__ROLLIPOP_VERSION__;
588
- const GLOBAL_IDENTIFIER = "global";
589
- /**
590
- * @see {@link https://github.com/facebook/metro/blob/0.81.x/docs/Configuration.md#resolvermainfields}
591
- */
592
- const DEFAULT_RESOLVER_MAIN_FIELDS = [
593
- "react-native",
594
- "browser",
595
- "main"
596
- ];
597
- const DEFAULT_RESOLVER_ALIAS_FIELDS = [["react-native"], ["browser"]];
598
- const DEFAULT_RESOLVER_CONDITION_NAMES = ["react-native"];
599
- /**
600
- * Unlike the Metro bundler configuration, this prioritizes resolving TypeScript and ESM first.
601
- *
602
- * @see {@link https://github.com/facebook/metro/blob/0.81.x/packages/metro-config/src/defaults/defaults.js}
603
- * @see {@link https://github.com/facebook/metro/blob/0.81.x/packages/metro-file-map/src/workerExclusionList.js}
604
- */
605
- const DEFAULT_SOURCE_EXTENSIONS = [
606
- "ts",
607
- "tsx",
608
- "js",
609
- "jsx",
610
- "mjs",
611
- "cjs",
612
- "json"
613
- ];
614
- const DEFAULT_IMAGE_EXTENSIONS = [
615
- "bmp",
616
- "gif",
617
- "jpg",
618
- "jpeg",
619
- "png",
620
- "psd",
621
- "svg",
622
- "webp"
623
- ];
624
- const IMAGE_EXTENSIONS = [
625
- ...DEFAULT_IMAGE_EXTENSIONS,
626
- "tiff",
627
- "ktx"
628
- ];
629
- const DEFAULT_ASSET_EXTENSIONS = [
630
- ...DEFAULT_IMAGE_EXTENSIONS,
631
- "xml",
632
- "m4v",
633
- "mov",
634
- "mp4",
635
- "mpeg",
636
- "mpg",
637
- "webm",
638
- "aac",
639
- "aiff",
640
- "caf",
641
- "m4a",
642
- "mp3",
643
- "wav",
644
- "html",
645
- "pdf",
646
- "yaml",
647
- "yml",
648
- "otf",
649
- "ttf",
650
- "zip"
651
- ];
652
- const DEFAULT_ASSET_REGISTRY_PATH = "react-native/Libraries/Image/AssetRegistry.js";
653
- const DEFAULT_HMR_CLIENT_PATH = "react-native/Libraries/Utilities/HMRClient.js";
654
- const DEFAULT_REACT_NATIVE_GLOBAL_IDENTIFIERS = [
655
- GLOBAL_IDENTIFIER,
656
- "Promise",
657
- "regeneratorRuntime",
658
- "XMLHttpRequest",
659
- "FormData",
660
- "fetch",
661
- "Headers",
662
- "Request",
663
- "Response",
664
- "WebSocket",
665
- "Blob",
666
- "File",
667
- "FileReader",
668
- "URL",
669
- "URLSearchParams",
670
- "AbortController",
671
- "AbortSignal",
672
- "queueMicrotask",
673
- "setImmediate",
674
- "clearImmediate",
675
- "requestIdleCallback",
676
- "cancelIdleCallback",
677
- "setTimeout",
678
- "clearTimeout",
679
- "setInterval",
680
- "clearInterval",
681
- "requestAnimationFrame",
682
- "cancelAnimationFrame",
683
- "DOMRect",
684
- "DOMRectReadOnly",
685
- "DOMRectList",
686
- "HTMLCollection",
687
- "NodeList",
688
- "Node",
689
- "Document",
690
- "CharacterData",
691
- "Text",
692
- "Element",
693
- "HTMLElement",
694
- "IntersectionObserver",
695
- "MutationObserver",
696
- "MutationRecord",
697
- "EventCounts",
698
- "Performance",
699
- "PerformanceEntry",
700
- "PerformanceEventTiming",
701
- "PerformanceLongTaskTiming",
702
- "PerformanceMark",
703
- "PerformanceMeasure",
704
- "PerformanceObserver",
705
- "PerformanceObserverEntryList",
706
- "PerformanceResourceTiming",
707
- "TaskAttributionTiming"
708
- ];
709
- const DEFAULT_ENV_PREFIX = "ROLLIPOP_";
710
- const DEFAULT_ENV_FILE = ".env";
711
- const DEFAULT_RUNTIME_TARGET = "hermes-v1";
712
- //#endregion
713
- //#region src/utils/hash.ts
714
- function md5(data) {
715
- return node_crypto.default.createHash("md5").update(data).digest("hex");
716
- }
717
- //#endregion
718
- //#region src/utils/serialize.ts
719
- function serialize(value) {
720
- return JSON.stringify(value, (_, value) => {
721
- if (typeof value === "function") return value.toString();
722
- if (value instanceof RegExp) return value.toString();
723
- return value;
724
- });
725
- }
726
- //#endregion
727
- //#region src/utils/id.ts
728
- function createId(config, buildOptions) {
729
- return md5(serialize([
730
- ROLLIPOP_VERSION,
731
- filterTransformAffectedOptions(buildOptions),
732
- filterTransformAffectedConfig(config)
733
- ]));
734
- }
735
- function filterTransformAffectedOptions(buildOptions) {
736
- return (0, es_toolkit.pick)(buildOptions, ["platform", "dev"]);
737
- }
738
- function filterTransformAffectedConfig(config) {
739
- const { transformer, serializer, reactNative, devMode, plugins = [] } = config;
740
- return [
741
- transformer,
742
- serializer.polyfills,
743
- serializer.prelude,
744
- reactNative.assetRegistryPath,
745
- devMode,
746
- plugins.map((plugin, index) => `${plugin.name}#${index}`)
747
- ];
748
- }
749
- //#endregion
750
- //#region src/core/fs/storage.ts
751
- const DEFAULT_DATA = { build: {} };
752
- var FileStorage = class FileStorage {
753
- static instance = null;
754
- dataFilePath;
755
- data;
756
- static getInstance(basePath) {
757
- if (FileStorage.instance == null) FileStorage.instance = new FileStorage(basePath);
758
- return FileStorage.instance;
759
- }
760
- constructor(basePath) {
761
- this.basePath = basePath;
762
- this.dataFilePath = node_path.default.join(getSharedDataPath(basePath), "rollipop.json");
763
- if (node_fs.default.existsSync(this.dataFilePath)) this.data = JSON.parse(node_fs.default.readFileSync(this.dataFilePath, "utf-8"));
764
- else this.data = DEFAULT_DATA;
765
- }
766
- get() {
767
- return this.data;
768
- }
769
- set(data) {
770
- this.data = (0, es_toolkit.merge)(this.data, data);
771
- node_fs.default.writeFileSync(this.dataFilePath, JSON.stringify(this.data, null, 2));
772
- }
773
- };
774
- //#endregion
775
- //#region src/utils/string.ts
776
- function indent(text, indent, space = " ") {
777
- return text.replace(/^/gm, space.repeat(indent));
778
- }
779
- //#endregion
780
- //#region src/common/code.ts
781
- function asLiteral(value) {
782
- return JSON.stringify(value);
783
- }
784
- function nodeEnvironment(dev) {
785
- return dev ? "development" : "production";
786
- }
787
- function iife(body, path = "<unknown>") {
788
- const bodyPlaceholder = "__BODY__";
789
- return dedent.default`
790
- // ${path}
791
- (function (global) {
792
- ${bodyPlaceholder}
793
- })(${GLOBAL_IDENTIFIER});
794
- `.replace(bodyPlaceholder, indent(body, 1));
795
- }
796
- //#endregion
797
- //#region src/config/compose-override.ts
798
- async function applyOverrideRolldownOptions(override, rolldownOptions) {
799
- if (typeof override === "function") return await override(rolldownOptions);
800
- return {
801
- input: (0, es_toolkit.merge)(rolldownOptions.input ?? {}, override.input ?? {}),
802
- output: (0, es_toolkit.merge)(rolldownOptions.output ?? {}, override.output ?? {})
803
- };
804
- }
805
- function composeOverrideRolldownOptions(target, source) {
806
- if (source == null) return target;
807
- if (target == null) return source;
808
- return async (rolldownOptions) => {
809
- return await applyOverrideRolldownOptions(source, await applyOverrideRolldownOptions(target, rolldownOptions));
810
- };
811
- }
812
- //#endregion
813
- //#region src/internal/react-native.ts
814
- function getInitializeCorePath(basePath) {
815
- return require.resolve("react-native/Libraries/Core/InitializeCore", { paths: [basePath] });
816
- }
817
- function getPolyfillScriptPaths(reactNativePath) {
818
- const scriptPath = node_path.default.join(reactNativePath, "rn-get-polyfills");
819
- return require(scriptPath)();
820
- }
821
- function getGlobalVariables(dev, buildType) {
822
- const isDevServerMode = dev && buildType === "serve";
823
- return [
824
- `var __BUNDLE_START_TIME__=globalThis.nativePerformanceNow?nativePerformanceNow():Date.now();`,
825
- `var __DEV__=${dev};`,
826
- `var ${GLOBAL_IDENTIFIER}=typeof globalThis!=='undefined'?globalThis:typeof global !== 'undefined'?global:typeof window!=='undefined'?window:this;`,
827
- `var process=globalThis.process||{};process.env=process.env||{};process.env.NODE_ENV=process.env.NODE_ENV||"${dev ? "development" : "production"}";`,
828
- isDevServerMode ? `var $RefreshReg$ = () => {};` : null,
829
- isDevServerMode ? `var $RefreshSig$ = () => (v) => v;` : null
830
- ].filter(es_toolkit.isNotNil);
831
- }
832
- //#endregion
833
- //#region src/utils/config.ts
834
- function bindReporter(config, eventSource, onEvent) {
835
- const originalReporter = config.reporter;
836
- config.reporter = { update(event) {
837
- switch (event.type) {
838
- case "bundle_build_started":
839
- eventSource.emit("buildStart");
840
- break;
841
- case "bundle_build_done":
842
- eventSource.emit("buildDone");
843
- break;
844
- case "bundle_build_failed":
845
- eventSource.emit("buildFailed", event.error);
846
- break;
847
- case "transform":
848
- eventSource.emit("transform", event.id, event.totalModules, event.transformedModules);
849
- break;
850
- case "watch_change":
851
- eventSource.emit("watchChange", event.id);
852
- break;
853
- }
854
- originalReporter?.update(event);
855
- onEvent?.(event);
856
- } };
857
- return config;
858
- }
859
- function resolveHmrConfig(config) {
860
- if (config.mode !== "development") return null;
861
- const defaultRuntimeImplements = getDefaultRuntimeImplements();
862
- if (typeof config.devMode.hmr === "boolean") return config.devMode.hmr ? defaultRuntimeImplements : null;
863
- const { runtimeImplement = defaultRuntimeImplements.runtimeImplement, clientImplement = defaultRuntimeImplements.clientImplement } = config.devMode.hmr;
864
- return {
865
- runtimeImplement,
866
- clientImplement
867
- };
868
- }
869
- getDefaultRuntimeImplements.cache = null;
870
- function getDefaultRuntimeImplements() {
871
- if (getDefaultRuntimeImplements.cache == null) getDefaultRuntimeImplements.cache = {
872
- runtimeImplement: node_fs.default.readFileSync(require.resolve("rollipop/hmr-runtime"), "utf-8"),
873
- clientImplement: node_fs.default.readFileSync(require.resolve("rollipop/hmr-client"), "utf-8")
874
- };
875
- return getDefaultRuntimeImplements.cache;
876
- }
877
- //#endregion
878
- //#region src/utils/env.ts
879
- function defineEnvFromObject(env) {
880
- return Object.fromEntries(Object.entries(env).map(([key, value]) => [`import.meta.env.${key}`, asLiteral(value)]));
881
- }
882
- //#endregion
883
- //#region src/utils/node-resolve.ts
884
- function resolveFrom(basePath, lookupPath) {
885
- if (node_path.default.isAbsolute(lookupPath)) return lookupPath;
886
- return require.resolve(lookupPath, { paths: [basePath] });
887
- }
888
- function resolvePackagePath(basePath, packageName) {
889
- let packagePath = null;
890
- try {
891
- packagePath = resolvePackagePathWithNodeRequire(basePath, packageName, "package.json");
892
- if (packagePath) return packagePath;
893
- } catch {}
894
- try {
895
- packagePath = resolvePackagePathWithNodeRequire(basePath, packageName);
896
- if (packagePath) return packagePath;
897
- } catch {}
898
- throw new Error(`Failed to resolve package path for '${packageName}'`);
899
- }
900
- function resolvePackageJson(basePath, packageName) {
901
- try {
902
- const packagePath = resolvePackagePath(basePath, packageName);
903
- const packageJsonPath = node_path.default.join(packagePath, "package.json");
904
- const rawPackageJson = node_fs.default.readFileSync(packageJsonPath, "utf-8");
905
- return JSON.parse(rawPackageJson);
906
- } catch {
907
- return null;
908
- }
909
- }
910
- function resolvePackagePathWithNodeRequire(basePath, packageName, subpath) {
911
- const resolvedPath = require.resolve(subpath ? `${packageName}/${subpath}` : packageName, { paths: [basePath] });
912
- const root = node_path.default.parse(resolvedPath).root;
913
- let currentPath = node_path.default.dirname(resolvedPath);
914
- while (currentPath !== root) {
915
- if (node_fs.default.existsSync(node_path.default.join(currentPath, "package.json"))) return currentPath;
916
- currentPath = node_path.default.dirname(currentPath);
917
- }
918
- return null;
919
- }
920
- //#endregion
921
- //#region src/utils/terminal.ts
922
- /**
923
- * Based on https://github.com/sindresorhus/log-update/blob/master/index.js
924
- * Based on https://github.com/unjs/webpackbar
925
- */
926
- function eraseLines(count) {
927
- let clear = "";
928
- for (let i = 0; i < count; i++) clear += `\u001B[2K` + (i < count - 1 ? `\u001B[1A` : "");
929
- if (count) clear += `\u001B[G`;
930
- return clear;
931
- }
932
- function ellipsisLeft(value, maxLength) {
933
- if (value.length <= maxLength - 3) return value;
934
- return `...${value.slice(value.length - maxLength - 1)}`;
935
- }
936
- const originalWrite = Symbol("original-write");
937
- var StreamManager = class {
938
- prevLineCount;
939
- listening;
940
- extraLines;
941
- _streams;
942
- constructor() {
943
- this.prevLineCount = 0;
944
- this.listening = false;
945
- this.extraLines = "";
946
- this._onData = this._onData.bind(this);
947
- this._streams = [process.stdout, process.stderr];
948
- }
949
- render(lines) {
950
- this.listen();
951
- const wrappedLines = (0, wrap_ansi.default)(lines, this.columns, {
952
- trim: false,
953
- hard: true,
954
- wordWrap: false
955
- });
956
- const data = eraseLines(this.prevLineCount) + wrappedLines + "\n" + this.extraLines;
957
- this.write(data);
958
- this.prevLineCount = data.split("\n").length;
959
- }
960
- get columns() {
961
- return (process.stderr.columns || 80) - 2;
962
- }
963
- write(data) {
964
- const stream = process.stderr;
965
- if (stream.write[originalWrite]) stream.write[originalWrite].call(stream, data, "utf8");
966
- else stream.write(data, "utf8");
967
- }
968
- clear() {
969
- this.done();
970
- this.write(eraseLines(this.prevLineCount));
971
- }
972
- done() {
973
- this.stopListen();
974
- this.prevLineCount = 0;
975
- this.extraLines = "";
976
- }
977
- _onData(data) {
978
- const lines = String(data).split("\n").length - 1;
979
- if (lines > 0) {
980
- this.prevLineCount += lines;
981
- this.extraLines += data;
982
- }
983
- }
984
- listen() {
985
- if (this.listening) return;
986
- for (const stream of this._streams) {
987
- if (stream.write[originalWrite]) continue;
988
- const write = (data, ...args) => {
989
- if (!stream.write[originalWrite]) return stream.write(data, ...args);
990
- this._onData(data);
991
- return stream.write[originalWrite].call(stream, data, ...args);
992
- };
993
- write[originalWrite] = stream.write;
994
- stream.write = write;
995
- }
996
- this.listening = true;
997
- }
998
- stopListen() {
999
- for (const stream of this._streams) if (stream.write[originalWrite]) stream.write = stream.write[originalWrite];
1000
- this.listening = false;
1001
- }
1002
- };
1003
- //#endregion
1004
- //#region src/common/progress-bar.ts
1005
- const BAR_LENGTH = 25;
1006
- const BLOCK_CHAR = "█";
1007
- const idleRenderer = { render(_state, context) {
1008
- return ` ${chalk.default.gray("Waiting...")} ${chalk.default.gray(context.label)}\n`;
1009
- } };
1010
- const runningRenderer = { render(state, context) {
1011
- const { label, current, total, columns } = context;
1012
- const unknownTotal = total === 0;
1013
- const progress = unknownTotal ? 0 : current / total * 100;
1014
- const width = unknownTotal ? 0 : progress * (BAR_LENGTH / 100);
1015
- const bg = chalk.default.white(BLOCK_CHAR);
1016
- const fg = chalk.default.cyan(BLOCK_CHAR);
1017
- const bar = (0, es_toolkit.range)(BAR_LENGTH).map((n) => n < width ? fg : bg).join("");
1018
- const progressLabel = unknownTotal ? chalk.default.gray("(calculating...)") : `(${progress.toFixed(2)}%)`;
1019
- const moduleCountLabel = unknownTotal ? `${current} modules` : `${current}/${total} modules`;
1020
- return `${[
1021
- chalk.default.cyan("●"),
1022
- bar,
1023
- progressLabel,
1024
- chalk.default.gray(moduleCountLabel),
1025
- chalk.default.gray(label)
1026
- ].join(" ")}\n${state.moduleId ? " " + chalk.default.grey(ellipsisLeft(state.moduleId, columns - 10)) : ""}`;
1027
- } };
1028
- const completedRenderer = { render(state, context) {
1029
- if (state.hasErrors) return `${chalk.default.red("✘")} Build failed ${chalk.default.gray(context.label)}`;
1030
- else {
1031
- const icon = chalk.default.green("✔");
1032
- const durationInSeconds = (state.duration / 1e3).toFixed(2);
1033
- return `${`${icon} Build completed ${chalk.default.gray(context.label)}`}\n${chalk.default.grey(` Built in ${durationInSeconds}s (${context.current}/${context.total} modules)`)}`;
1034
- }
1035
- } };
1036
- var ProgressBarRenderer = class {
1037
- renderers = {
1038
- idle: idleRenderer,
1039
- running: runningRenderer,
1040
- completed: completedRenderer
1041
- };
1042
- render(state, context) {
1043
- return this.renderers[state.type].render(state, context);
1044
- }
1045
- };
1046
- var ProgressBar = class {
1047
- columns = (process.stderr.columns || 80) - 2;
1048
- renderer;
1049
- label;
1050
- state = { type: "idle" };
1051
- current = 0;
1052
- total;
1053
- stale = false;
1054
- constructor(options) {
1055
- this.total = options.total;
1056
- this.label = options.label;
1057
- this.renderer = options.renderer ?? new ProgressBarRenderer();
1058
- }
1059
- get done() {
1060
- return this.state.type === "completed";
1061
- }
1062
- setCurrent(current) {
1063
- this.current = current;
1064
- this.stale = true;
1065
- return this;
1066
- }
1067
- setTotal(total) {
1068
- this.total = total;
1069
- this.stale = true;
1070
- return this;
1071
- }
1072
- start() {
1073
- this.state = { type: "running" };
1074
- this.stale = true;
1075
- return this;
1076
- }
1077
- setModuleId(moduleId) {
1078
- if (this.state.type !== "running") return this;
1079
- this.state = {
1080
- type: "running",
1081
- moduleId
1082
- };
1083
- this.stale = true;
1084
- return this;
1085
- }
1086
- complete(duration, hasErrors = false) {
1087
- this.state = {
1088
- type: "completed",
1089
- duration,
1090
- hasErrors
1091
- };
1092
- this.stale = true;
1093
- return this;
1094
- }
1095
- render() {
1096
- this.stale = false;
1097
- const context = {
1098
- label: this.label,
1099
- current: this.current,
1100
- total: this.total,
1101
- columns: this.columns
1102
- };
1103
- return this.renderer.render(this.state, context);
1104
- }
1105
- };
1106
- var ProgressBarRenderManager = class ProgressBarRenderManager {
1107
- static instance = null;
1108
- streamManager = new StreamManager();
1109
- progressBars = /* @__PURE__ */ new Map();
1110
- throttledRender;
1111
- static getInstance() {
1112
- if (!ProgressBarRenderManager.instance) ProgressBarRenderManager.instance = new ProgressBarRenderManager();
1113
- return ProgressBarRenderManager.instance;
1114
- }
1115
- constructor() {
1116
- this.throttledRender = (0, es_toolkit.throttle)(this._render.bind(this), 50);
1117
- }
1118
- _render() {
1119
- const renderedLines = Array.from(this.progressBars.values().filter((progressBar) => progressBar.stale).map((progressBar) => progressBar.render()));
1120
- if (renderedLines.length > 0) this.streamManager.render(renderedLines.join("\n\n"));
1121
- }
1122
- register(key, options) {
1123
- const progressBar = this.progressBars.get(key);
1124
- if (progressBar == null) {
1125
- const newProgressBar = new ProgressBar(options);
1126
- this.progressBars.set(key, newProgressBar);
1127
- return newProgressBar;
1128
- }
1129
- return progressBar;
1130
- }
1131
- start() {
1132
- console.log();
1133
- this.streamManager.listen();
1134
- this._render();
1135
- }
1136
- render() {
1137
- this.throttledRender();
1138
- }
1139
- release() {
1140
- if (this.progressBars.values().every((progressBar) => progressBar.done)) {
1141
- this._render();
1142
- this.streamManager.done();
1143
- console.log();
1144
- }
1145
- }
1146
- clear() {
1147
- this.streamManager.clear();
1148
- }
1149
- };
1150
- //#endregion
1151
- //#region src/logger.ts
1152
- const logger = new Logger("bundler");
1153
- //#endregion
1154
- //#region src/utils/reporters.ts
1155
- function mergeReporters(reporters) {
1156
- return { update(event) {
1157
- reporters.forEach((reporter) => reporter.update(event));
1158
- } };
1159
- }
1160
- var ClientLogReporter = class {
1161
- logger = new Logger("app");
1162
- update(event) {
1163
- if (event.type === "client_log") {
1164
- if (event.level === "group" || event.level === "groupCollapsed") {
1165
- this.logger.info(...event.data);
1166
- return;
1167
- } else if (event.level === "groupEnd") return;
1168
- this.logger[event.level](...event.data);
1169
- }
1170
- }
1171
- };
1172
- var ProgressFlags = /* @__PURE__ */ function(ProgressFlags) {
1173
- ProgressFlags[ProgressFlags["NONE"] = 0] = "NONE";
1174
- ProgressFlags[ProgressFlags["BUILD_IN_PROGRESS"] = 1] = "BUILD_IN_PROGRESS";
1175
- ProgressFlags[ProgressFlags["FILE_CHANGED"] = 2] = "FILE_CHANGED";
1176
- return ProgressFlags;
1177
- }(ProgressFlags || {});
1178
- var ProgressBarStatusReporter = class {
1179
- renderManager = ProgressBarRenderManager.getInstance();
1180
- progressBar;
1181
- flags = ProgressFlags.NONE;
1182
- constructor(id, label, initialTotalModules) {
1183
- this.progressBar = this.renderManager.register(id, {
1184
- label,
1185
- total: initialTotalModules
1186
- });
1187
- }
1188
- renderProgress(id, totalModules, transformedModules) {
1189
- if (totalModules != null) this.progressBar.setTotal(totalModules);
1190
- this.progressBar.setCurrent(transformedModules).setModuleId(id);
1191
- this.renderManager.render();
1192
- }
1193
- update(event) {
1194
- switch (event.type) {
1195
- case "bundle_build_started":
1196
- this.flags |= ProgressFlags.BUILD_IN_PROGRESS;
1197
- this.progressBar.start();
1198
- this.renderManager.start();
1199
- break;
1200
- case "bundle_build_failed":
1201
- this.flags = ProgressFlags.NONE;
1202
- this.progressBar.complete(0, true);
1203
- this.renderManager.release();
1204
- break;
1205
- case "bundle_build_done":
1206
- this.flags = ProgressFlags.NONE;
1207
- this.progressBar.setTotal(event.totalModules).complete(event.duration, false);
1208
- this.renderManager.release();
1209
- break;
1210
- case "transform":
1211
- const { id, totalModules, transformedModules } = event;
1212
- if (this.flags & ProgressFlags.FILE_CHANGED) {
1213
- logger.debug("Transformed changed file", { id });
1214
- return;
1215
- }
1216
- this.renderProgress(id, totalModules, transformedModules);
1217
- break;
1218
- case "watch_change":
1219
- this.flags |= ProgressFlags.FILE_CHANGED;
1220
- break;
1221
- }
1222
- }
1223
- };
1224
- var CompatStatusReporter = class {
1225
- update(event) {
1226
- switch (event.type) {
1227
- case "bundle_build_started":
1228
- logger.info("Build started...");
1229
- break;
1230
- case "bundle_build_failed":
1231
- logger.error(`Build failed`);
1232
- break;
1233
- case "bundle_build_done":
1234
- const { duration, totalModules } = event;
1235
- const time = chalk.default.blue(`${duration.toFixed(2)}ms`);
1236
- const modules = chalk.default.blue(`(${totalModules} modules)`);
1237
- logger.info(`Build completed in ${time} ${modules}`);
1238
- break;
1239
- }
1240
- }
1241
- };
1242
- //#endregion
1243
- //#region src/utils/runtime-target.ts
1244
- function resolveRuntimeTarget(target) {
1245
- switch (target) {
1246
- case "hermes": return "Hermes";
1247
- default: return "HermesV1";
1248
- }
1249
- }
1250
- //#endregion
1251
- //#region src/utils/server.ts
1252
- function getBaseUrl(host, port, https) {
1253
- return `${https ? "https" : "http"}://${host}:${port}`;
1254
- }
1255
- //#endregion
1256
- //#region src/utils/storage.ts
1257
- function getBuildTotalModules(storage, id) {
1258
- return storage.get().build[id]?.totalModules ?? 0;
1259
- }
1260
- //#endregion
1261
- //#region src/core/env.ts
1262
- function loadEnv(options) {
1263
- const { envDir, envPrefix, envFile, mode } = options;
1264
- (0, es_toolkit.invariant)(envPrefix.length > 0, "`envPrefix` is required");
1265
- (0, es_toolkit.invariant)(envFile.length > 0, "`envFile` is required");
1266
- const env = {};
1267
- const envFilesToLoad = [
1268
- envFile,
1269
- `${envFile}.local`,
1270
- mode ? `${envFile}.${mode}` : null,
1271
- mode ? `${envFile}.${mode}.local` : null
1272
- ].filter(es_toolkit.isNotNil);
1273
- for (const file of envFilesToLoad) {
1274
- const envPath = node_path.default.resolve(envDir, file);
1275
- if (!node_fs.default.existsSync(envPath)) continue;
1276
- logger.trace(`Loading environment variables from ${envPath}`);
1277
- const parsed = dotenv.default.parse(node_fs.default.readFileSync(envPath, "utf-8"));
1278
- const expanded = dotenv_expand.default.expand({
1279
- parsed,
1280
- processEnv: {}
1281
- });
1282
- if (expanded.parsed) Object.entries(expanded.parsed).forEach(([key, value]) => {
1283
- if (key.startsWith(envPrefix)) env[key] = key in process.env ? process.env[key] : value;
1284
- });
1285
- }
1286
- logger.trace("Loaded environment variables:", env);
1287
- return env;
1288
- }
1289
- //#endregion
1290
- //#region src/common/transformer.ts
1291
- async function stripFlowTypes(id, code) {
1292
- return await (0, fast_flow_transform.default)({
1293
- filename: id,
1294
- source: code,
1295
- sourcemap: true,
1296
- dialect: "flow",
1297
- format: "pretty"
1298
- });
1299
- }
1300
- //#endregion
1301
- //#region src/core/assets.ts
1302
- /**
1303
- * **NOTE**: Type definitions are ported from `metro` implementation.
1304
- *
1305
- * @see https://github.com/facebook/metro/blob/0.81.x/packages/metro/src/Assets.js
1306
- */
1307
- const SCALE_PATTERN = "@(\\d+\\.?\\d*)x";
1308
- const IMAGE_ASSET_TYPES = new Set(IMAGE_EXTENSIONS);
1309
- /**
1310
- * key: platform,
1311
- * value: allowed scales
1312
- *
1313
- * @see https://github.com/facebook/react-native/blob/0.83-stable/packages/community-cli-plugin/src/commands/bundle/filterPlatformAssetScales.js#L11
1314
- */
1315
- const ALLOW_SCALES = { ios: [
1316
- 1,
1317
- 2,
1318
- 3
1319
- ] };
1320
- /**
1321
- * @see https://developer.android.com/training/multiscreen/screendensities#TaskProvideAltBmp
1322
- */
1323
- const ANDROID_ASSET_QUALIFIER = {
1324
- .75: "ldpi",
1325
- 1: "mdpi",
1326
- 1.5: "hdpi",
1327
- 2: "xhdpi",
1328
- 3: "xxhdpi",
1329
- 4: "xxxhdpi"
1330
- };
1331
- async function resolveScaledAssets(options) {
1332
- const { projectRoot, assetPath, platform, preferNativePlatform } = options;
1333
- const context = {
1334
- platform,
1335
- preferNativePlatform
1336
- };
1337
- const extension = node_path.default.extname(assetPath);
1338
- const type = extension.substring(1);
1339
- const relativePath = node_path.default.relative(projectRoot, assetPath);
1340
- const dirname = node_path.default.dirname(assetPath);
1341
- const files = node_fs.default.readdirSync(dirname);
1342
- const stripedBasename = stripSuffix(assetPath, context);
1343
- const suffixPattern = platformSuffixPattern(context);
1344
- const assetRegExp = new RegExp(`${stripedBasename}(${SCALE_PATTERN})?(?:${suffixPattern})?${extension}$`);
1345
- const scaledAssets = {};
1346
- for (const file of files.sort((a, b) => getAssetPriority(b, context) - getAssetPriority(a, context))) {
1347
- const match = assetRegExp.exec(file);
1348
- if (match) {
1349
- const [, , scale = "1"] = match;
1350
- if (scaledAssets[scale]) continue;
1351
- scaledAssets[scale] = file;
1352
- }
1353
- }
1354
- if (!(Object.keys(scaledAssets).length && scaledAssets[1])) throw new Error(`cannot resolve base asset of ${assetPath}`);
1355
- const imageData = node_fs.default.readFileSync(assetPath);
1356
- const dimensions = IMAGE_ASSET_TYPES.has(type) ? (0, image_size.imageSize)(imageData) : void 0;
1357
- const filteredScaledAssets = Object.entries(scaledAssets).map(([scale, file]) => ({
1358
- scale: parseFloat(scale),
1359
- file
1360
- })).filter(({ scale }) => ALLOW_SCALES[platform]?.includes(scale) ?? true).reduce((acc, { scale, file }) => {
1361
- acc.files.push(file);
1362
- acc.scales.push(scale);
1363
- return acc;
1364
- }, {
1365
- scales: [],
1366
- files: []
1367
- });
1368
- return {
1369
- __packager_asset: true,
1370
- id: assetPath,
1371
- name: stripedBasename.replace(extension, ""),
1372
- type,
1373
- width: dimensions?.width,
1374
- height: dimensions?.height,
1375
- files: filteredScaledAssets.files,
1376
- scales: filteredScaledAssets.scales,
1377
- fileSystemLocation: node_path.default.dirname(assetPath),
1378
- httpServerLocation: node_path.default.join(DEV_SERVER_ASSET_PATH, node_path.default.dirname(relativePath)),
1379
- hash: md5(imageData)
1380
- };
1381
- }
1382
- function platformSuffixPattern(context) {
1383
- return [context.platform, context.preferNativePlatform ? "native" : null].filter(es_toolkit.isNotNil).map((platform) => `.${platform}`).join("|");
1384
- }
1385
- function stripSuffix(assetPath, context) {
1386
- const basename = node_path.default.basename(assetPath);
1387
- const extension = node_path.default.extname(assetPath);
1388
- const suffixPattern = platformSuffixPattern(context);
1389
- return basename.replace(new RegExp(`(${SCALE_PATTERN})?(?:${suffixPattern})?${extension}$`), "");
1390
- }
1391
- function getAssetPriority(assetPath, context) {
1392
- const suffixPattern = platformSuffixPattern(context);
1393
- if (new RegExp(`${SCALE_PATTERN}(?:${suffixPattern})`).test(assetPath)) return 3;
1394
- else if (new RegExp(`(?:${suffixPattern})`).test(assetPath)) return 2;
1395
- else if (new RegExp(`${SCALE_PATTERN}`).test(assetPath)) return 1;
1396
- return 0;
1397
- }
1398
- function addSuffix(assetPath, context, options) {
1399
- const extension = node_path.default.extname(assetPath);
1400
- return stripSuffix(assetPath, context).concat(options?.scale ? `@${options.scale}x` : "").concat(options?.platform ? `.${options.platform}${extension}` : extension);
1401
- }
1402
- /**
1403
- * add suffix to asset path
1404
- *
1405
- * ```js
1406
- * // assetPath input
1407
- * '/path/to/assets/image.png'
1408
- *
1409
- * // `platform` suffixed
1410
- * '/path/to/assets/image.android.png'
1411
- *
1412
- * // `scale` suffixed
1413
- * '/path/to/assets/image@1x.png'
1414
- *
1415
- * // both `platform` and `scale` suffixed
1416
- * '/path/to/assets/image@1x.android.png'
1417
- * ```
1418
- */
1419
- function getSuffixedPath(assetPath, context, options) {
1420
- const suffixedBasename = addSuffix(assetPath, context, {
1421
- scale: options?.scale,
1422
- platform: options?.platform
1423
- });
1424
- const dirname = node_path.default.dirname(assetPath);
1425
- return node_path.default.join(dirname, suffixedBasename);
1426
- }
1427
- function resolveAssetPath(assetPath, context, scale) {
1428
- const suffixedPaths = [
1429
- getSuffixedPath(assetPath, context, {
1430
- scale,
1431
- platform: context.platform
1432
- }),
1433
- context.preferNativePlatform ? getSuffixedPath(assetPath, context, {
1434
- scale,
1435
- platform: "native"
1436
- }) : null,
1437
- getSuffixedPath(assetPath, context, { scale })
1438
- ].filter(es_toolkit.isNotNil);
1439
- /**
1440
- * When scale is 1, filename can be suffixed or non-suffixed(`image.png`).
1441
- *
1442
- * - Suffixed
1443
- * - `filename.<platform>@<scale>x.ext`
1444
- * - `filename.<platform>.ext`
1445
- * - `filename@<scale>x.ext`
1446
- * - Non suffixed
1447
- * - `filename.ext`
1448
- *
1449
- * 1. Resolve non-suffixed asset first.
1450
- * 2. If file is not exist, resolve suffixed path.
1451
- */
1452
- if (scale === 1) try {
1453
- node_fs.default.statSync(assetPath);
1454
- return assetPath;
1455
- } catch {}
1456
- for (const suffixedPath of suffixedPaths) try {
1457
- node_fs.default.statSync(suffixedPath);
1458
- return suffixedPath;
1459
- } catch {}
1460
- throw new Error(`cannot resolve asset path for ${assetPath}`);
1461
- }
1462
- /**
1463
- * @see https://github.com/facebook/react-native/blob/0.83-stable/packages/community-cli-plugin/src/commands/bundle/assetPathUtils.js
1464
- */
1465
- async function copyAssetsToDestination(options) {
1466
- const { assets, platform, assetsDir, preferNativePlatform } = options;
1467
- const context = {
1468
- platform,
1469
- preferNativePlatform
1470
- };
1471
- const mkdirWithAssertPath = (targetPath) => {
1472
- const dirname = node_path.default.dirname(targetPath);
1473
- node_fs.default.mkdirSync(dirname, { recursive: true });
1474
- };
1475
- return Promise.all(assets.map((asset) => {
1476
- return Promise.all(asset.scales.map(async (scale) => {
1477
- if (platform !== "android") {
1478
- const from = resolveAssetPath(asset.id, context, scale);
1479
- const to = node_path.default.join(assetsDir, getIosAssetDestinationPath(asset, scale));
1480
- mkdirWithAssertPath(to);
1481
- return node_fs.default.copyFileSync(from, to);
1482
- }
1483
- const from = resolveAssetPath(asset.id, context, scale);
1484
- const to = node_path.default.join(assetsDir, getAndroidAssetDestinationPath(asset, scale));
1485
- mkdirWithAssertPath(to);
1486
- node_fs.default.copyFileSync(from, to);
1487
- })).then(() => void 0);
1488
- })).then(() => void 0);
1489
- }
1490
- /**
1491
- * @see https://github.com/facebook/react-native/blob/0.83-stable/packages/community-cli-plugin/src/commands/bundle/getAssetDestPathIOS.js
1492
- */
1493
- function getIosAssetDestinationPath(asset, scale) {
1494
- const suffix = scale === 1 ? "" : `@${scale}x`;
1495
- const fileName = `${asset.name + suffix}.${asset.type}`;
1496
- const devServerBasePath = asset.httpServerLocation.at(0) === "/" ? asset.httpServerLocation.slice(1) : asset.httpServerLocation;
1497
- return node_path.default.join(devServerBasePath.replace(/\.\.\//g, "_"), fileName);
1498
- }
1499
- function getAndroidAssetDestinationPath(asset, scale) {
1500
- const assetQualifierSuffix = ANDROID_ASSET_QUALIFIER[scale];
1501
- const assetName = `${asset.httpServerLocation.at(0) === "/" ? asset.httpServerLocation.slice(1) : asset.httpServerLocation}/${asset.name}`.toLowerCase().replace(/\//g, "_").replace(/(?:[^a-z0-9_])/g, "").replace(/^assets_/, "");
1502
- if (!assetQualifierSuffix) throw new Error(`invalid asset qualifier: ${asset.id}`);
1503
- return node_path.default.join(isDrawable(asset.type) ? `drawable-${assetQualifierSuffix}` : "raw", `${assetName}.${asset.type}`);
1504
- }
1505
- /**
1506
- * @see https://developer.android.com/guide/topics/resources/drawable-resource
1507
- */
1508
- function isDrawable(type) {
1509
- return [
1510
- "gif",
1511
- "heic",
1512
- "heif",
1513
- "jpeg",
1514
- "jpg",
1515
- "ktx",
1516
- "png",
1517
- "webp",
1518
- "xml"
1519
- ].includes(type);
1520
- }
1521
- function generateAssetRegistryCode(assetRegistryPath, asset) {
1522
- return `module.exports = require('${assetRegistryPath}').registerAsset(${JSON.stringify(asset)});`;
1523
- }
1524
- //#endregion
1525
- //#region src/core/plugins/utils/transform-utils.ts
1526
- const TRANSFORM_FLAGS_KEY = Symbol("transform-flags");
1527
- let TransformFlag = /* @__PURE__ */ function(TransformFlag) {
1528
- TransformFlag[TransformFlag["NONE"] = 0] = "NONE";
1529
- TransformFlag[TransformFlag["CODEGEN_REQUIRED"] = 1] = "CODEGEN_REQUIRED";
1530
- TransformFlag[TransformFlag["STRIP_FLOW_REQUIRED"] = 2] = "STRIP_FLOW_REQUIRED";
1531
- TransformFlag[TransformFlag["SKIP_ALL"] = 128] = "SKIP_ALL";
1532
- return TransformFlag;
1533
- }({});
1534
- function setFlag(context, id, flag, options) {
1535
- const moduleInfo = context.getModuleInfo(id);
1536
- if (moduleInfo && hasFlag(moduleInfo.meta)) {
1537
- if (options?.override) moduleInfo.meta[TRANSFORM_FLAGS_KEY] = flag;
1538
- else moduleInfo.meta[TRANSFORM_FLAGS_KEY] |= flag;
1539
- return moduleInfo.meta;
1540
- } else return { [TRANSFORM_FLAGS_KEY]: flag };
1541
- }
1542
- function hasFlag(meta) {
1543
- return TRANSFORM_FLAGS_KEY in meta;
1544
- }
1545
- function getFlag(context, id) {
1546
- return getFlagFromModuleInfo(context.getModuleInfo(id));
1547
- }
1548
- function getFlagFromModuleInfo(moduleInfo) {
1549
- if (moduleInfo && hasFlag(moduleInfo.meta)) return moduleInfo.meta[TRANSFORM_FLAGS_KEY];
1550
- return TransformFlag.NONE;
1551
- }
1552
- function withTransformBoundary(context, plugins) {
1553
- return [
1554
- {
1555
- name: "rollipop:transform-initializer",
1556
- transform: {
1557
- order: "pre",
1558
- handler(_code, id) {
1559
- if (context.state.hmrUpdates.has(id)) {
1560
- context.state.hmrUpdates.delete(id);
1561
- return { meta: setFlag(this, id, TransformFlag.NONE, { override: true }) };
1562
- }
1563
- }
1564
- }
1565
- },
1566
- {
1567
- name: "rollipop:transform-change-watcher",
1568
- watchChange(id) {
1569
- context.state.hmrUpdates.add(id);
1570
- }
1571
- },
1572
- plugins
1573
- ];
1574
- }
1575
- //#endregion
1576
- //#region src/core/plugins/react-native-plugin.ts
1577
- function reactNativePlugin(options) {
1578
- const { projectRoot, platform, preferNativePlatform, buildType, assetsDir, assetExtensions, assetRegistryPath, flowFilter, codegenFilter, builtinPluginConfig } = options;
1579
- const codegenPlugin = {
1580
- name: "rollipop:react-native-codegen-marker",
1581
- transform: {
1582
- order: "pre",
1583
- filter: codegenFilter,
1584
- handler(_code, id) {
1585
- return { meta: setFlag(this, id, TransformFlag.CODEGEN_REQUIRED) };
1586
- }
1587
- }
1588
- };
1589
- const stripFlowSyntaxPlugin = {
1590
- name: "rollipop:react-native-strip-flow-syntax",
1591
- transform: {
1592
- order: "pre",
1593
- filter: flowFilter,
1594
- async handler(code, id) {
1595
- const flags = getFlag(this, id);
1596
- if (flags & TransformFlag.SKIP_ALL) return;
1597
- if (flags & TransformFlag.CODEGEN_REQUIRED) return { meta: setFlag(this, id, TransformFlag.STRIP_FLOW_REQUIRED) };
1598
- const result = await stripFlowTypes(id, code);
1599
- return {
1600
- code: result.code,
1601
- map: result.map,
1602
- moduleType: "tsx"
1603
- };
1604
- }
1605
- }
1606
- };
1607
- const assets = [];
1608
- const assetPlugin = {
1609
- name: "rollipop:react-native-asset",
1610
- load: {
1611
- filter: [(0, _rollipop_rolldown_pluginutils.include)((0, _rollipop_rolldown_pluginutils.id)(new RegExp(`\\.(?:${assetExtensions.join("|")})$`)))],
1612
- async handler(id) {
1613
- this.debug(`Asset ${id} found`);
1614
- const assetData = await resolveScaledAssets({
1615
- projectRoot,
1616
- assetPath: id,
1617
- platform,
1618
- preferNativePlatform
1619
- });
1620
- assets.push(assetData);
1621
- return {
1622
- code: generateAssetRegistryCode(assetRegistryPath, assetData),
1623
- meta: setFlag(this, id, TransformFlag.SKIP_ALL),
1624
- moduleType: "js"
1625
- };
1626
- }
1627
- },
1628
- buildStart() {
1629
- assets.length = 0;
1630
- },
1631
- async buildEnd(error) {
1632
- if (error || buildType === "serve") return;
1633
- if (assetsDir != null) {
1634
- this.debug(`Copying assets to ${assetsDir}`);
1635
- await copyAssetsToDestination({
1636
- assets,
1637
- assetsDir,
1638
- platform,
1639
- preferNativePlatform
1640
- });
1641
- }
1642
- }
1643
- };
1644
- return [...builtinPluginConfig ? [(0, _rollipop_rolldown_experimental.rollipopReactNativePlugin)(builtinPluginConfig)] : [codegenPlugin, stripFlowSyntaxPlugin], assetPlugin];
1645
- }
1646
- //#endregion
1647
- //#region src/core/plugins/prelude-plugin.ts
1648
- const IS_ENTRY = Symbol("IS_ENTRY");
1649
- function preludePlugin(options) {
1650
- if (options.modulePaths.length === 0) return null;
1651
- const preludeImportStatements = options.modulePaths.map((modulePath) => `import '${modulePath}';`).join("\n");
1652
- let processed = false;
1653
- return {
1654
- name: "rollipop:prelude",
1655
- buildStart() {
1656
- processed = false;
1657
- },
1658
- resolveId: { handler: (source, _importer, extraOptions) => {
1659
- if (extraOptions.isEntry) return {
1660
- id: source,
1661
- meta: { [IS_ENTRY]: true }
1662
- };
1663
- } },
1664
- load: { handler(id) {
1665
- if (processed) return;
1666
- const moduleInfo = this.getModuleInfo(id);
1667
- if (moduleInfo && isEntry(moduleInfo.meta)) {
1668
- this.debug(`Prelude plugin found entry ${id}`);
1669
- const modifiedSource = [preludeImportStatements, node_fs.default.readFileSync(id, "utf-8")].join("\n");
1670
- processed = true;
1671
- return modifiedSource;
1672
- }
1673
- } }
1674
- };
1675
- }
1676
- function isEntry(meta) {
1677
- return IS_ENTRY in meta;
1678
- }
1679
- //#endregion
1680
- //#region src/core/plugins/json-plugin.ts
1681
- function jsonPlugin() {
1682
- return {
1683
- name: "rollipop:json",
1684
- load: {
1685
- filter: [(0, _rollipop_rolldown_pluginutils.include)((0, _rollipop_rolldown_pluginutils.id)(/\.json$/))],
1686
- handler(id) {
1687
- return {
1688
- code: `export = ${node_fs.default.readFileSync(id, "utf-8")};`,
1689
- meta: setFlag(this, id, TransformFlag.SKIP_ALL),
1690
- moduleType: "ts"
1691
- };
1692
- }
1693
- }
1694
- };
1695
- }
1696
- //#endregion
1697
- //#region src/utils/babel.ts
1698
- function mergeBabelOptions(options) {
1699
- return options.reduce((acc, options) => (0, es_toolkit.mergeWith)(acc, options, merge$4), {});
1700
- }
1701
- function merge$4(target, source, key) {
1702
- if (key === "plugins") return [...target ?? [], ...source ?? []];
1703
- if (key === "presets") return [...target ?? [], ...source ?? []];
1704
- }
1705
- //#endregion
1706
- //#region src/core/plugins/utils/source.ts
1707
- const TS_EXTENSION_REGEXP = /\.tsx?$/;
1708
- function isTS(id) {
1709
- return TS_EXTENSION_REGEXP.test(id);
1710
- }
1711
- function isJSX(id) {
1712
- return id.endsWith("x");
1713
- }
1714
- //#endregion
1715
- //#region src/core/plugins/babel-plugin.ts
1716
- function babelPlugin({ useNativeTransformPipeline, transformConfig }) {
1717
- const { rules = [] } = transformConfig ?? {};
1718
- const babelOptionsById = /* @__PURE__ */ new Map();
1719
- const babelRules = rules.map(({ filter, options }, index) => {
1720
- return {
1721
- name: `rollipop:babel-rule-${index}`,
1722
- transform: {
1723
- filter,
1724
- handler(code, id) {
1725
- const existingBabelOptions = babelOptionsById.get(id);
1726
- const resolvedOptions = typeof options === "function" ? options(code, id) : options;
1727
- existingBabelOptions ? existingBabelOptions.push(resolvedOptions) : babelOptionsById.set(id, [resolvedOptions]);
1728
- }
1729
- }
1730
- };
1731
- });
1732
- const babelPlugin = {
1733
- name: "rollipop:babel",
1734
- buildStart() {
1735
- babelOptionsById.clear();
1736
- },
1737
- transform: { handler(code, id) {
1738
- const flags = getFlag(this, id);
1739
- if (flags & TransformFlag.SKIP_ALL) return;
1740
- const babelOptions = babelOptionsById.get(id) ?? [];
1741
- if (!(useNativeTransformPipeline ? babelOptions.length > 0 : flags & TransformFlag.CODEGEN_REQUIRED || babelOptions.length > 0)) return;
1742
- const baseOptions = useNativeTransformPipeline ? [] : [getPreset(flags, id)];
1743
- const result = _babel_core.transformSync(code, {
1744
- filename: id,
1745
- babelrc: false,
1746
- configFile: false,
1747
- sourceMaps: true,
1748
- ...mergeBabelOptions([...baseOptions, ...babelOptions])
1749
- });
1750
- (0, es_toolkit.invariant)(result?.code, `Failed to transform with babel: ${id}`);
1751
- return {
1752
- code: result.code,
1753
- map: result.map
1754
- };
1755
- } }
1756
- };
1757
- return [...babelRules, babelPlugin];
1758
- }
1759
- function getPreset(flags, id) {
1760
- const presets = [];
1761
- const plugins = [];
1762
- let parserOpts = null;
1763
- if (flags & TransformFlag.STRIP_FLOW_REQUIRED) {
1764
- parserOpts = { flow: "all" };
1765
- plugins.push([require.resolve("babel-plugin-syntax-hermes-parser"), {
1766
- parseLangTypes: "flow",
1767
- reactRuntimeTarget: "19"
1768
- }], require.resolve("@babel/plugin-transform-flow-strip-types"));
1769
- } else if (isTS(id)) plugins.push([require.resolve("@babel/plugin-transform-typescript"), {
1770
- isTSX: isJSX(id),
1771
- allowNamespaces: true
1772
- }]);
1773
- if (flags & TransformFlag.CODEGEN_REQUIRED) plugins.push([require.resolve("@react-native/babel-plugin-codegen")]);
1774
- const options = {
1775
- presets,
1776
- plugins
1777
- };
1778
- if (parserOpts) options.parserOpts = parserOpts;
1779
- return options;
1780
- }
1781
- //#endregion
1782
- //#region src/utils/swc.ts
1783
- function mergeSwcOptions(options) {
1784
- return options.reduce((acc, options) => (0, es_toolkit.mergeWith)(acc, options, merge$3), {});
1785
- }
1786
- function merge$3(target, source, key) {
1787
- if (key === "plugins") return [...target ?? [], ...source ?? []];
1788
- }
1789
- //#endregion
1790
- //#region src/core/plugins/shared/filters.ts
1791
- const ROLLDOWN_RUNTIME_EXCLUDE_FILTER = (0, _rollipop_rolldown_pluginutils.exclude)((0, _rollipop_rolldown_pluginutils.or)((0, _rollipop_rolldown_pluginutils.id)(/rolldown\/runtime/), (0, _rollipop_rolldown_pluginutils.id)(/@oxc-project\+runtime/)));
1792
- //#endregion
1793
- //#region src/core/plugins/swc-plugin.ts
1794
- function swcPlugin({ useNativeTransformPipeline, runtimeTarget, transformConfig }) {
1795
- const { rules = [] } = transformConfig ?? {};
1796
- const swcOptionsById = /* @__PURE__ */ new Map();
1797
- const swcHelpersResolvePlugin = {
1798
- name: "rollipop:swc-helpers-resolve",
1799
- resolveId: {
1800
- order: "pre",
1801
- filter: [(0, _rollipop_rolldown_pluginutils.include)((0, _rollipop_rolldown_pluginutils.id)(/^@swc\/helpers/)), ROLLDOWN_RUNTIME_EXCLUDE_FILTER],
1802
- handler(source, _importer, extraOptions) {
1803
- return this.resolve(source, __dirname, extraOptions);
1804
- }
1805
- }
1806
- };
1807
- const swcRules = rules.map(({ filter, options }, index) => {
1808
- return {
1809
- name: `rollipop:swc-rule-${index}`,
1810
- transform: {
1811
- filter,
1812
- handler(code, id) {
1813
- const existingBabelOptions = swcOptionsById.get(id);
1814
- const resolvedOptions = typeof options === "function" ? options(code, id) : options;
1815
- existingBabelOptions ? existingBabelOptions.push(resolvedOptions) : swcOptionsById.set(id, [resolvedOptions]);
1816
- }
1817
- }
1818
- };
1819
- });
1820
- const getSwcPreset = useNativeTransformPipeline ? null : presets[runtimeTarget];
1821
- const swcPlugin = {
1822
- name: "rollipop:swc",
1823
- buildStart() {
1824
- swcOptionsById.clear();
1825
- },
1826
- transform: {
1827
- filter: [ROLLDOWN_RUNTIME_EXCLUDE_FILTER],
1828
- handler(code, id) {
1829
- if (getFlag(this, id) & TransformFlag.SKIP_ALL) return;
1830
- const swcOptions = swcOptionsById.get(id) ?? [];
1831
- if (getSwcPreset == null && swcOptions.length === 0) return;
1832
- const baseOptions = getSwcPreset != null ? [getSwcPreset(id)] : [];
1833
- const result = _swc_core.transformSync(code, {
1834
- filename: id,
1835
- configFile: false,
1836
- swcrc: false,
1837
- sourceMaps: true,
1838
- inputSourceMap: false,
1839
- ...mergeSwcOptions([...baseOptions, ...swcOptions])
1840
- });
1841
- return {
1842
- code: result.code,
1843
- map: result.map
1844
- };
1845
- }
1846
- }
1847
- };
1848
- return [
1849
- swcHelpersResolvePlugin,
1850
- ...swcRules,
1851
- swcPlugin
1852
- ];
1853
- }
1854
- const presets = {
1855
- "hermes-v1": (id) => ({
1856
- env: {
1857
- targets: { node: 9999 },
1858
- include: [
1859
- "transform-block-scoping",
1860
- "transform-class-properties",
1861
- "transform-private-methods",
1862
- "transform-private-property-in-object"
1863
- ]
1864
- },
1865
- jsc: {
1866
- parser: {
1867
- syntax: "typescript",
1868
- tsx: true
1869
- },
1870
- transform: { react: { runtime: "preserve" } },
1871
- externalHelpers: true
1872
- },
1873
- isModule: id.endsWith(".cjs") ? "commonjs" : true
1874
- }),
1875
- hermes: (id) => ({
1876
- jsc: {
1877
- parser: {
1878
- syntax: "typescript",
1879
- tsx: true
1880
- },
1881
- transform: { react: { runtime: "preserve" } },
1882
- externalHelpers: true,
1883
- keepClassNames: true,
1884
- loose: false,
1885
- assumptions: {
1886
- setPublicClassFields: true,
1887
- privateFieldsAsProperties: true
1888
- },
1889
- target: "es5"
1890
- },
1891
- isModule: id.endsWith(".cjs") ? "commonjs" : true
1892
- })
1893
- };
1894
- //#endregion
1895
- //#region src/core/plugins/reporter-plugin.ts
1896
- function reporterPlugin(options) {
1897
- const { reporter, initialTotalModules = 0 } = options ?? {};
1898
- let totalModules = initialTotalModules;
1899
- let startedAt = 0;
1900
- let transformedModules = 0;
1901
- let unknownTotalModules = totalModules === 0;
1902
- return {
1903
- name: "rollipop:status",
1904
- buildStart() {
1905
- startedAt = performance.now();
1906
- transformedModules = 0;
1907
- reporter?.update({ type: "bundle_build_started" });
1908
- },
1909
- buildEnd(error) {
1910
- const endedAt = performance.now();
1911
- if (transformedModules !== 0) totalModules = transformedModules;
1912
- unknownTotalModules = false;
1913
- reporter?.update(error == null ? {
1914
- type: "bundle_build_done",
1915
- totalModules,
1916
- duration: endedAt - startedAt
1917
- } : {
1918
- type: "bundle_build_failed",
1919
- error
1920
- });
1921
- },
1922
- transform: {
1923
- order: "post",
1924
- handler(_code, id) {
1925
- ++transformedModules;
1926
- if (!unknownTotalModules && totalModules < transformedModules) totalModules = transformedModules;
1927
- reporter?.update({
1928
- type: "transform",
1929
- id,
1930
- totalModules: unknownTotalModules ? void 0 : totalModules,
1931
- transformedModules
1932
- });
1933
- }
1934
- },
1935
- watchChange(id) {
1936
- reporter?.update({
1937
- type: "watch_change",
1938
- id
1939
- });
1940
- }
1941
- };
1942
- }
1943
- //#endregion
1944
- //#region src/core/plugins/dev-server-plugin.ts
1945
- async function devServerPlugin(options) {
1946
- const { cwd, hmrClientPath, hmrConfig } = options;
1947
- if (hmrConfig == null) return null;
1948
- return [{
1949
- name: "rollipop:replace-hmr-client",
1950
- load: {
1951
- filter: [(0, _rollipop_rolldown_pluginutils.include)((0, _rollipop_rolldown_pluginutils.id)((0, _rollipop_rolldown_pluginutils.exactRegex)(resolveFrom(cwd, typeof hmrClientPath === "function" ? await hmrClientPath(cwd) : hmrClientPath))))],
1952
- handler(id) {
1953
- this.debug(`Replacing HMR client: ${id}`);
1954
- return {
1955
- code: hmrConfig.clientImplement,
1956
- moduleType: "ts"
1957
- };
1958
- }
1959
- }
1960
- }, (0, _rollipop_rolldown_experimental.rollipopReactRefreshWrapperPlugin)({
1961
- cwd,
1962
- include: [/\.[tj]sx?(?:$|\?)/],
1963
- exclude: [/\/node_modules\//]
1964
- })];
1965
- }
1966
- //#endregion
1967
- //#region src/core/rolldown.ts
1968
- resolveRolldownOptions.cache = /* @__PURE__ */ new Map();
1969
- async function resolveRolldownOptions(context, config, buildOptions, devEngineOptions) {
1970
- const cachedOptions = resolveRolldownOptions.cache.get(context.id);
1971
- if (cachedOptions != null) return cachedOptions;
1972
- const { platform, dev, cache } = buildOptions;
1973
- const isDevServerMode = dev && context.buildType === "serve";
1974
- (0, es_toolkit.invariant)(isDevServerMode ? devEngineOptions != null : true, "devEngineOptions is required in dev server mode");
1975
- const env = loadEnv(config);
1976
- const builtInEnv = {
1977
- MODE: config.mode,
1978
- ...isDevServerMode ? { BASE_URL: getBaseUrl(devEngineOptions.host, devEngineOptions.port, devEngineOptions.https) } : null
1979
- };
1980
- const hmrConfig = resolveHmrConfig(config);
1981
- const hmrEnabled = hmrConfig != null;
1982
- const { sourceExtensions, assetExtensions, preferNativePlatform, external: rolldownExternal, ...rolldownResolve } = config.resolver;
1983
- const { polyfills, banner: rolldownBanner, footer: rolldownFooter, postBanner: rolldownPostBanner, postFooter: rolldownPostFooter, intro: rolldownIntro, outro: rolldownOutro, shimMissingExports: rolldownShimMissingExports } = config.serializer;
1984
- const { flow: _flow, babel: _babel, swc: _swc, ...rolldownTransform } = config.transformer;
1985
- const { treeshake: rolldownTreeshake, minify: rolldownMinify, lazyBarrel: rolldownLazyBarrel, ...rolldownOptimization } = config.optimization;
1986
- const { globalIdentifiers: rolldownGlobalIdentifiers } = config.reactNative;
1987
- const { sourcemap: rolldownSourcemap, sourcemapBaseUrl: rolldownSourcemapBaseUrl, sourcemapDebugIds: rolldownSourcemapDebugIds, sourcemapIgnoreList: rolldownSourcemapIgnoreList, sourcemapPathTransform: rolldownSourcemapPathTransform } = config;
1988
- const userPlugins = config.plugins;
1989
- const mergedResolveOptions = (0, es_toolkit.merge)({ extensions: getResolveExtensions({
1990
- sourceExtensions,
1991
- assetExtensions,
1992
- platform,
1993
- preferNativePlatform
1994
- }) }, rolldownResolve);
1995
- const mergedTransformOptions = (0, es_toolkit.merge)({
1996
- cwd: config.root,
1997
- target: "esnext",
1998
- jsx: {
1999
- runtime: "automatic",
2000
- development: dev
2001
- },
2002
- define: {
2003
- __DEV__: asLiteral(dev),
2004
- "process.env.NODE_ENV": asLiteral(nodeEnvironment(dev)),
2005
- "process.env.DEBUG_ROLLIPOP": asLiteral(isDebugEnabled()),
2006
- ...hmrEnabled ? null : { "import.meta.hot": "{}" },
2007
- ...defineEnvFromObject(env),
2008
- ...defineEnvFromObject(builtInEnv)
2009
- },
2010
- helpers: { mode: "Runtime" }
2011
- }, rolldownTransform);
2012
- const preludePluginOptions = resolvePreludePluginOptions(config);
2013
- const reactNativePluginOptions = await resolveReactNativePluginOptions(config, context, buildOptions);
2014
- const babelPluginOptions = resolveBabelPluginOptions(config);
2015
- const swcPluginOptions = resolveSwcPluginOptions(config);
2016
- const devServerPluginOptions = resolveDevServerPluginOptions(config, hmrConfig);
2017
- const reporterPluginOptions = resolveReporterPluginOptions(config, context, buildOptions);
2018
- const finalOptions = await applyDangerouslyOverrideOptionsFinalizer(config, {
2019
- platform: "neutral",
2020
- cwd: config.root,
2021
- input: config.entry,
2022
- tsconfig: config.tsconfig,
2023
- resolve: mergedResolveOptions,
2024
- transform: mergedTransformOptions,
2025
- treeshake: rolldownTreeshake,
2026
- external: rolldownExternal,
2027
- shimMissingExports: rolldownShimMissingExports,
2028
- optimization: rolldownOptimization,
2029
- experimental: {
2030
- lazyBarrel: rolldownLazyBarrel,
2031
- ...isDevServerMode ? { devMode: hmrConfig ? { implement: hmrConfig.runtimeImplement } : false } : null
2032
- },
2033
- plugins: withTransformBoundary(context, [
2034
- preludePlugin(preludePluginOptions),
2035
- reactNativePlugin(reactNativePluginOptions),
2036
- jsonPlugin(),
2037
- babelPlugin(babelPluginOptions),
2038
- swcPlugin(swcPluginOptions),
2039
- devServerPlugin(devServerPluginOptions),
2040
- reporterPlugin(reporterPluginOptions),
2041
- userPlugins
2042
- ]),
2043
- checks: {
2044
- eval: false,
2045
- pluginTimings: isDebugEnabled()
2046
- },
2047
- logLevel: isDebugEnabled() ? "debug" : "info",
2048
- onLog(level, log, defaultHandler) {
2049
- if (log.code?.startsWith("PLUGIN_")) printPluginLog(level, log, log.plugin);
2050
- else defaultHandler(level, log);
2051
- },
2052
- id: context.id
2053
- }, {
2054
- format: "esm",
2055
- file: buildOptions.outfile,
2056
- banner: rolldownBanner,
2057
- footer: rolldownFooter,
2058
- postFooter: rolldownPostFooter,
2059
- postBanner: rolldownPostBanner,
2060
- outro: rolldownOutro,
2061
- intro: async (chunk) => {
2062
- return [
2063
- ...getGlobalVariables(dev, context.buildType),
2064
- ...loadPolyfills(polyfills),
2065
- typeof rolldownIntro === "function" ? await rolldownIntro(chunk) : rolldownIntro
2066
- ].filter(es_toolkit.isNotNil).join("\n");
2067
- },
2068
- minify: buildOptions.minify ?? rolldownMinify,
2069
- sourcemap: buildOptions.sourcemap ?? rolldownSourcemap,
2070
- sourcemapBaseUrl: rolldownSourcemapBaseUrl,
2071
- sourcemapDebugIds: rolldownSourcemapDebugIds,
2072
- sourcemapIgnoreList: rolldownSourcemapIgnoreList,
2073
- sourcemapPathTransform: rolldownSourcemapPathTransform ?? createProjectRootSourcemapPathTransform(config.root),
2074
- codeSplitting: false,
2075
- strictExecutionOrder: true,
2076
- globalIdentifiers: rolldownGlobalIdentifiers,
2077
- persistentCache: cache
2078
- });
2079
- resolveRolldownOptions.cache.set(context.id, finalOptions);
2080
- return finalOptions;
2081
- }
2082
- function resolvePreludePluginOptions(config) {
2083
- return { modulePaths: config.serializer.prelude };
2084
- }
2085
- async function resolveReactNativePluginOptions(config, context, buildOptions) {
2086
- return {
2087
- projectRoot: config.root,
2088
- platform: buildOptions.platform,
2089
- preferNativePlatform: config.resolver.preferNativePlatform,
2090
- buildType: context.buildType,
2091
- assetsDir: buildOptions.assetsDir,
2092
- assetExtensions: config.resolver.assetExtensions,
2093
- assetRegistryPath: await resolveAssetRegistryPath(config),
2094
- flowFilter: config.transformer.flow?.filter ?? [],
2095
- codegenFilter: config.reactNative.codegen?.filter ?? [],
2096
- builtinPluginConfig: resolveReactNativeBuiltinPluginConfig(config)
2097
- };
2098
- }
2099
- async function resolveAssetRegistryPath(config) {
2100
- const { assetRegistryPath } = config.reactNative;
2101
- const path = typeof assetRegistryPath === "function" ? await assetRegistryPath(config.root) : assetRegistryPath;
2102
- return resolveFrom(config.root, path);
2103
- }
2104
- function resolveReactNativeBuiltinPluginConfig(config) {
2105
- if (!config.experimental?.nativeTransformPipeline) return null;
2106
- return {
2107
- envName: config.mode,
2108
- runtimeTarget: resolveRuntimeTarget(config.runtimeTarget),
2109
- flow: config.experimental.flow,
2110
- worklets: resolveWorkletsConfig(config)
2111
- };
2112
- }
2113
- function resolveWorkletsConfig(config) {
2114
- const { worklets } = config.experimental ?? {};
2115
- if (worklets == null) return;
2116
- return (0, es_toolkit.merge)({
2117
- isRelease: config.mode === "production",
2118
- pluginVersion: resolvePackageJson(config.root, "react-native-worklets")?.version
2119
- }, worklets);
2120
- }
2121
- function resolveBabelPluginOptions(config) {
2122
- return {
2123
- useNativeTransformPipeline: config.experimental?.nativeTransformPipeline,
2124
- transformConfig: config.transformer.babel
2125
- };
2126
- }
2127
- function resolveSwcPluginOptions(config) {
2128
- return {
2129
- useNativeTransformPipeline: config.experimental?.nativeTransformPipeline,
2130
- runtimeTarget: config.runtimeTarget,
2131
- transformConfig: config.transformer.swc
2132
- };
2133
- }
2134
- function resolveDevServerPluginOptions(config, hmrConfig) {
2135
- return {
2136
- cwd: config.root,
2137
- hmrClientPath: config.reactNative.hmrClientPath,
2138
- hmrConfig
2139
- };
2140
- }
2141
- function resolveReporterPluginOptions(config, context, buildOptions) {
2142
- const statusReporter = createStatusReporter(config, context, buildOptions);
2143
- return {
2144
- initialTotalModules: getBuildTotalModules(context.storage, context.id),
2145
- reporter: mergeReporters([statusReporter, config.reporter].filter(es_toolkit.isNotNil))
2146
- };
2147
- }
2148
- function createStatusReporter(config, context, buildOptions) {
2149
- switch (config.terminal.status) {
2150
- case "compat": return new CompatStatusReporter();
2151
- case "progress": return new ProgressBarStatusReporter(context.id, `[${buildOptions.platform}, ${buildOptions.dev ? "dev" : "prod"}]`, getBuildTotalModules(context.storage, context.id));
2152
- }
2153
- }
2154
- function getResolveExtensions({ platform, sourceExtensions, assetExtensions, preferNativePlatform }) {
2155
- const supportedExtensions = [...sourceExtensions, ...assetExtensions];
2156
- return [...[platform, preferNativePlatform ? "native" : null].filter(es_toolkit.isNotNil).map((platform) => {
2157
- return supportedExtensions.map((extension) => `.${platform}.${extension}`);
2158
- }), ...supportedExtensions.map((extension) => `.${extension}`)].flat();
2159
- }
2160
- /**
2161
- * Default sourcemap path transform.
2162
- *
2163
- * Rolldown emits `sources` relative to the bundle output's directory, which
2164
- * yields paths like `../App.tsx` when the bundle lives under e.g. `dist/`.
2165
- * RN tooling (symbolication, devtools) expects project-root-relative paths,
2166
- * so this rewrites each entry to be relative to `projectRoot`.
2167
- */
2168
- function createProjectRootSourcemapPathTransform(projectRoot) {
2169
- return (source, sourcemapPath) => {
2170
- const absolute = node_path.default.resolve(node_path.default.dirname(sourcemapPath), source);
2171
- return node_path.default.relative(projectRoot, absolute);
2172
- };
2173
- }
2174
- function loadPolyfills(polyfills) {
2175
- return polyfills.map((polyfill) => {
2176
- if (typeof polyfill === "string") return node_fs.default.readFileSync(polyfill, "utf-8");
2177
- const path = "path" in polyfill ? polyfill.path : void 0;
2178
- const content = "code" in polyfill ? polyfill.code : node_fs.default.readFileSync(polyfill.path, "utf-8");
2179
- return polyfill.type === "iife" ? iife(content, path) : content;
2180
- });
2181
- }
2182
- async function applyDangerouslyOverrideOptionsFinalizer(config, inputOptions, outputOptions) {
2183
- const override = config.dangerously_overrideRolldownOptions;
2184
- if (override == null) return {
2185
- input: inputOptions,
2186
- output: outputOptions
2187
- };
2188
- return await applyOverrideRolldownOptions(override, {
2189
- input: inputOptions,
2190
- output: outputOptions
2191
- });
2192
- }
2193
- function getOverrideOptionsForDevServer(buildOptions) {
2194
- return {
2195
- input: {
2196
- transform: { jsx: { development: true } },
2197
- experimental: {
2198
- incrementalBuild: true,
2199
- nativeMagicString: true
2200
- },
2201
- treeshake: false
2202
- },
2203
- output: {
2204
- minify: buildOptions.minify ?? false,
2205
- sourcemap: buildOptions.sourcemap ?? true,
2206
- generatedCode: {
2207
- symbols: buildOptions.dev,
2208
- profilerNames: buildOptions.dev
2209
- }
2210
- }
2211
- };
2212
- }
2213
- //#endregion
2214
- //#region src/core/bundler.ts
2215
- var Bundler = class Bundler {
2216
- static async devEngine(config, buildOptions, devEngineOptions) {
2217
- const buildType = "serve";
2218
- const resolvedBuildOptions = resolveBuildOptions(config, buildOptions);
2219
- const context = Bundler.createContext(buildType, config, resolvedBuildOptions);
2220
- const { input = {}, output = {} } = await resolveRolldownOptions(context, config, resolvedBuildOptions, devEngineOptions);
2221
- const devServerOptions = getOverrideOptionsForDevServer(resolvedBuildOptions);
2222
- const devEngine = await (0, _rollipop_rolldown_experimental.dev)((0, es_toolkit.merge)(input, devServerOptions.input), (0, es_toolkit.merge)(output, devServerOptions.output), {
2223
- watch: config.watcher,
2224
- ...devEngineOptions
2225
- });
2226
- Object.defineProperty(devEngine, "getContext", {
2227
- value: () => context,
2228
- enumerable: true,
2229
- configurable: false
2230
- });
2231
- return devEngine;
2232
- }
2233
- static createId(config, buildOptions) {
2234
- return createId(config, buildOptions);
2235
- }
2236
- static createContext(buildType, config, buildOptions) {
2237
- return {
2238
- id: Bundler.createId(config, buildOptions),
2239
- root: config.root,
2240
- storage: FileStorage.getInstance(config.root),
2241
- buildType,
2242
- state: { hmrUpdates: /* @__PURE__ */ new Set() }
2243
- };
2244
- }
2245
- constructor(config) {
2246
- this.config = config;
2247
- Logo.printOnce();
2248
- }
2249
- async build(buildOptions) {
2250
- const buildType = "build";
2251
- const resolvedBuildOptions = resolveBuildOptions(this.config, buildOptions);
2252
- const context = Bundler.createContext(buildType, this.config, resolvedBuildOptions);
2253
- const sourcemap = resolvedBuildOptions.sourcemap ? true : false;
2254
- const { input, output } = await resolveRolldownOptions(context, this.config, resolvedBuildOptions);
2255
- const rolldownBuildOptions = {
2256
- ...input,
2257
- output: {
2258
- ...output,
2259
- sourcemap
2260
- },
2261
- write: Boolean(resolvedBuildOptions.outfile)
2262
- };
2263
- const chunk = (await _rollipop_rolldown.build(rolldownBuildOptions)).output[0];
2264
- (0, es_toolkit.invariant)(chunk, "Bundled chunk is not found");
2265
- if (resolvedBuildOptions.outfile && chunk.sourcemapFileName && resolvedBuildOptions.sourcemapOutfile) {
2266
- const outputDir = node_path.default.dirname(resolvedBuildOptions.outfile);
2267
- const sourcemapDir = node_path.default.dirname(resolvedBuildOptions.sourcemapOutfile);
2268
- const sourcemapFile = node_path.default.join(outputDir, chunk.sourcemapFileName);
2269
- if (!node_fs.default.existsSync(sourcemapDir)) node_fs.default.mkdirSync(sourcemapDir, { recursive: true });
2270
- node_fs.default.renameSync(sourcemapFile, resolvedBuildOptions.sourcemapOutfile);
2271
- }
2272
- return chunk;
2273
- }
2274
- };
2275
- //#endregion
2276
- //#region src/utils/bundle.ts
2277
- function getBaseBundleName(name) {
2278
- return name.replace(/^\//, "").replace(/\.bundle$/, "");
2279
- }
2280
- //#endregion
2281
- //#region src/utils/errors.ts
2282
- function normalizeRolldownError(error) {
2283
- const normalizedError = new Error((0, strip_ansi.default)(error.message));
2284
- normalizedError.stack = error.stack;
2285
- return normalizedError;
2286
- }
2287
- //#endregion
2288
- //#region src/utils/promise.ts
2289
- function taskHandler() {
2290
- let resolver;
2291
- let rejector;
2292
- return {
2293
- task: new Promise((resolve, reject) => {
2294
- resolver = resolve;
2295
- rejector = reject;
2296
- }),
2297
- resolve: () => resolver?.(void 0),
2298
- reject: (reason) => rejector?.(reason)
2299
- };
2300
- }
2301
- //#endregion
2302
- //#region src/server/bundle.ts
2303
- var FileSystemBundleStore = class {
2304
- bundleFilePath;
2305
- _sourceMap;
2306
- lazySourceMapConsumer = null;
2307
- holder;
2308
- constructor(projectRoot, id, code, sourceMap) {
2309
- const sharedDataPath = getSharedDataPath(projectRoot);
2310
- const bundlesPath = node_path.default.join(sharedDataPath, "bundles");
2311
- const bundleFilePath = node_path.default.join(bundlesPath, `${id}.bundle`);
2312
- if (!node_fs.default.existsSync(bundlesPath)) node_fs.default.mkdirSync(bundlesPath, { recursive: true });
2313
- node_fs.default.writeFileSync(bundleFilePath, code, { encoding: "utf-8" });
2314
- const stats = node_fs.default.statSync(bundleFilePath);
2315
- this.bundleFilePath = bundleFilePath;
2316
- this._sourceMap = sourceMap;
2317
- this.holder = {
2318
- code,
2319
- mtimeMs: stats.mtimeMs
2320
- };
2321
- logger.debug(`File system bundle created at ${bundleFilePath}`);
2322
- }
2323
- update() {
2324
- this.holder = {
2325
- code: node_fs.default.readFileSync(this.bundleFilePath, { encoding: "utf-8" }),
2326
- mtimeMs: node_fs.default.statSync(this.bundleFilePath).mtimeMs
2327
- };
2328
- }
2329
- get code() {
2330
- if (this.isStale()) {
2331
- logger.info("File system bundle is stale, updating...");
2332
- this.update();
2333
- } else logger.trace("File system bundle is up to date");
2334
- return this.holder.code;
2335
- }
2336
- get sourceMap() {
2337
- return this.isStale() ? void 0 : this._sourceMap;
2338
- }
2339
- get sourceMapConsumer() {
2340
- if (this.isStale() || this._sourceMap == null) return;
2341
- if (this.lazySourceMapConsumer == null) this.lazySourceMapConsumer = new source_map.SourceMapConsumer(this._sourceMap);
2342
- return this.lazySourceMapConsumer;
2343
- }
2344
- isStale() {
2345
- return this.holder.mtimeMs !== node_fs.default.statSync(this.bundleFilePath).mtimeMs;
2346
- }
2347
- };
2348
- //#endregion
2349
- //#region src/server/bundler-pool.ts
2350
- var BundlerDevEngine = class extends node_events.default {
2351
- initializeHandle;
2352
- isHmrEnabled;
2353
- _id;
2354
- bundleStore = null;
2355
- buildFailedError = null;
2356
- _devEngine = null;
2357
- _state = "idle";
2358
- _status = "idle";
2359
- constructor(options, config, buildOptions, onReporterEvent) {
2360
- super();
2361
- this.options = options;
2362
- this.config = config;
2363
- this.buildOptions = buildOptions;
2364
- this.onReporterEvent = onReporterEvent;
2365
- this._id = Bundler.createId(config, buildOptions);
2366
- this.initializeHandle = taskHandler();
2367
- this.isHmrEnabled = Boolean(buildOptions.dev && config.devMode.hmr);
2368
- this.on("buildStart", () => {
2369
- this._status = "building";
2370
- });
2371
- this.on("buildDone", () => {
2372
- this._status = "build-done";
2373
- });
2374
- this.on("buildFailed", () => {
2375
- this._status = "build-failed";
2376
- });
2377
- this.initialize();
2378
- }
2379
- get id() {
2380
- return this._id;
2381
- }
2382
- /** Snapshot of the bundler's current lifecycle state. */
2383
- get status() {
2384
- return this._status;
2385
- }
2386
- get devEngine() {
2387
- (0, es_toolkit.invariant)(this._devEngine, "DevEngine is not initialized");
2388
- return this._devEngine;
2389
- }
2390
- get ensureInitialized() {
2391
- return this.initializeHandle.task;
2392
- }
2393
- async initialize() {
2394
- if (this._state !== "idle" || this._devEngine != null) return this;
2395
- this._state = "initializing";
2396
- const onEvent = this.onReporterEvent ? (event) => this.onReporterEvent(this._id, event) : void 0;
2397
- const devEngine = await Bundler.devEngine(bindReporter(this.config, this, onEvent), this.buildOptions, {
2398
- host: this.options.server.host,
2399
- port: this.options.server.port,
2400
- onHmrUpdates: (errorOrResult) => {
2401
- if (!this.isHmrEnabled) return;
2402
- if (errorOrResult instanceof Error) {
2403
- logger$1.error("Failed to handle HMR updates", {
2404
- bundlerId: this.id,
2405
- error: errorOrResult
2406
- });
2407
- const normalizedError = normalizeRolldownError(errorOrResult);
2408
- this.config.reporter?.update({
2409
- type: "bundle_build_failed",
2410
- error: normalizedError
2411
- });
2412
- } else {
2413
- logger$1.trace("Detected changed files", {
2414
- bundlerId: this.id,
2415
- changedFiles: errorOrResult.changedFiles
2416
- });
2417
- this.emit("hmrUpdates", errorOrResult.updates);
2418
- }
2419
- },
2420
- onOutput: (errorOrResult) => {
2421
- if (errorOrResult instanceof Error) {
2422
- const normalizedError = normalizeRolldownError(errorOrResult);
2423
- logger$1.trace("onOutput", { bundlerId: this.id });
2424
- logger$1.error(errorOrResult.message);
2425
- this.buildFailedError = normalizedError;
2426
- this.emit("buildFailed", normalizedError);
2427
- } else {
2428
- const output = errorOrResult.output[0];
2429
- this.updateBundleStore(output);
2430
- this.buildFailedError = null;
2431
- logger$1.debug("Build completed", {
2432
- bundlerId: this.id,
2433
- bundleName: output.name
2434
- });
2435
- }
2436
- },
2437
- rebuildStrategy: "auto"
2438
- });
2439
- await devEngine.run();
2440
- this._devEngine = devEngine;
2441
- this._state = "ready";
2442
- this.initializeHandle.resolve();
2443
- }
2444
- updateBundleStore(output) {
2445
- this.bundleStore = new FileSystemBundleStore(this.config.root, this.id, output.code, output.map?.toString());
2446
- }
2447
- async getBundle() {
2448
- await this.ensureInitialized;
2449
- const state = await this.devEngine.getBundleState();
2450
- logger$1.debug("Bundle state", {
2451
- bundlerId: this.id,
2452
- state
2453
- });
2454
- if (state.lastFullBuildFailed) throw new Error(this.buildFailedError?.message ?? "Build failed");
2455
- if (state.hasStaleOutput || this.bundleStore == null) await this.devEngine.ensureLatestBuildOutput();
2456
- (0, es_toolkit.invariant)(this.bundleStore, "Bundle is not available");
2457
- return this.bundleStore;
2458
- }
2459
- };
2460
- var BundlerPool = class BundlerPool {
2461
- static instances = /* @__PURE__ */ new Map();
2462
- constructor(config, resolvedServerOptions, onReporterEvent) {
2463
- this.config = config;
2464
- this.resolvedServerOptions = resolvedServerOptions;
2465
- this.onReporterEvent = onReporterEvent;
2466
- }
2467
- instanceKey(bundleName, buildOptions) {
2468
- return `${bundleName}-${Bundler.createId(this.config, buildOptions)}`;
2469
- }
2470
- get(bundleName, buildOptions) {
2471
- const key = this.instanceKey(getBaseBundleName(bundleName), buildOptions);
2472
- const instance = BundlerPool.instances.get(key);
2473
- if (instance) return instance;
2474
- else {
2475
- logger$1.debug("Preparing new bundler instance", {
2476
- bundleName,
2477
- key
2478
- });
2479
- const instance = new BundlerDevEngine({ server: this.resolvedServerOptions }, this.config, buildOptions, this.onReporterEvent);
2480
- logger$1.debug("Setting new bundler instance", { key });
2481
- BundlerPool.instances.set(key, instance);
2482
- return instance;
2483
- }
2484
- }
2485
- /**
2486
- * Look up a cached bundler by its reporter-facing id (the same id carried
2487
- * in SSE events such as `bundle_build_done`). Returns `undefined` when no
2488
- * instance with that id has been created yet.
2489
- */
2490
- getInstanceById(id) {
2491
- for (const instance of BundlerPool.instances.values()) if (instance.id === id) return instance;
2492
- }
2493
- };
2494
- //#endregion
2495
- //#region src/server/constants.ts
2496
- const DEFAULT_PORT = 8081;
2497
- const DEFAULT_HOST = "localhost";
2498
- const DEV_SERVER_ASSET_PATH = "assets";
2499
- //#endregion
2500
- //#region src/server/error.ts
2501
- function errorHandler(error, request, reply) {
2502
- logger$1.error(`An error occurred while processing the request (${request.method} ${request.url}):`, error.message);
2503
- logger$1.debug(error);
2504
- reply.status(500).send("Internal Server Error");
2505
- }
2506
- //#endregion
2507
- //#region src/utils/reset-cache.ts
2508
- /**
2509
- * Resolve the build cache directory for the given project root. The cache
2510
- * itself is owned by rolldown's native implementation; we keep the path
2511
- * here only because `resetCache` — and any tooling that wants to inspect
2512
- * the on-disk layout — needs to know where to look.
2513
- */
2514
- function getCacheDirectory(projectRoot) {
2515
- return node_path.default.join(getSharedDataPath(projectRoot), "cache");
2516
- }
2517
- /**
2518
- * Remove the entire build cache directory for the given project root.
2519
- * Backs the `/reset-cache` control endpoint, the `reset_cache` MCP tool,
2520
- * and the `--reset-cache` CLI flag.
2521
- */
2522
- function resetCache(projectRoot) {
2523
- node_fs.default.rmSync(getCacheDirectory(projectRoot), {
2524
- recursive: true,
2525
- force: true
2526
- });
2527
- }
2528
- //#endregion
2529
- //#region src/server/mcp/server.ts
2530
- function createMcpServer(options) {
2531
- const { projectRoot, eventBus } = options;
2532
- const server = new _modelcontextprotocol_sdk_server_mcp_js.McpServer({
2533
- name: "rollipop",
2534
- version: "0.1.0"
2535
- }, { capabilities: { logging: {} } });
2536
- server.registerTool("reset_cache", {
2537
- title: "Reset Cache",
2538
- description: "Clear the entire build cache. The bundler will rebuild from scratch on next change."
2539
- }, async () => {
2540
- resetCache(projectRoot);
2541
- eventBus.emit({ type: "cache_reset" });
2542
- return { content: [{
2543
- type: "text",
2544
- text: "Cache cleared successfully."
2545
- }] };
2546
- });
2547
- server.registerTool("get_build_events", {
2548
- title: "Get Build Events",
2549
- description: "Subscribe to bundler events for a duration. Returns all events (build start/done/fail, watch changes, client logs, device connections) collected during the wait period.",
2550
- inputSchema: { duration: zod.z.number().min(1e3).max(6e4).default(1e4).describe("How long to listen for events in milliseconds (1000-60000, default 10000)") }
2551
- }, async ({ duration }) => {
2552
- const events = [];
2553
- const unsubscribe = eventBus.collect(events);
2554
- await new Promise((resolve) => setTimeout(resolve, duration));
2555
- unsubscribe();
2556
- if (events.length === 0) return { content: [{
2557
- type: "text",
2558
- text: "No events received during the listening period."
2559
- }] };
2560
- return { content: [{
2561
- type: "text",
2562
- text: JSON.stringify(events, null, 2)
2563
- }] };
2564
- });
2565
- return server;
2566
- }
2567
- const sessions = /* @__PURE__ */ new Map();
2568
- const plugin$6 = (0, fastify_plugin.default)((fastify, options) => {
2569
- fastify.addContentTypeParser("application/json", { parseAs: "string" }, (_req, body, done) => {
2570
- try {
2571
- done(null, JSON.parse(body));
2572
- } catch (error) {
2573
- done(error, void 0);
2574
- }
2575
- });
2576
- fastify.post("/mcp", async (request, reply) => {
2577
- const sessionId = request.headers["mcp-session-id"];
2578
- if (sessionId && sessions.has(sessionId)) {
2579
- const { transport } = sessions.get(sessionId);
2580
- await transport.handleRequest(request.raw, reply.raw, request.body);
2581
- return reply;
2582
- }
2583
- if (!sessionId && (0, _modelcontextprotocol_sdk_types_js.isInitializeRequest)(request.body)) {
2584
- const transport = new _modelcontextprotocol_sdk_server_streamableHttp_js.StreamableHTTPServerTransport({
2585
- sessionIdGenerator: () => (0, node_crypto.randomUUID)(),
2586
- onsessioninitialized: (sid) => {
2587
- sessions.set(sid, {
2588
- transport,
2589
- server
2590
- });
2591
- }
2592
- });
2593
- transport.onclose = () => {
2594
- const sid = transport.sessionId;
2595
- if (sid) sessions.delete(sid);
2596
- };
2597
- const server = createMcpServer(options);
2598
- await server.connect(transport);
2599
- await transport.handleRequest(request.raw, reply.raw, request.body);
2600
- return reply;
2601
- }
2602
- return reply.status(400).send({
2603
- jsonrpc: "2.0",
2604
- error: {
2605
- code: -32e3,
2606
- message: "Bad Request: invalid or missing session"
2607
- },
2608
- id: null
2609
- });
2610
- });
2611
- fastify.get("/mcp", async (request, reply) => {
2612
- const sessionId = request.headers["mcp-session-id"];
2613
- if (!sessionId || !sessions.has(sessionId)) return reply.status(400).send("Missing or invalid session ID");
2614
- await sessions.get(sessionId).transport.handleRequest(request.raw, reply.raw);
2615
- return reply;
2616
- });
2617
- fastify.delete("/mcp", async (request, reply) => {
2618
- const sessionId = request.headers["mcp-session-id"];
2619
- if (!sessionId || !sessions.has(sessionId)) return reply.status(404).send("Session not found");
2620
- await sessions.get(sessionId).transport.handleRequest(request.raw, reply.raw);
2621
- return reply;
2622
- });
2623
- }, { name: "mcp" });
2624
- //#endregion
2625
- //#region src/server/middlewares/bundlers.ts
2626
- const routeParamSchema$1 = (0, json_schema_to_ts.asConst)({
2627
- type: "object",
2628
- required: ["id"],
2629
- properties: { id: { type: "string" } }
2630
- });
2631
- const plugin$5 = (0, fastify_plugin.default)((fastify, { bundlerPool }) => {
2632
- fastify.get("/bundlers/:id/status", { schema: { params: routeParamSchema$1 } }, (request, reply) => {
2633
- const instance = bundlerPool.getInstanceById(request.params.id);
2634
- if (!instance) return reply.status(404).send({ error: "not found" });
2635
- return reply.send({
2636
- id: instance.id,
2637
- status: instance.status
2638
- });
2639
- });
2640
- }, { name: "bundlers" });
2641
- //#endregion
2642
- //#region src/server/middlewares/control.ts
2643
- const plugin$4 = (0, fastify_plugin.default)((fastify, { projectRoot, eventBus }) => {
2644
- fastify.all("/reset-cache", async (_request, reply) => {
2645
- resetCache(projectRoot);
2646
- eventBus.emit({ type: "cache_reset" });
2647
- return reply.send({
2648
- success: true,
2649
- message: "Cache cleared"
2650
- });
2651
- });
2652
- }, { name: "control" });
2653
- //#endregion
2654
- //#region src/server/middlewares/request-logger.ts
2655
- const requestLogger = (req, _res, next) => {
2656
- if (isDebugEnabled()) {
2657
- logger$1.trace(chalk.default.bgBlue(` ${req.method} `), chalk.default.gray(req.url));
2658
- Object.entries(req.headers).forEach(([key, value]) => {
2659
- logger$1.trace(`${chalk.default.bold(key)}: ${chalk.default.gray(value)}`);
2660
- });
2661
- }
2662
- next();
2663
- };
2664
- //#endregion
2665
- //#region src/server/middlewares/serve-assets.ts
2666
- const queryParamSchema = (0, json_schema_to_ts.asConst)({
2667
- type: "object",
2668
- properties: {
2669
- platform: { type: "string" },
2670
- hash: { type: "string" }
2671
- },
2672
- required: ["platform"]
2673
- });
2674
- const plugin$3 = (0, fastify_plugin.default)((fastify, options) => {
2675
- const { projectRoot, host, port, https, preferNativePlatform } = options;
2676
- const baseUrl = https ? `https://${host}:${port}` : `http://${host}:${port}`;
2677
- function resolveAsset(asset) {
2678
- return node_path.default.resolve(projectRoot, asset);
2679
- }
2680
- fastify.get(`/${DEV_SERVER_ASSET_PATH}/*`, {
2681
- schema: { querystring: queryParamSchema },
2682
- async handler(request, reply) {
2683
- const { url, query } = request;
2684
- const { pathname } = new URL(url, baseUrl);
2685
- const assetPath = resolveAsset(pathname.replace(new RegExp(`^/${DEV_SERVER_ASSET_PATH}/?`), ""));
2686
- let handle = null;
2687
- try {
2688
- handle = await node_fs.default.promises.open(resolveAssetPath(assetPath, {
2689
- platform: query.platform,
2690
- preferNativePlatform
2691
- }, 1), "r");
2692
- const assetData = await handle.readFile();
2693
- const { size } = await handle.stat();
2694
- await reply.header("Content-Type", mime.default.getType(assetPath) ?? "").header("Content-Length", size).send(assetData);
2695
- } catch (error) {
2696
- fastify.log.error(error, "Failed to serve asset (scale assets resolving is not implemented yet)");
2697
- await reply.status(500).send();
2698
- } finally {
2699
- await handle?.close();
2700
- }
2701
- }
2702
- });
2703
- }, { name: "serve-assets" });
2704
- //#endregion
2705
- //#region src/utils/response.ts
2706
- var BundleResponse = class BundleResponse {
2707
- static CRLF = "\r\n";
2708
- static THROTTLE_DELAY = 10;
2709
- done = 0;
2710
- total = 0;
2711
- boundary;
2712
- throttleTimer = null;
2713
- constructor(reply) {
2714
- this.reply = reply;
2715
- const boundary = performance.now().toString();
2716
- this.boundary = boundary;
2717
- this.reply.raw.writeHead(200, { "Content-Type": `multipart/mixed; boundary="${boundary}"` });
2718
- }
2719
- writeChunk(data, headers, end = false) {
2720
- if (this.reply.raw.writableEnded) return;
2721
- const CRLF = BundleResponse.CRLF;
2722
- this.reply.raw.write(`${CRLF}--${this.boundary}${CRLF}`);
2723
- this.reply.raw.write(Object.entries(headers).map(([key, value]) => `${key}: ${value}`).join(CRLF) + CRLF + CRLF);
2724
- if (data) this.reply.raw.write(data);
2725
- if (end) {
2726
- this.reply.raw.write(`${CRLF}--${this.boundary}--${CRLF}`);
2727
- this.reply.raw.end();
2728
- }
2729
- }
2730
- /**
2731
- * Sample
2732
- *
2733
- * ```
2734
- * --boundary
2735
- *
2736
- * Content-Type: application/json
2737
- *
2738
- * {"done":10,"total":100}
2739
- * ```
2740
- */
2741
- writeBundleState(done, total) {
2742
- const previousProgress = this.done / this.total;
2743
- const currentProgress = done / total;
2744
- this.done = done;
2745
- this.total = total;
2746
- if (total < 10 || this.throttleTimer != null || previousProgress >= currentProgress) return;
2747
- this.writeChunk(JSON.stringify({
2748
- done,
2749
- total
2750
- }), { "Content-Type": "application/json" });
2751
- this.throttleTimer = setTimeout(() => {
2752
- this.throttleTimer = null;
2753
- }, BundleResponse.THROTTLE_DELAY);
2754
- }
2755
- /**
2756
- * Sample
2757
- *
2758
- * ```
2759
- * --boundary
2760
- *
2761
- * X-Metro-Files-Changed-Count: 0
2762
- * Content-Type: application/json
2763
- * Content-Length: 100
2764
- * Last-Modified: Thu, 10 Aug 2023 12:00:00 GMT
2765
- *
2766
- * <bundle result>
2767
- * ```
2768
- */
2769
- endWithBundle(bundle) {
2770
- this.writeChunk(JSON.stringify({
2771
- done: this.total,
2772
- total: this.total
2773
- }), { "Content-Type": "application/json" });
2774
- this.writeChunk(bundle, {
2775
- "X-Metro-Files-Changed-Count": String(0),
2776
- "Content-Type": "application/javascript; charset=UTF-8",
2777
- "Content-Length": String(Buffer.byteLength(bundle)),
2778
- "Last-Modified": (/* @__PURE__ */ new Date()).toUTCString()
2779
- }, true);
2780
- }
2781
- endWithError(error) {
2782
- const errorData = JSON.stringify({
2783
- type: error?.name ?? "InternalError",
2784
- message: error?.message ?? "internal error",
2785
- errors: []
2786
- });
2787
- this.writeChunk(errorData, {
2788
- "Content-Type": "application/json",
2789
- "X-Http-Status": "500"
2790
- }, true);
2791
- }
2792
- };
2793
- //#endregion
2794
- //#region src/server/common/schema.ts
2795
- const bundleRequestSchema = (0, json_schema_to_ts.asConst)({
2796
- type: "object",
2797
- properties: {
2798
- platform: { type: "string" },
2799
- app: { type: "string" },
2800
- dev: { type: "boolean" },
2801
- minify: { type: "boolean" },
2802
- runModule: { type: "boolean" },
2803
- inlineSourceMap: { type: "boolean" },
2804
- modulesOnly: { type: "boolean" }
2805
- },
2806
- required: ["platform"]
2807
- });
2808
- new ajv.default().compile(bundleRequestSchema);
2809
- //#endregion
2810
- //#region src/server/middlewares/serve-bundle.ts
2811
- const routeParamSchema = (0, json_schema_to_ts.asConst)({
2812
- type: "object",
2813
- properties: { name: { type: "string" } }
2814
- });
2815
- function withGetBundleErrorHandler(reply, task) {
2816
- return task.catch((error) => {
2817
- return reply.status(500).send(error instanceof Error ? error.message : "Internal Server Error");
2818
- });
2819
- }
2820
- const plugin$2 = (0, fastify_plugin.default)((fastify, options) => {
2821
- const { getBundler } = options;
2822
- const getBundleOptions = (buildOptions) => {
2823
- return {
2824
- platform: buildOptions.platform,
2825
- dev: buildOptions.dev,
2826
- minify: buildOptions.minify,
2827
- sourcemap: buildOptions.inlineSourceMap ? "inline" : true
2828
- };
2829
- };
2830
- fastify.get("/:name.bundle", {
2831
- schema: {
2832
- params: routeParamSchema,
2833
- querystring: bundleRequestSchema
2834
- },
2835
- async handler(request, reply) {
2836
- const { params, query, headers: { accept } } = request;
2837
- if (!params.name) {
2838
- await reply.status(400).send("invalid bundle name");
2839
- return;
2840
- }
2841
- const buildOptions = getBundleOptions(query);
2842
- const bundler = getBundler(params.name, buildOptions);
2843
- if (accept?.includes("multipart/mixed") ?? false) {
2844
- const bundleResponse = new BundleResponse(reply);
2845
- const transformHandler = (_id, totalModules = 0, transformedModules) => {
2846
- bundleResponse.writeBundleState(transformedModules, totalModules);
2847
- };
2848
- bundler.on("transform", transformHandler);
2849
- await bundler.getBundle().then((bundle) => bundleResponse.endWithBundle(bundle.code)).catch((error) => bundleResponse.endWithError(error)).finally(() => bundler.off("transform", transformHandler));
2850
- } else {
2851
- this.log.debug(`client is not support multipart/mixed content: ${accept ?? "<empty>"}`);
2852
- const code = (await withGetBundleErrorHandler(reply, bundler.getBundle())).code;
2853
- await reply.header("Content-Type", "application/javascript").header("Content-Length", Buffer.byteLength(code)).status(200).send(code);
2854
- }
2855
- }
2856
- });
2857
- fastify.get("/:name.map", {
2858
- schema: {
2859
- params: routeParamSchema,
2860
- querystring: bundleRequestSchema
2861
- },
2862
- async handler(request, reply) {
2863
- const { params, query } = request;
2864
- if (!params.name) {
2865
- await reply.status(400).send("invalid bundle name");
2866
- return;
2867
- }
2868
- const buildOptions = getBundleOptions(query);
2869
- const sourceMap = (await withGetBundleErrorHandler(reply, getBundler(params.name, buildOptions).getBundle())).sourceMap;
2870
- (0, es_toolkit.invariant)(sourceMap, "Source map is not available");
2871
- await reply.header("Access-Control-Allow-Origin", "devtools://devtools").header("Content-Type", "application/json").header("Content-Length", Buffer.byteLength(sourceMap)).status(200).send(sourceMap);
2872
- }
2873
- });
2874
- }, { name: "serve-bundle" });
2875
- //#endregion
2876
- //#region src/server/middlewares/sse.ts
2877
- const plugin$1 = (0, fastify_plugin.default)((fastify, { eventBus }) => {
2878
- fastify.get("/sse/events", (request, reply) => {
2879
- const res = reply.raw;
2880
- res.writeHead(200, {
2881
- Connection: "keep-alive",
2882
- "Content-Type": "text/event-stream",
2883
- "Cache-Control": "no-cache",
2884
- "X-Accel-Buffering": "no"
2885
- });
2886
- request.raw.socket.setNoDelay(true);
2887
- res.write(":ok\n\n");
2888
- eventBus.addClient(res);
2889
- request.raw.on("close", () => eventBus.removeClient(res));
2890
- });
2891
- }, { name: "sse" });
2892
- //#endregion
2893
- //#region src/utils/url.ts
2894
- function parseUrl(value) {
2895
- if (value.startsWith("/")) {
2896
- const [pathname, query] = value.split("?");
2897
- return {
2898
- pathname,
2899
- query: query ? toQueryObject(new URLSearchParams(query)) : {}
2900
- };
2901
- }
2902
- const url = new URL(value);
2903
- return {
2904
- pathname: url.pathname,
2905
- query: toQueryObject(url.searchParams)
2906
- };
2907
- }
2908
- function toQueryObject(searchParams) {
2909
- return searchParams.entries().reduce((acc, [key, value]) => ({
2910
- ...acc,
2911
- [key]: value
2912
- }), {});
2913
- }
2914
- //#endregion
2915
- //#region src/server/symbolicate.ts
2916
- /**
2917
- * @see https://github.com/facebook/react-native/blob/0.83-stable/packages/metro-config/src/index.flow.js#L17
2918
- */
2919
- const INTERNAL_CALLSITES_REGEX = new RegExp([
2920
- "/Libraries/BatchedBridge/MessageQueue\\.js$",
2921
- "/Libraries/Core/.+\\.js$",
2922
- "/Libraries/LogBox/.+\\.js$",
2923
- "/Libraries/Network/.+\\.js$",
2924
- "/Libraries/Pressability/.+\\.js$",
2925
- "/Libraries/Renderer/implementations/.+\\.js$",
2926
- "/Libraries/Utilities/.+\\.js$",
2927
- "/Libraries/vendor/.+\\.js$",
2928
- "/Libraries/WebSocket/.+\\.js$",
2929
- "/src/private/renderer/errorhandling/.+\\.js$",
2930
- "/metro-runtime/.+\\.js$",
2931
- "/node_modules/@babel/runtime/.+\\.js$",
2932
- "/node_modules/@react-native/js-polyfills/.+\\.js$",
2933
- "/node_modules/invariant/.+\\.js$",
2934
- "/node_modules/react-devtools-core/.+\\.js$",
2935
- "/node_modules/react-native/index.js$",
2936
- "/node_modules/react-refresh/.+\\.js$",
2937
- "/node_modules/scheduler/.+\\.js$",
2938
- "^\\[native code\\]$"
2939
- ].map((pathPattern) => pathPattern.replaceAll("/", "[/\\\\]")).join("|"));
2940
- async function symbolicate(bundleStore, stack) {
2941
- const sourceMapConsumer = await bundleStore.sourceMapConsumer;
2942
- const symbolicatedStack = stack.filter((frame) => frame.file?.startsWith("http")).map((frame) => sourceMapConsumer ? originalPositionFor(sourceMapConsumer, frame) : frame).map((frame) => collapseFrame(frame));
2943
- return {
2944
- stack: symbolicatedStack,
2945
- codeFrame: getCodeFrame(symbolicatedStack, bundleStore, sourceMapConsumer)
2946
- };
2947
- }
2948
- function originalPositionFor(sourceMapConsumer, frame) {
2949
- if (frame.column == null || frame.lineNumber == null) return frame;
2950
- const originalPosition = sourceMapConsumer.originalPositionFor({
2951
- column: frame.column,
2952
- line: frame.lineNumber
2953
- });
2954
- return Object.entries(originalPosition).reduce((frame, [key, value]) => {
2955
- const targetKey = convertFrameKey(key);
2956
- return {
2957
- ...frame,
2958
- ...value ? { [targetKey]: value } : null
2959
- };
2960
- }, frame);
2961
- }
2962
- function collapseFrame(frame) {
2963
- return {
2964
- ...frame,
2965
- collapse: Boolean(frame.file && INTERNAL_CALLSITES_REGEX.test(frame.file))
2966
- };
2967
- }
2968
- function isCollapsed(frame) {
2969
- return "collapse" in frame && frame.collapse;
2970
- }
2971
- function convertFrameKey(key) {
2972
- if (key === "line") return "lineNumber";
2973
- else if (key === "source") return "file";
2974
- else if (key === "name") return "methodName";
2975
- return key;
2976
- }
2977
- function getCodeFrame(frames, bundleStore, sourceMapConsumer) {
2978
- const frame = frames.find((frame) => {
2979
- return frame.lineNumber != null && frame.column != null && !isCollapsed(frame);
2980
- });
2981
- if (frame?.file == null || frame.column == null || frame.lineNumber == null) return null;
2982
- try {
2983
- const { lineNumber, column, file } = frame;
2984
- const unresolved = file.startsWith("http");
2985
- const source = sourceMapConsumer == null || unresolved ? bundleStore.code : sourceMapConsumer.sourceContentFor(frame.file);
2986
- const fileName = unresolved ? parseUrl(file).pathname ?? "unknown" : file;
2987
- let content = "";
2988
- if (source) content = (0, _babel_code_frame.codeFrameColumns)(source, { start: {
2989
- column,
2990
- line: lineNumber
2991
- } }, { highlightCode: true });
2992
- return {
2993
- content,
2994
- fileName,
2995
- location: {
2996
- column,
2997
- row: lineNumber
2998
- }
2999
- };
3000
- } catch {
3001
- return null;
3002
- }
3003
- }
3004
- //#endregion
3005
- //#region src/server/middlewares/symbolicate.ts
3006
- const bodySchema = (0, json_schema_to_ts.asConst)({
3007
- type: "object",
3008
- properties: {
3009
- stack: {
3010
- type: "array",
3011
- items: {}
3012
- },
3013
- extraData: {}
3014
- },
3015
- required: ["stack"]
3016
- });
3017
- const plugin = (0, fastify_plugin.default)((fastify, options) => {
3018
- const { getBundler } = options;
3019
- fastify.post("/symbolicate", {
3020
- schema: { body: bodySchema },
3021
- async handler(request, reply) {
3022
- const { stack } = request.body;
3023
- const bundleUrl = stack.find((frame) => frame.file?.startsWith("http"));
3024
- (0, es_toolkit.invariant)(bundleUrl?.file, "No bundle URL found in stack frames");
3025
- const { pathname, query } = parseUrl(bundleUrl.file);
3026
- (0, es_toolkit.invariant)(pathname, "No pathname found in bundle URL");
3027
- (0, es_toolkit.invariant)(query.platform, "No platform found in query");
3028
- (0, es_toolkit.invariant)(query.dev, "No dev found in query");
3029
- const symbolicateResult = await symbolicate(await getBundler(getBaseBundleName(pathname), {
3030
- platform: query.platform,
3031
- dev: query.dev === "true"
3032
- }).getBundle(), stack);
3033
- if (isDebugEnabled()) printSymbolicateResult(stack, symbolicateResult);
3034
- await reply.header("Content-Type", "application/json").send(symbolicateResult);
3035
- }
3036
- });
3037
- }, { name: "symbolicate" });
3038
- function printSymbolicateResult(rawStackFrame, symbolicateResult) {
3039
- console.log();
3040
- console.log("Symbolicate result:");
3041
- console.log();
3042
- if (symbolicateResult.codeFrame != null) {
3043
- console.log(symbolicateResult.codeFrame.content);
3044
- console.log();
3045
- }
3046
- console.log("Stack trace:");
3047
- symbolicateResult.stack.forEach((stackFrame) => {
3048
- const symbol = stackFrame.methodName ?? "<anonymous>";
3049
- const file = stackFrame.file ?? "unknown";
3050
- const location = stackFrame.lineNumber != null && stackFrame.column != null ? `(${chalk.default.gray.underline(`${file}:${stackFrame.lineNumber}:${stackFrame.column}`)})` : "";
3051
- console.log(` at ${symbol} ${location}`);
3052
- });
3053
- console.log();
3054
- console.log("Raw stack trace:");
3055
- rawStackFrame.filter((stackFrame) => stackFrame.file?.startsWith("http")).forEach((stackFrame) => {
3056
- const bundleName = new URL(stackFrame.file).pathname.slice(1);
3057
- const symbol = stackFrame.methodName ?? "<anonymous>";
3058
- const location = stackFrame.lineNumber != null && stackFrame.column != null ? `(${chalk.default.gray.underline(`${bundleName}:${stackFrame.lineNumber}:${stackFrame.column}`)})` : "";
3059
- console.log(` at ${symbol} ${location}`);
3060
- });
3061
- console.log();
3062
- }
3063
- //#endregion
3064
- //#region src/server/sse/event-bus.ts
3065
- var SSEEventBus = class {
3066
- clients = /* @__PURE__ */ new Set();
3067
- listeners = /* @__PURE__ */ new Set();
3068
- emit(event) {
3069
- const data = JSON.stringify(event);
3070
- const message = `event: ${event.type}\ndata: ${data}\n\n`;
3071
- for (const client of this.clients) if (!client.closed) client.write(message);
3072
- for (const listener of this.listeners) listener(event);
3073
- }
3074
- /**
3075
- * Subscribe an SSE HTTP response client.
3076
- */
3077
- addClient(res) {
3078
- this.clients.add(res);
3079
- }
3080
- /**
3081
- * Unsubscribe an SSE HTTP response client.
3082
- */
3083
- removeClient(res) {
3084
- this.clients.delete(res);
3085
- }
3086
- /**
3087
- * Subscribe a listener that collects events into the given array.
3088
- * Returns an unsubscribe function.
3089
- */
3090
- collect(collector) {
3091
- const listener = (event) => collector.push(event);
3092
- this.listeners.add(listener);
3093
- return () => this.listeners.delete(listener);
3094
- }
3095
- get clientCount() {
3096
- return this.clients.size;
3097
- }
3098
- };
3099
- //#endregion
3100
- //#region src/server/sse/reporter.ts
3101
- function toSSEEvent(id, event) {
3102
- switch (event.type) {
3103
- case "bundle_build_started": return {
3104
- type: "bundle_build_started",
3105
- id
3106
- };
3107
- case "bundle_build_done": return {
3108
- type: "bundle_build_done",
3109
- id,
3110
- totalModules: event.totalModules,
3111
- duration: event.duration
3112
- };
3113
- case "bundle_build_failed": return {
3114
- type: "bundle_build_failed",
3115
- id,
3116
- error: (0, strip_ansi.default)(event.error.message)
3117
- };
3118
- case "watch_change": return {
3119
- type: "watch_change",
3120
- id,
3121
- file: event.id
3122
- };
3123
- case "client_log": return {
3124
- type: "client_log",
3125
- data: event.data
3126
- };
3127
- case "transform": return null;
3128
- }
3129
- }
3130
- //#endregion
3131
- //#region src/server/wss/server.ts
3132
- var WebSocketServer = class extends node_events.default {
3133
- clientId = 0;
3134
- wss;
3135
- logger;
3136
- constructor(name, options) {
3137
- super();
3138
- const logger = logger$1.child(name);
3139
- const wss = new ws.WebSocketServer(options);
3140
- wss.on("connection", (socket) => {
3141
- const client = Object.defineProperty(socket, "id", {
3142
- value: this.clientId++,
3143
- writable: false
3144
- });
3145
- this.onConnection(client);
3146
- this.emit("connection", client);
3147
- client.on("message", (data) => {
3148
- this.onMessage(client, data);
3149
- this.emit("message", client, data);
3150
- });
3151
- client.on("error", (error) => {
3152
- this.onError(client, error);
3153
- this.emit("error", client, error);
3154
- });
3155
- client.on("close", () => {
3156
- this.onClose(client);
3157
- this.emit("close", client);
3158
- });
3159
- });
3160
- this.wss = wss;
3161
- this.logger = logger;
3162
- }
3163
- get server() {
3164
- return this.wss;
3165
- }
3166
- send(client, data) {
3167
- if (client.readyState === ws.WebSocket.OPEN) client.send(data);
3168
- }
3169
- sendAll(data) {
3170
- this.wss.clients.forEach((client) => {
3171
- if (client.readyState === ws.WebSocket.OPEN) client.send(data);
3172
- });
3173
- }
3174
- rawDataToString(data) {
3175
- if (Buffer.isBuffer(data)) return data.toString("utf8");
3176
- if (Array.isArray(data)) return Buffer.concat(data).toString("utf8");
3177
- return Buffer.from(data).toString("utf8");
3178
- }
3179
- };
3180
- function getWebSocketUpgradeHandler(websocketEndpoints) {
3181
- return (request, socket, head) => {
3182
- if (request.url == null) {
3183
- socket.destroy();
3184
- return;
3185
- }
3186
- const { pathname } = parseUrl(request.url);
3187
- if (pathname != null && websocketEndpoints[pathname]) {
3188
- const wss = websocketEndpoints[pathname];
3189
- wss.handleUpgrade(request, socket, head, (socket) => {
3190
- wss.emit("connection", socket, request);
3191
- });
3192
- } else socket.destroy();
3193
- };
3194
- }
3195
- //#endregion
3196
- //#region src/server/wss/hmr-server.ts
3197
- var HMRServer = class extends WebSocketServer {
3198
- bundlerPool;
3199
- reportEvent;
3200
- instances = /* @__PURE__ */ new Map();
3201
- bindings = /* @__PURE__ */ new Map();
3202
- constructor({ bundlerPool, reportEvent }) {
3203
- super("hmr", { noServer: true });
3204
- this.bundlerPool = bundlerPool;
3205
- this.reportEvent = reportEvent;
3206
- }
3207
- parseClientMessage(data) {
3208
- const parsedData = JSON.parse(this.rawDataToString(data));
3209
- const clientMessage = "type" in parsedData ? parsedData : null;
3210
- (0, es_toolkit.invariant)(clientMessage, "Invalid HMR client message");
3211
- return clientMessage;
3212
- }
3213
- async handleConnected(client, platform, bundleEntry) {
3214
- try {
3215
- this.logger.trace(`HMR client connected (clientId: ${client.id})`, {
3216
- platform,
3217
- bundleEntry
3218
- });
3219
- const devEngineInstance = this.bundlerPool.get(bundleEntry, {
3220
- platform,
3221
- dev: true
3222
- });
3223
- this.bindEvents(client, devEngineInstance);
3224
- this.instances.set(client.id, devEngineInstance);
3225
- this.logger.trace(`Bundler instance prepared (bundlerId: ${devEngineInstance.id})`);
3226
- } catch (error) {
3227
- this.logger.error(`Failed to prepare bundler instance`, error);
3228
- }
3229
- }
3230
- bindEvents(client, instance) {
3231
- if (this.bindings.get(client.id) == null) {
3232
- const handleHmrUpdates = (updates) => {
3233
- this.handleUpdates(client, updates);
3234
- };
3235
- const handleWatchChange = () => {
3236
- this.send(client, JSON.stringify({ type: "hmr:update-start" }));
3237
- };
3238
- const handleBuildFailed = (error) => {
3239
- this.send(client, JSON.stringify({
3240
- type: "hmr:error",
3241
- payload: {
3242
- type: "BuildError",
3243
- errors: [{ description: error.message }],
3244
- message: error.message
3245
- }
3246
- }));
3247
- };
3248
- instance.addListener("hmrUpdates", handleHmrUpdates);
3249
- instance.addListener("watchChange", handleWatchChange);
3250
- instance.addListener("buildFailed", handleBuildFailed);
3251
- this.bindings.set(client.id, {
3252
- hmrUpdates: handleHmrUpdates,
3253
- watchChange: handleWatchChange,
3254
- buildFailed: handleBuildFailed
3255
- });
3256
- this.logger.trace(`HMR event binding established (clientId: ${client.id})`);
3257
- }
3258
- }
3259
- async handleModuleRegistered(client, modules) {
3260
- try {
3261
- const instance = this.instances.get(client.id);
3262
- (0, es_toolkit.invariant)(instance != null, `Bundler instance not found for client clientId: ${client.id}`);
3263
- await instance.ensureInitialized;
3264
- await instance.devEngine.registerModules(client.id.toString(), modules);
3265
- } catch (error) {
3266
- this.logger.error(`Failed to handle module registered`, error);
3267
- }
3268
- }
3269
- async handleInvalidate(client, moduleId) {
3270
- try {
3271
- const instance = this.instances.get(client.id);
3272
- (0, es_toolkit.invariant)(instance != null, `Bundler instance not found for client clientId: ${client.id}`);
3273
- await instance.ensureInitialized;
3274
- const updates = await instance.devEngine.invalidate(moduleId);
3275
- await this.handleUpdates(client, updates);
3276
- } catch (error) {
3277
- this.logger.error(`Failed to handle invalidate`, error);
3278
- }
3279
- }
3280
- async handleUpdates(client, updates) {
3281
- this.logger.trace(`HMR updates found (clientId: ${client.id})`, { updatesCount: updates.length });
3282
- for (const clientUpdate of updates) {
3283
- const update = clientUpdate.update;
3284
- switch (update.type) {
3285
- case "Patch":
3286
- this.sendUpdateToClient(client, update);
3287
- break;
3288
- case "FullReload":
3289
- this.sendReloadToClient(client);
3290
- break;
3291
- case "Noop":
3292
- this.logger.warn(`Client ${clientUpdate.clientId} received noop update`);
3293
- break;
3294
- }
3295
- }
3296
- }
3297
- sendUpdateToClient(client, update) {
3298
- (0, es_toolkit.invariant)(update.type === "Patch", "Invalid HMR update type");
3299
- const updateMessage = {
3300
- type: "hmr:update",
3301
- code: update.code
3302
- };
3303
- this.send(client, JSON.stringify(updateMessage));
3304
- this.done(client);
3305
- }
3306
- sendReloadToClient(client) {
3307
- this.logger.trace(`Sending HMR reload message to client (clientId: ${client.id})`);
3308
- this.send(client, JSON.stringify({ type: "hmr:reload" }));
3309
- this.done(client);
3310
- }
3311
- done(client) {
3312
- this.send(client, JSON.stringify({ type: "hmr:update-done" }));
3313
- }
3314
- sendError(client, error) {
3315
- try {
3316
- this.send(client, JSON.stringify(error));
3317
- } catch (error) {
3318
- this.logger.error(`Failed to send HMR error message to client (clientId: ${client.id})`, error);
3319
- }
3320
- }
3321
- cleanup(client) {
3322
- this.logger.trace(`HMR client cleanup (clientId: ${client.id})`);
3323
- const binding = this.bindings.get(client.id);
3324
- const instance = this.instances.get(client.id);
3325
- if (binding != null && instance != null) {
3326
- instance.removeListener("hmrUpdates", binding.hmrUpdates);
3327
- instance.removeListener("watchChange", binding.watchChange);
3328
- instance.removeListener("buildFailed", binding.buildFailed);
3329
- }
3330
- if (instance != null) try {
3331
- instance.devEngine.removeClient(String(client.id));
3332
- } catch (error) {
3333
- this.logger.warn(`Skipped devEngine.removeClient for client ${client.id}: ` + (error instanceof Error ? error.message : String(error)));
3334
- }
3335
- this.bindings.delete(client.id);
3336
- this.instances.delete(client.id);
3337
- }
3338
- onMessage(client, data) {
3339
- let message;
3340
- try {
3341
- message = this.parseClientMessage(data);
3342
- let traceMessage = message;
3343
- if (message.type === "hmr:module-registered") traceMessage = {
3344
- ...message,
3345
- modules: `[${message.modules.length} modules]`
3346
- };
3347
- else if (message.type === "hmr:log") traceMessage = {
3348
- ...message,
3349
- data: `(${message.data.length} items)`
3350
- };
3351
- this.logger.trace("HMR client message received", traceMessage);
3352
- } catch (error) {
3353
- const message = "Failed to parse HMR client message";
3354
- this.logger.error(message, error);
3355
- this.sendError(client, {
3356
- type: "InternalError",
3357
- errors: [{ description: error instanceof Error ? error.message : String(error) }],
3358
- message
3359
- });
3360
- return;
3361
- }
3362
- if (isCustomHMRMessage(message)) {
3363
- this.wss.emit(message.type, message.payload);
3364
- return;
3365
- }
3366
- switch (message.type) {
3367
- case "hmr:connected":
3368
- this.handleConnected(client, message.platform, message.bundleEntry);
3369
- break;
3370
- case "hmr:module-registered":
3371
- this.handleModuleRegistered(client, message.modules);
3372
- break;
3373
- case "hmr:invalidate":
3374
- this.handleInvalidate(client, message.moduleId);
3375
- break;
3376
- case "hmr:log":
3377
- this.reportEvent({
3378
- type: "client_log",
3379
- level: message.level,
3380
- data: message.data
3381
- });
3382
- break;
3383
- }
3384
- }
3385
- onConnection(client) {
3386
- this.logger.trace(`connection established (clientId: ${client.id})`);
3387
- }
3388
- onError(client, error) {
3389
- this.logger.error(`connection error (clientId: ${client.id})`, error);
3390
- this.cleanup(client);
3391
- }
3392
- onClose(client) {
3393
- this.logger.trace(`connection closed (clientId: ${client.id})`);
3394
- this.cleanup(client);
3395
- }
3396
- };
3397
- function isCustomHMRMessage(message) {
3398
- if (typeof message !== "object" || message == null) return false;
3399
- if ("type" in message && typeof message.type === "string" && message.type.startsWith("hmr:")) return false;
3400
- return true;
3401
- }
3402
- //#endregion
3403
- //#region src/server/create-dev-server.ts
3404
- async function createDevServer(config, options) {
3405
- const projectRoot = config.root;
3406
- const { port = DEFAULT_PORT, host = DEFAULT_HOST, https = false } = options ?? {};
3407
- if (https) throw new Error("HTTPS is not supported yet");
3408
- const serverBaseUrl = url.default.format({
3409
- protocol: https ? "https" : "http",
3410
- hostname: host,
3411
- port
3412
- });
3413
- await assertDevServerStatus({
3414
- devServerUrl: serverBaseUrl,
3415
- projectRoot,
3416
- port
3417
- });
3418
- const emitter = (0, mitt.default)();
3419
- const fastify$1 = (0, fastify.default)({
3420
- loggerInstance: new DevServerLogger(),
3421
- disableRequestLogging: true
3422
- });
3423
- const sseEventBus = new SSEEventBus();
3424
- const bundlerPool = new BundlerPool(config, {
3425
- host,
3426
- port
3427
- }, (id, event) => {
3428
- const sseEvent = toSSEEvent(id, event);
3429
- if (sseEvent) sseEventBus.emit(sseEvent);
3430
- });
3431
- const getBundler = (bundleName, buildOptions) => {
3432
- return bundlerPool.get(bundleName, (0, es_toolkit.merge)(options?.buildOptions ?? {}, buildOptions));
3433
- };
3434
- const { middleware: communityMiddleware, websocketEndpoints: communityWebsocketEndpoints, messageSocketEndpoint: { server: messageServer, broadcast }, eventsSocketEndpoint: { server: eventsServer, reportEvent } } = (0, _react_native_community_cli_server_api.createDevServerMiddleware)({
3435
- port,
3436
- host,
3437
- watchFolders: []
3438
- });
3439
- const { middleware: devMiddleware, websocketEndpoints } = (0, _react_native_dev_middleware.createDevMiddleware)({
3440
- serverBaseUrl,
3441
- logger: {
3442
- info(...args) {
3443
- if (args[0].includes("JavaScript logs have moved")) return;
3444
- logger$1.info(...args);
3445
- },
3446
- warn: logger$1.warn.bind(logger$1),
3447
- error: logger$1.error.bind(logger$1)
3448
- },
3449
- unstable_experiments: {
3450
- enableNetworkInspector: true,
3451
- enableStandaloneFuseboxShell: true
3452
- }
3453
- });
3454
- const hmrServer = new HMRServer({
3455
- bundlerPool,
3456
- reportEvent: (event) => {
3457
- reportEvent?.(event);
3458
- config.reporter?.update(event);
3459
- }
3460
- }).on("connection", (client) => {
3461
- emitter.emit("device.connected", { client });
3462
- sseEventBus.emit({
3463
- type: "device_connected",
3464
- clientId: client.id
3465
- });
3466
- }).on("message", (client, data) => emitter.emit("device.message", {
3467
- client,
3468
- data
3469
- })).on("error", (client, error) => emitter.emit("device.error", {
3470
- client,
3471
- error
3472
- })).on("close", (client) => {
3473
- emitter.emit("device.disconnected", { client });
3474
- sseEventBus.emit({
3475
- type: "device_disconnected",
3476
- clientId: client.id
3477
- });
3478
- });
3479
- await fastify$1.register(import("@fastify/middie"));
3480
- const devServer = {
3481
- ...emitter,
3482
- config,
3483
- instance: fastify$1,
3484
- middlewares: { use: fastify$1.use.bind(fastify$1) },
3485
- message: Object.assign(messageServer, { broadcast }),
3486
- events: Object.assign(eventsServer, { reportEvent }),
3487
- hot: Object.assign(hmrServer.server, {
3488
- send: (client, eventName, payload) => {
3489
- hmrServer.send(client, JSON.stringify({
3490
- type: eventName,
3491
- payload
3492
- }));
3493
- },
3494
- sendAll: (eventName, payload) => {
3495
- hmrServer.sendAll(JSON.stringify({
3496
- type: eventName,
3497
- payload
3498
- }));
3499
- }
3500
- })
3501
- };
3502
- const { invokePostConfigureServer } = await invokeConfigureServer(devServer, config.plugins ?? []);
3503
- fastify$1.use(requestLogger).use(communityMiddleware).use(devMiddleware).register(plugin$1, { eventBus: sseEventBus }).register(plugin$4, {
3504
- projectRoot,
3505
- eventBus: sseEventBus
3506
- }).register(plugin$5, { bundlerPool }).register(plugin$6, {
3507
- projectRoot,
3508
- eventBus: sseEventBus
3509
- }).register(plugin, { getBundler }).register(plugin$2, { getBundler }).register(plugin$3, {
3510
- projectRoot,
3511
- host,
3512
- port,
3513
- https,
3514
- preferNativePlatform: config.resolver.preferNativePlatform
3515
- }).setErrorHandler(errorHandler);
3516
- fastify$1.server.on("upgrade", getWebSocketUpgradeHandler({
3517
- ...communityWebsocketEndpoints,
3518
- ...websocketEndpoints,
3519
- "/hot": hmrServer.server
3520
- }));
3521
- await invokePostConfigureServer();
3522
- sseEventBus.emit({
3523
- type: "server_ready",
3524
- host,
3525
- port
3526
- });
3527
- return devServer;
3528
- }
3529
- async function invokeConfigureServer(server, plugins) {
3530
- const postConfigureServerHandlers = [];
3531
- for (const plugin of plugins) {
3532
- const context = createPluginContext(plugin.name);
3533
- const result = await plugin.configureServer?.call(context, server);
3534
- if (typeof result === "function") postConfigureServerHandlers.push(result);
3535
- }
3536
- return { invokePostConfigureServer: async () => {
3537
- for (const handler of postConfigureServerHandlers) await handler();
3538
- } };
3539
- }
3540
- //#endregion
3541
- //#region src/node/commands/agent/action.ts
3542
- const defaultBaseUrl = `http://${DEFAULT_HOST}:${DEFAULT_PORT}`;
3543
- function getAgentGuide(baseUrl = defaultBaseUrl) {
3544
- return [
3545
- "Rollipop Agent Guide",
3546
- "",
3547
- "Rollipop exposes build and runtime diagnostics through SSE and MCP.",
3548
- "Keep the dev server running, then connect your agent to one of these endpoints.",
3549
- "",
3550
- "Start the dev server:",
3551
- "",
3552
- " rollipop start --reset-cache",
3553
- "",
3554
- "Default endpoints:",
3555
- "",
3556
- ` SSE events: ${baseUrl}/sse/events`,
3557
- ` MCP server: ${baseUrl}/mcp`,
3558
- ` Reset cache: ${baseUrl}/reset-cache`,
3559
- ` Bundler status: ${baseUrl}/bundlers/<id>/status`,
3560
- "",
3561
- "If you start Rollipop with custom --host, --port, or --https options,",
3562
- "adjust these URLs to match the running dev server.",
3563
- "",
3564
- "SSE usage:",
3565
- "",
3566
- ` curl -N ${baseUrl}/sse/events`,
3567
- "",
3568
- " Event format:",
3569
- " event: <event_type>",
3570
- " data: <json_payload>",
3571
- "",
3572
- " Useful event types:",
3573
- " bundle_build_started, bundle_build_done, bundle_build_failed",
3574
- " watch_change, client_log, device_connected, device_disconnected",
3575
- " server_ready, cache_reset",
3576
- "",
3577
- "MCP setup:",
3578
- "",
3579
- " Add this to your project .mcp.json:",
3580
- "",
3581
- " {",
3582
- " \"mcpServers\": {",
3583
- " \"rollipop\": {",
3584
- " \"type\": \"http\",",
3585
- ` "url": "${baseUrl}/mcp"`,
3586
- " }",
3587
- " }",
3588
- " }",
3589
- "",
3590
- " Available tools:",
3591
- " get_build_events({ \"duration\": 10000 })",
3592
- " reset_cache()",
3593
- "",
3594
- "Agent workflow:",
3595
- "",
3596
- " 1. Run rollipop start and keep it running.",
3597
- " 2. Use get_build_events or subscribe to SSE before and after edits.",
3598
- " 3. Wait for bundle_build_done or bundle_build_failed.",
3599
- " 4. If the build fails, inspect the error payload, fix the code, and repeat.",
3600
- " 5. Use reset_cache or /reset-cache when stale cache is suspected."
3601
- ].join("\n");
3602
- }
3603
- const action$2 = async () => {
3604
- console.log(getAgentGuide());
3605
- };
3606
- //#endregion
3607
- //#region src/node/commands/agent/command.ts
3608
- const command$2 = {
3609
- name: "agent",
3610
- description: "Print guidance for connecting LLM agents to Rollipop diagnostics.",
3611
- helpText: getAgentGuide(),
3612
- action: action$2
3613
- };
3614
- //#endregion
3615
- //#region src/node/constants.ts
3616
- const UNSUPPORTED_OPTION_DESCRIPTION = "This option is not supported by Rollipop.";
3617
- //#endregion
3618
- //#region src/config/defaults.ts
3619
- async function getDefaultConfig(projectRoot, mode) {
3620
- let reactNativePath;
3621
- try {
3622
- reactNativePath = process.env.ROLLIPOP_REACT_NATIVE_PATH ?? resolvePackagePath(projectRoot, "react-native");
3623
- } catch {
3624
- throw new Error(`Could not resolve 'react-native' package path. Please check your project path.`);
3625
- }
3626
- return {
3627
- root: projectRoot,
3628
- mode: mode ?? "development",
3629
- entry: "index.js",
3630
- resolver: {
3631
- sourceExtensions: DEFAULT_SOURCE_EXTENSIONS,
3632
- assetExtensions: DEFAULT_ASSET_EXTENSIONS,
3633
- mainFields: DEFAULT_RESOLVER_MAIN_FIELDS,
3634
- aliasFields: DEFAULT_RESOLVER_ALIAS_FIELDS,
3635
- conditionNames: DEFAULT_RESOLVER_CONDITION_NAMES,
3636
- preferNativePlatform: true,
3637
- symlinks: true
3638
- },
3639
- transformer: { flow: { filter: {
3640
- id: /\.jsx?$/,
3641
- code: /@flow/
3642
- } } },
3643
- serializer: {
3644
- prelude: [getInitializeCorePath(projectRoot)],
3645
- polyfills: await Promise.all(getPolyfillScriptPaths(reactNativePath).map(async (path) => {
3646
- return {
3647
- type: "iife",
3648
- code: (await stripFlowTypes(path, node_fs.default.readFileSync(path, "utf-8"))).code
3649
- };
3650
- }))
3651
- },
3652
- watcher: {
3653
- skipWrite: true,
3654
- useDebounce: true,
3655
- debounceDuration: 50
3656
- },
3657
- optimization: { treeshake: true },
3658
- reactNative: {
3659
- reactNativePath,
3660
- codegen: { filter: { code: /\bcodegenNativeComponent</ } },
3661
- assetRegistryPath: DEFAULT_ASSET_REGISTRY_PATH,
3662
- hmrClientPath: DEFAULT_HMR_CLIENT_PATH,
3663
- globalIdentifiers: DEFAULT_REACT_NATIVE_GLOBAL_IDENTIFIERS
3664
- },
3665
- devMode: { hmr: true },
3666
- reporter: new ClientLogReporter(),
3667
- terminal: { status: (() => {
3668
- if (isDebugEnabled()) return "compat";
3669
- if (process.stderr.isTTY) return "progress";
3670
- return "compat";
3671
- })() },
3672
- envDir: projectRoot,
3673
- envFile: DEFAULT_ENV_FILE,
3674
- envPrefix: DEFAULT_ENV_PREFIX,
3675
- runtimeTarget: DEFAULT_RUNTIME_TARGET,
3676
- experimental: { nativeTransformPipeline: false }
3677
- };
3678
- }
3679
- //#endregion
3680
- //#region src/config/merge-config.ts
3681
- function mergeConfig(baseConfig, ...overrideConfigs) {
3682
- let mergedConfig = baseConfig;
3683
- for (const overrideConfig of overrideConfigs) mergedConfig = (0, es_toolkit.mergeWith)(mergedConfig, overrideConfig, (target, source, key) => {
3684
- if ([
3685
- "sourceExtensions",
3686
- "assetExtensions",
3687
- "polyfills",
3688
- "prelude",
3689
- "plugins"
3690
- ].includes(key)) return Array.from(new Set([...target ?? [], ...source ?? []]));
3691
- if (key === "reporter") return source ?? target;
3692
- if (key === "dangerously_overrideRolldownOptions") return composeOverrideRolldownOptions(target, source);
3693
- });
3694
- return mergedConfig;
3695
- }
3696
- //#endregion
3697
- //#region src/config/load-config.ts
3698
- const CONFIG_FILE_NAME = "rollipop";
3699
- async function loadConfig(options = {}) {
3700
- const { cwd = process.cwd(), configFile, mode, context = {} } = options;
3701
- const defaultConfig = await getDefaultConfig(cwd, mode);
3702
- const commonOptions = {
3703
- context: {
3704
- ...context,
3705
- defaultConfig
3706
- },
3707
- rcFile: false
3708
- };
3709
- const { config: userConfig } = await c12.loadConfig(configFile ? {
3710
- configFile: node_path.default.resolve(cwd, configFile),
3711
- configFileRequired: true
3712
- } : {
3713
- cwd,
3714
- defaultConfig,
3715
- name: CONFIG_FILE_NAME,
3716
- ...commonOptions
3717
- });
3718
- const plugins = await flattenPluginOption(userConfig.plugins);
3719
- const resolvedConfig = {
3720
- ...await resolvePluginConfig(mergeConfig(defaultConfig, {
3721
- ...userConfig,
3722
- plugins
3723
- }), plugins),
3724
- plugins
3725
- };
3726
- await invokeConfigResolved(resolvedConfig, plugins);
3727
- return resolvedConfig;
3728
- }
3729
- async function flattenPluginOption(pluginOption) {
3730
- const awaitedPluginOption = await pluginOption;
3731
- if (Array.isArray(awaitedPluginOption)) return (await Promise.all(awaitedPluginOption.map(flattenPluginOption))).flat();
3732
- if (awaitedPluginOption == null || awaitedPluginOption === false) return [];
3733
- return [awaitedPluginOption];
3734
- }
3735
- async function resolvePluginConfig(baseConfig, plugins) {
3736
- let mergedConfig = (0, es_toolkit.omit)(baseConfig, ["plugins"]);
3737
- for (const plugin of plugins) {
3738
- const context = createPluginContext(plugin.name);
3739
- const overrideBefore = mergedConfig.dangerously_overrideRolldownOptions;
3740
- if (typeof plugin.config === "function") {
3741
- const config = await plugin.config.call(context, mergedConfig);
3742
- if (config != null) mergedConfig = mergeConfig(mergedConfig, config);
3743
- } else if (typeof plugin.config === "object") mergedConfig = mergeConfig(mergedConfig, plugin.config);
3744
- const overrideAfter = mergedConfig.dangerously_overrideRolldownOptions;
3745
- if (overrideAfter != null && overrideAfter !== overrideBefore) context.debug({ message: `set 'dangerously_overrideRolldownOptions'` });
3746
- }
3747
- return mergedConfig;
3748
- }
3749
- async function invokeConfigResolved(config, plugins) {
3750
- await Promise.all(plugins.map((plugin) => {
3751
- const context = createPluginContext(plugin.name);
3752
- return plugin.configResolved?.call(context, config);
3753
- }));
3754
- }
3755
- //#endregion
3756
- //#region src/utils/run-build.ts
3757
- async function runBuild(config, options) {
3758
- return await new Bundler(config).build(options);
3759
- }
3760
- //#endregion
3761
- //#region src/utils/run-server.ts
3762
- async function runServer(config, options) {
3763
- const { port, host } = options;
3764
- const devServer = await createDevServer(config, options);
3765
- await devServer.instance.listen({
3766
- port,
3767
- host
3768
- });
3769
- return devServer;
3770
- }
3771
- //#endregion
3772
- //#region src/node/commands/start/action.ts
3773
- const action$1 = async function(options) {
3774
- const cwd = process.cwd();
3775
- const config = await loadConfig({
3776
- cwd,
3777
- mode: "development",
3778
- configFile: options.config,
3779
- context: { command: "start" }
3780
- });
3781
- if (options.resetCache) {
3782
- resetCache(cwd);
3783
- logger$2.info("The transform cache was reset");
3784
- }
3785
- if (options.clientLogs === false) config.reporter = { update: es_toolkit.noop };
3786
- const devServer = await runServer(config, {
3787
- buildOptions: { cache: options.cache },
3788
- port: options.port,
3789
- host: options.host,
3790
- https: options.https,
3791
- key: options.key,
3792
- cert: options.cert
3793
- });
3794
- if (options.interactive) setupInteractiveMode({
3795
- devServer,
3796
- extraCommands: config.terminal?.extraCommands
3797
- });
3798
- };
3799
- //#endregion
3800
- //#region src/node/commands/start/command.ts
3801
- const command$1 = {
3802
- name: "start",
3803
- description: "Start the React Native development server.",
3804
- action: action$1,
3805
- options: [
3806
- {
3807
- name: "--config <string>",
3808
- description: "Path to the CLI configuration file",
3809
- parse: resolvePath
3810
- },
3811
- {
3812
- name: "--host <string>",
3813
- description: "Host to start the development server on",
3814
- default: DEFAULT_HOST
3815
- },
3816
- {
3817
- name: "--port <number>",
3818
- description: "Port to start the development server on",
3819
- default: DEFAULT_PORT,
3820
- parse: Number
3821
- },
3822
- {
3823
- name: "--reset-cache, --resetCache",
3824
- description: "Removes cached files"
3825
- },
3826
- {
3827
- name: "--https",
3828
- description: "Enables https connections to the server"
3829
- },
3830
- {
3831
- name: "--key <path>",
3832
- description: "Path to custom SSL key"
3833
- },
3834
- {
3835
- name: "--cert <path>",
3836
- description: "Path to custom SSL cert"
3837
- },
3838
- {
3839
- name: "--no-interactive",
3840
- description: "Disables interactive mode"
3841
- },
3842
- {
3843
- name: "--client-logs",
3844
- description: "[Deprecated] Enable plain text JavaScript log streaming for all connected apps. This feature is deprecated and will be removed in future.",
3845
- default: false
3846
- },
3847
- {
3848
- name: "--cache [boolean]",
3849
- description: "If false, the bundler will not load or store any cache",
3850
- parse: parseBoolean
3851
- },
3852
- {
3853
- name: "--projectRoot <path>",
3854
- description: UNSUPPORTED_OPTION_DESCRIPTION
3855
- },
3856
- {
3857
- name: "--watchFolders <list>",
3858
- description: UNSUPPORTED_OPTION_DESCRIPTION
3859
- },
3860
- {
3861
- name: "--assetPlugins <list>",
3862
- description: UNSUPPORTED_OPTION_DESCRIPTION
3863
- },
3864
- {
3865
- name: "--sourceExts <list>",
3866
- description: UNSUPPORTED_OPTION_DESCRIPTION
3867
- },
3868
- {
3869
- name: "--max-workers <number>",
3870
- description: UNSUPPORTED_OPTION_DESCRIPTION
3871
- },
3872
- {
3873
- name: "--transformer <string>",
3874
- description: UNSUPPORTED_OPTION_DESCRIPTION
3875
- },
3876
- {
3877
- name: "--custom-log-reporter-path, --customLogReporterPath <string>",
3878
- description: UNSUPPORTED_OPTION_DESCRIPTION
3879
- }
3880
- ]
3881
- };
3882
- //#endregion
3883
- //#region src/node/commands/bundle/action.ts
3884
- const action = async function(options) {
3885
- if (!this.platforms.includes(options.platform)) throw new Error(`Unrecognized platform: ${options.platform}`);
3886
- const cwd = process.cwd();
3887
- const config = await loadConfig({
3888
- cwd,
3889
- mode: "production",
3890
- configFile: options.config,
3891
- context: { command: "bundle" }
3892
- });
3893
- if (options.resetCache) {
3894
- resetCache(cwd);
3895
- logger$2.info("The transform cache was reset");
3896
- }
3897
- if (options.entryFile) config.entry = options.entryFile;
3898
- await runBuild(config, {
3899
- platform: options.platform,
3900
- dev: options.dev,
3901
- minify: options.minify,
3902
- cache: options.cache,
3903
- outfile: options.bundleOutput,
3904
- sourcemapOutfile: options.sourcemapOutput,
3905
- assetsDir: options.assetsDest
3906
- });
3907
- };
3908
- //#endregion
3909
- //#region src/node/commands/bundle/command.ts
3910
- const command = {
3911
- name: "bundle",
3912
- description: "Build the bundle for the provided JavaScript entry file.",
3913
- action,
3914
- options: [
3915
- {
3916
- name: "--config <string>",
3917
- description: "Path to the CLI configuration file",
3918
- parse: resolvePath
3919
- },
3920
- {
3921
- name: "--entry-file <path>",
3922
- description: "Path to the root JS file, either absolute or relative to JS root"
3923
- },
3924
- {
3925
- name: "--platform <string>",
3926
- description: "Either \"ios\" or \"android\"",
3927
- default: "ios"
3928
- },
3929
- {
3930
- name: "--dev [boolean]",
3931
- description: "If false, warnings are disabled and the bundle is minified",
3932
- parse: parseBoolean
3933
- },
3934
- {
3935
- name: "--minify [boolean]",
3936
- description: "Allows overriding whether bundle is minified. This defaults to false if dev is true, and true if dev is false. Disabling minification can be useful for speeding up production builds for testing purposes.",
3937
- parse: parseBoolean
3938
- },
3939
- {
3940
- name: "--cache [boolean]",
3941
- description: "If false, the bundler will not load or store any cache",
3942
- parse: parseBoolean
3943
- },
3944
- {
3945
- name: "--bundle-output <string>",
3946
- description: "File name where to store the resulting bundle, ex. /tmp/groups.bundle",
3947
- required: true
3948
- },
3949
- {
3950
- name: "--sourcemap-output <string>",
3951
- description: "File name where to store the sourcemap file for resulting bundle, ex. /tmp/groups.map"
3952
- },
3953
- {
3954
- name: "--sourcemap-sources-root <string>",
3955
- description: `Path to make sourcemap's sources entries relative to, ex. /root/dir`
3956
- },
3957
- {
3958
- name: "--sourcemap-use-absolute-path",
3959
- description: "Report SourceMapURL using its full path"
3960
- },
3961
- {
3962
- name: "--assets-dest <string>",
3963
- description: "Directory name where to store assets referenced in the bundle"
3964
- },
3965
- {
3966
- name: "--reset-cache",
3967
- description: "Removes cached files",
3968
- default: false
3969
- },
3970
- {
3971
- name: "--transformer <string>",
3972
- description: UNSUPPORTED_OPTION_DESCRIPTION
3973
- },
3974
- {
3975
- name: "--bundle-encoding <string>",
3976
- description: UNSUPPORTED_OPTION_DESCRIPTION
3977
- },
3978
- {
3979
- name: "--max-workers <number>",
3980
- description: UNSUPPORTED_OPTION_DESCRIPTION
3981
- },
3982
- {
3983
- name: "--unstable-transform-profile <string>",
3984
- description: UNSUPPORTED_OPTION_DESCRIPTION
3985
- },
3986
- {
3987
- name: "--asset-catalog-dest [string]",
3988
- description: UNSUPPORTED_OPTION_DESCRIPTION
3989
- },
3990
- {
3991
- name: "--read-global-cache",
3992
- description: UNSUPPORTED_OPTION_DESCRIPTION
3993
- },
3994
- {
3995
- name: "--resolver-option <string...>",
3996
- description: UNSUPPORTED_OPTION_DESCRIPTION
3997
- }
3998
- ]
3999
- };
4000
- //#endregion
4001
- //#region src/commands.ts
4002
- const commands = [
4003
- createReactNativeCliCommand(command$1),
4004
- createReactNativeCliCommand(command),
4005
- createReactNativeCliCommand(command$2)
4006
- ];
4007
- //#endregion
4008
- module.exports = commands;