miaoda-expo-devkit 0.1.1-beta.69 → 0.1.1-beta.70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +102 -4
- package/dist/metro.d.mts +10 -0
- package/dist/metro.d.ts +10 -0
- package/dist/metro.js +16 -0
- package/dist/metro.mjs +16 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,9 +7,18 @@ Expo / React Native 开发环境工具集,通过 Metro 构建层注入以下
|
|
|
7
7
|
- **Bundle 首部注入** — 在 expo-router 初始化之前执行自定义脚本
|
|
8
8
|
- **HMR postMessage 控制** — 通过 `window.postMessage` 在运行时启动或停止 Fast Refresh
|
|
9
9
|
- **LogBox 屏蔽** — web 平台禁用 Expo 全屏错误遮罩
|
|
10
|
+
- **Metro transform 缓存持久化** — 将缓存目录固定到项目根目录(可通过 `METRO_CACHE_DIR` 指定),容器/CI 重启后不丢失
|
|
11
|
+
- **构建耗时日志** — 将 bundle 总耗时和每个 cache miss 文件的 transform 耗时写入 JSONL 文件(通过 `METRO_TRANSFORM_LOG` 启用)
|
|
12
|
+
- **esbuild minifier** — 生产构建时将 Metro minifier 切换为 esbuild(比 terser 快数十倍)
|
|
13
|
+
- **WASM 支持** — 将 `.wasm` 加入 assetExts,修复 expo-sqlite web worker 打包失败
|
|
14
|
+
- **lucide-react-native 路径解析** — 配合 babel 插件,消除图标子路径 exports 未声明的 warning
|
|
15
|
+
- **workspace node_modules 修复** — 修复沙箱环境中 node_modules 位于祖先目录时 Metro 模块解析和 bundle 请求失败的问题
|
|
10
16
|
- **expo-notifications stub** — Expo Go(Android)中提供 no-op 实现,核心 API 调用时弹出带参数校验的调试 Alert,Dev Build 透传真实模块
|
|
11
17
|
- **expo-media-library stub** — Expo Go / Web 中提供 no-op 实现,`saveToLibraryAsync`、`createAssetAsync`、权限请求等 API 调用时弹出 Alert 提示,Dev Build 原生环境透传真实模块
|
|
12
18
|
- **expo-calendar stub** — Expo Go / Web 中提供 no-op 实现,`getEventsAsync`、`createEventAsync`、`getCalendarsAsync`、权限请求等核心 API 调用时弹出 Alert 提示并校验参数,Dev Build 原生环境透传真实模块
|
|
19
|
+
- **expo-file-system stub** — Web 中将 `expo-file-system` 和 `expo-file-system/legacy` 替换为 no-op stub,核心 API 弹 Dialog 提示,Expo Go / Dev Build 透传真实模块
|
|
20
|
+
- **expo-haptics stub** — Web 中提供 no-op 实现,触觉 API 调用时弹 Dialog 提示参数信息,native 不受影响
|
|
21
|
+
- **expo-contacts stub** — Web / Expo Go 中提供 no-op 实现,联系人 API 调用时弹 Dialog 提示,Dev Build 透传真实模块
|
|
13
22
|
- **expo-image-picker stub** — 桌面 Web 中 `launchCameraAsync` 通过 `getUserMedia` 打开摄像头预览弹窗(浏览器原生 `capture` 属性在 PC 端被忽略),移动端浏览器透传 expo 原实现,Native 不受影响
|
|
14
23
|
|
|
15
24
|
## 安装
|
|
@@ -224,12 +233,43 @@ expect(onError).toHaveBeenCalledWith(
|
|
|
224
233
|
| 变量 | 默认值 | 说明 |
|
|
225
234
|
|---|---|---|
|
|
226
235
|
| `SENTRY_OVERRIDE_DSN` | `https://stubPublicKey@o0.ingest.sentry.io/0` | 覆盖 Sentry DSN,可指向本地 relay 等自定义端点 |
|
|
236
|
+
| `METRO_CACHE_DIR` | `projectRoot/.metro-cache` | Metro transform 缓存目录绝对路径,优先级最高,适合容器/CI 挂载外部持久目录 |
|
|
237
|
+
| `METRO_TRANSFORM_LOG` | _(未设置时不记录)_ | 构建日志输出文件的绝对路径(JSONL 格式),仅开发模式(`__DEV__`)下生效 |
|
|
227
238
|
|
|
228
239
|
## 工作原理
|
|
229
240
|
|
|
230
241
|
```
|
|
231
242
|
metro.config.js
|
|
232
243
|
└─ withDevkit(config)
|
|
244
|
+
│
|
|
245
|
+
├─ withTransformLogger → unstable_perfLoggerFactory + metro-core Logger
|
|
246
|
+
│ ├─ CACHE_CONFIG 条目(启动时由 withPersistentCache 写入,含 cache_root / store_class / source)
|
|
247
|
+
│ ├─ BUNDLING_REQUEST 条目(每次 bundle 请求写一条)
|
|
248
|
+
│ │ ├─ duration_ms、status、initial_build、graph_node_count
|
|
249
|
+
│ │ └─ transform_miss_count(cache miss 文件数;0 = 完全命中)
|
|
250
|
+
│ └─ TRANSFORM_FILE 条目(每个 cache miss 文件写一条,命中则不写)
|
|
251
|
+
│ └─ file、duration_ms
|
|
252
|
+
│ (需设置 METRO_TRANSFORM_LOG 且 __DEV__ 才生效)
|
|
253
|
+
│
|
|
254
|
+
├─ withPersistentCache → config.cacheStores
|
|
255
|
+
│ ├─ 缓存路径优先级:METRO_CACHE_DIR > options.cacheDir > projectRoot/.metro-cache
|
|
256
|
+
│ └─ 保留 @expo/metro-config FileStore 子类行为(NativeWind skipCache 标志)
|
|
257
|
+
│
|
|
258
|
+
├─ withWorkspaceNodeModules → watchFolders + resolver.nodeModulesPaths
|
|
259
|
+
│ ├─ 向上查找祖先目录的 node_modules,加入 watchFolders
|
|
260
|
+
│ └─ 若 .pnpm 是指向外部路径的 symlink,也将外部真实路径加入 watchFolders
|
|
261
|
+
│
|
|
262
|
+
├─ withWasmSupport → resolver.assetExts
|
|
263
|
+
│ └─ 将 .wasm 加入 assetExts,修复 expo-sqlite web worker 打包
|
|
264
|
+
│
|
|
265
|
+
├─ withCssInterop → 为 expo-image / expo-camera 等注入 NativeWind cssInterop
|
|
266
|
+
│
|
|
267
|
+
├─ withEsbuildMinify → transformer.minifierPath(仅生产构建)
|
|
268
|
+
│ └─ 切换为 metro-minify-esbuild,清空 terser 专属 minifierConfig
|
|
269
|
+
│
|
|
270
|
+
├─ withLucideResolver → resolver.resolveRequest
|
|
271
|
+
│ └─ lucide-react-native/dist/** 子路径 → 绝对文件路径(绕过 exports 检查)
|
|
272
|
+
│ └─ 自动检测 .mjs(>= 1.9)vs .js(1.8.x)扩展名
|
|
233
273
|
│
|
|
234
274
|
├─ withDevStubs → resolver.resolveRequest
|
|
235
275
|
│ ├─ @sentry/react-native → dist/stubs/sentry-react-native-stub.js (全平台)
|
|
@@ -246,19 +286,35 @@ metro.config.js
|
|
|
246
286
|
│ └─ Dev Build(原生):透传真实 expo-media-library
|
|
247
287
|
│
|
|
248
288
|
├─ withExpoCalendarStub → resolver.resolveRequest
|
|
249
|
-
│ └─ expo-calendar
|
|
289
|
+
│ └─ expo-calendar → dist/stubs/expo-calendar-stub.js (全平台)
|
|
250
290
|
│ ├─ Expo Go / Web:no-op + Alert 提示 + 参数校验(不崩溃)
|
|
251
291
|
│ └─ Dev Build(原生):透传真实 expo-calendar
|
|
252
292
|
│
|
|
293
|
+
├─ withExpoFileSystemStub → resolver.resolveRequest
|
|
294
|
+
│ ├─ expo-file-system/legacy → dist/stubs/expo-file-system-stub.js (全平台)
|
|
295
|
+
│ └─ expo-file-system → dist/stubs/expo-file-system-next-stub.js
|
|
296
|
+
│ ├─ Web:no-op + Dialog 提示(不崩溃)
|
|
297
|
+
│ └─ Expo Go / Dev Build(原生):透传真实模块
|
|
298
|
+
│
|
|
299
|
+
├─ withExpoHapticsStub → resolver.resolveRequest
|
|
300
|
+
│ └─ expo-haptics → dist/stubs/expo-haptics-stub.js (仅 web)
|
|
301
|
+
│ ├─ Web:no-op + Dialog 提示(不崩溃)
|
|
302
|
+
│ └─ native:透传真实 expo-haptics
|
|
303
|
+
│
|
|
304
|
+
├─ withExpoContactsStub → resolver.resolveRequest
|
|
305
|
+
│ └─ expo-contacts → dist/stubs/expo-contacts-stub.js (仅 web)
|
|
306
|
+
│ ├─ Web / Expo Go:no-op + Dialog 提示(不崩溃)
|
|
307
|
+
│ └─ Dev Build(原生):透传真实 expo-contacts
|
|
308
|
+
│
|
|
253
309
|
├─ withExpoImagePickerStub → resolver.resolveRequest
|
|
254
|
-
│ └─ expo-image-picker
|
|
310
|
+
│ └─ expo-image-picker → dist/stubs/expo-image-picker-stub.js (仅 web)
|
|
255
311
|
│ ├─ 桌面 Web:launchCameraAsync → getUserMedia + #__devkit_camera_overlay__ 弹窗
|
|
256
312
|
│ │ ├─ 点"拍照":canvas.toDataURL → ImagePickerResult { canceled:false, assets }
|
|
257
313
|
│ │ └─ 点"取消":返回 { canceled:true, assets:null }
|
|
258
314
|
│ ├─ 移动端浏览器:透传 expo 原实现(capture 属性正常工作)
|
|
259
315
|
│ └─ getUserMedia 不可用:降级透传 expo 原实现(不崩溃)
|
|
260
316
|
│
|
|
261
|
-
└─ withEntryInjection → resolver.resolveRequest
|
|
317
|
+
└─ withEntryInjection → resolver.resolveRequest(仅 __DEV__)
|
|
262
318
|
└─ expo-router/entry-classic → dist/stubs/expo-router-entry-stub.js
|
|
263
319
|
├─ require('./entry-inject') ← 注入脚本(bundle 首部执行)
|
|
264
320
|
│ ├─ globalThis.__DEVKIT_INJECTED__ = true
|
|
@@ -289,7 +345,7 @@ sentry-react-native-stub.js
|
|
|
289
345
|
| 子路径 | 文件 | 内容 |
|
|
290
346
|
|---|---|---|
|
|
291
347
|
| `.` | `dist/index.js` | `SentryCapture`、`MetroSymbolicator`、全部类型 |
|
|
292
|
-
| `./metro` | `dist/metro.js` | `withDevkit`、`withDevStubs`、`withEntryInjection`、`withExpoNotificationsStub`、`withExpoMediaLibraryStub`、`withExpoCalendarStub`
|
|
348
|
+
| `./metro` | `dist/metro.js` | `withDevkit`、`withDevStubs`、`withEntryInjection`、`withPersistentCache`、`withTransformLogger`、`withExpoNotificationsStub`、`withExpoMediaLibraryStub`、`withExpoCalendarStub` 等全部 Metro wrapper |
|
|
293
349
|
| `./babel-plugin-jsx-source` | `dist/babel/plugin-jsx-source.js` | Babel 插件:为 JSX 注入 source 信息 |
|
|
294
350
|
| `./babel-preset` | `dist/babel/preset.js` | Babel Preset:集成 jsx-source 和 lucide 插件 |
|
|
295
351
|
| `./sentry-react-native-stub` | `dist/stubs/sentry-react-native-stub.js` | `@sentry/react-native` 模块替换 stub |
|
|
@@ -297,6 +353,10 @@ sentry-react-native-stub.js
|
|
|
297
353
|
| `./expo-notifications-stub` | `dist/stubs/expo-notifications-stub.js` | `expo-notifications` Expo Go Android stub |
|
|
298
354
|
| `./expo-media-library-stub` | `dist/stubs/expo-media-library-stub.js` | `expo-media-library` Expo Go / Web stub |
|
|
299
355
|
| `./expo-calendar-stub` | `dist/stubs/expo-calendar-stub.js` | `expo-calendar` Expo Go / Web stub |
|
|
356
|
+
| `./expo-file-system-stub` | `dist/stubs/expo-file-system-stub.js` | `expo-file-system/legacy` Web stub |
|
|
357
|
+
| `./expo-file-system-next-stub` | `dist/stubs/expo-file-system-next-stub.js` | `expo-file-system` 新版 API Web stub |
|
|
358
|
+
| `./expo-haptics-stub` | `dist/stubs/expo-haptics-stub.js` | `expo-haptics` Web stub |
|
|
359
|
+
| `./expo-contacts-stub` | `dist/stubs/expo-contacts-stub.js` | `expo-contacts` Web / Expo Go stub |
|
|
300
360
|
| `./expo-image-picker-stub` | `dist/stubs/expo-image-picker-stub.js` | `expo-image-picker` 桌面 Web stub |
|
|
301
361
|
|
|
302
362
|
---
|
|
@@ -505,6 +565,44 @@ Expo Go 扫码预览不支持访问手机相册
|
|
|
505
565
|
|
|
506
566
|
---
|
|
507
567
|
|
|
568
|
+
### expo-file-system-stub.js / expo-file-system-next-stub.js
|
|
569
|
+
|
|
570
|
+
`expo-file-system` 模块替换 stub,由 `withExpoFileSystemStub()` 在 Metro 层注入(**全平台**)。
|
|
571
|
+
|
|
572
|
+
**背景:** `expo-file-system` 的文件 API 在 Web 端不可用:legacy API 底层方法缺失会抛 `UnavailabilityError`;新版 API(`File` / `Directory`)基类缺少 `validatePath()`,`new File(...)` 会抛 `TypeError: this.validatePath is not a function`。
|
|
573
|
+
|
|
574
|
+
**拦截路径:**
|
|
575
|
+
- `expo-file-system/legacy` → `expo-file-system-stub.js`(legacy API)
|
|
576
|
+
- `expo-file-system` → `expo-file-system-next-stub.js`(新版 File/Directory/Paths API)
|
|
577
|
+
|
|
578
|
+
**运行时行为:**
|
|
579
|
+
- **Web**:提供 no-op 实现,核心 API 调用时弹出 Dialog 提示(不崩溃)
|
|
580
|
+
- **Expo Go / Development Build(原生)**:透传真实 `expo-file-system`,功能完全正常
|
|
581
|
+
|
|
582
|
+
---
|
|
583
|
+
|
|
584
|
+
### expo-haptics-stub.js
|
|
585
|
+
|
|
586
|
+
`expo-haptics` 模块替换 stub,由 `withExpoHapticsStub()` 在 Metro 层注入(**仅 web 平台**)。
|
|
587
|
+
|
|
588
|
+
**背景:** Web 没有振动/触觉硬件 API,`expo-haptics` 在 web 会运行时崩溃。
|
|
589
|
+
|
|
590
|
+
**运行时行为:**
|
|
591
|
+
- **Web**:提供 no-op 实现,`impactAsync`、`notificationAsync`、`selectionAsync` 调用时弹出 Dialog 提示参数信息(不崩溃);枚举常量(`ImpactFeedbackStyle`、`NotificationFeedbackType` 等)正常可用
|
|
592
|
+
- **Expo Go / Development Build(native)**:透传真实 `expo-haptics`,功能完全正常
|
|
593
|
+
|
|
594
|
+
---
|
|
595
|
+
|
|
596
|
+
### expo-contacts-stub.js
|
|
597
|
+
|
|
598
|
+
`expo-contacts` 模块替换 stub,由 `withExpoContactsStub()` 在 Metro 层注入(**仅 web 平台**)。
|
|
599
|
+
|
|
600
|
+
**背景:** `expo-contacts` 依赖 native module,在 Web 和 Expo Go 中不可用。
|
|
601
|
+
|
|
602
|
+
**运行时行为:**
|
|
603
|
+
- **Web / Expo Go**:提供 no-op 实现,联系人 API 调用时弹出 Dialog 提示(不崩溃)
|
|
604
|
+
- **Development Build(原生)**:透传真实 `expo-contacts`,功能完全正常
|
|
605
|
+
|
|
508
606
|
---
|
|
509
607
|
|
|
510
608
|
### expo-image-picker-stub.js
|
package/dist/metro.d.mts
CHANGED
|
@@ -415,6 +415,7 @@ declare function withWasmSupport(config: MetroConfig): MetroConfig;
|
|
|
415
415
|
* "bundle_url": "index.bundle",
|
|
416
416
|
* "initial_build": true, // true=首次构建 false=增量更新
|
|
417
417
|
* "graph_node_count": 220,
|
|
418
|
+
* "transform_miss_count": 5, // cache miss 的文件数;0 = 完全命中缓存
|
|
418
419
|
* "bundle_length": 512000,
|
|
419
420
|
* "points": {
|
|
420
421
|
* "resolvingAndTransformingDependencies_start": 5,
|
|
@@ -460,6 +461,15 @@ declare function withTransformLogger(config: MetroConfig): MetroConfig;
|
|
|
460
461
|
*
|
|
461
462
|
* cache key 由文件内容 sha1 + 相对路径 + Babel/Metro 版本共同决定,
|
|
462
463
|
* 与项目绝对路径无关,换目录 clone 后缓存同样有效。
|
|
464
|
+
*
|
|
465
|
+
* 若 METRO_TRANSFORM_LOG 已设置,启动时向日志追加一条 CACHE_CONFIG 条目:
|
|
466
|
+
* {
|
|
467
|
+
* "type": "CACHE_CONFIG",
|
|
468
|
+
* "cache_root": "/workspace/.metro-cache",
|
|
469
|
+
* "store_class": "ExpoFileStore", // 生效的 store 类名
|
|
470
|
+
* "source": "env" | "option" | "default",
|
|
471
|
+
* "t": 1234567890
|
|
472
|
+
* }
|
|
463
473
|
*/
|
|
464
474
|
|
|
465
475
|
interface PersistentCacheOptions {
|
package/dist/metro.d.ts
CHANGED
|
@@ -415,6 +415,7 @@ declare function withWasmSupport(config: MetroConfig): MetroConfig;
|
|
|
415
415
|
* "bundle_url": "index.bundle",
|
|
416
416
|
* "initial_build": true, // true=首次构建 false=增量更新
|
|
417
417
|
* "graph_node_count": 220,
|
|
418
|
+
* "transform_miss_count": 5, // cache miss 的文件数;0 = 完全命中缓存
|
|
418
419
|
* "bundle_length": 512000,
|
|
419
420
|
* "points": {
|
|
420
421
|
* "resolvingAndTransformingDependencies_start": 5,
|
|
@@ -460,6 +461,15 @@ declare function withTransformLogger(config: MetroConfig): MetroConfig;
|
|
|
460
461
|
*
|
|
461
462
|
* cache key 由文件内容 sha1 + 相对路径 + Babel/Metro 版本共同决定,
|
|
462
463
|
* 与项目绝对路径无关,换目录 clone 后缓存同样有效。
|
|
464
|
+
*
|
|
465
|
+
* 若 METRO_TRANSFORM_LOG 已设置,启动时向日志追加一条 CACHE_CONFIG 条目:
|
|
466
|
+
* {
|
|
467
|
+
* "type": "CACHE_CONFIG",
|
|
468
|
+
* "cache_root": "/workspace/.metro-cache",
|
|
469
|
+
* "store_class": "ExpoFileStore", // 生效的 store 类名
|
|
470
|
+
* "source": "env" | "option" | "default",
|
|
471
|
+
* "t": 1234567890
|
|
472
|
+
* }
|
|
463
473
|
*/
|
|
464
474
|
|
|
465
475
|
interface PersistentCacheOptions {
|
package/dist/metro.js
CHANGED
|
@@ -504,6 +504,7 @@ function withWasmSupport(config) {
|
|
|
504
504
|
var import_node_fs = __toESM(require("fs"));
|
|
505
505
|
var import_node_path = __toESM(require("path"));
|
|
506
506
|
var import_metro_core = require("metro-core");
|
|
507
|
+
var currentMissCount = 0;
|
|
507
508
|
function installPerfLogger(logFile, existingFactory) {
|
|
508
509
|
const dir = import_node_path.default.dirname(logFile);
|
|
509
510
|
if (!import_node_fs.default.existsSync(dir)) {
|
|
@@ -515,6 +516,7 @@ function installPerfLogger(logFile, existingFactory) {
|
|
|
515
516
|
const startTime = process.hrtime.bigint();
|
|
516
517
|
const points = {};
|
|
517
518
|
const annotations = {};
|
|
519
|
+
const missCountAtStart = currentMissCount;
|
|
518
520
|
const logger = {
|
|
519
521
|
start() {
|
|
520
522
|
upstream?.start?.();
|
|
@@ -526,6 +528,7 @@ function installPerfLogger(logFile, existingFactory) {
|
|
|
526
528
|
status,
|
|
527
529
|
duration_ms: Math.round(duration_ms),
|
|
528
530
|
...annotations,
|
|
531
|
+
transform_miss_count: currentMissCount - missCountAtStart,
|
|
529
532
|
points,
|
|
530
533
|
t: Date.now()
|
|
531
534
|
});
|
|
@@ -557,6 +560,7 @@ function installFileLogger(logFile) {
|
|
|
557
560
|
fileLoggerInstalled = true;
|
|
558
561
|
import_metro_core.Logger.on("log", (entry) => {
|
|
559
562
|
if (entry.action_name === "Transforming file" && entry.action_phase === "end") {
|
|
563
|
+
currentMissCount++;
|
|
560
564
|
const line = JSON.stringify({
|
|
561
565
|
type: "TRANSFORM_FILE",
|
|
562
566
|
file: entry.file_name,
|
|
@@ -580,6 +584,7 @@ function withTransformLogger(config) {
|
|
|
580
584
|
}
|
|
581
585
|
|
|
582
586
|
// src/metro/withPersistentCache.ts
|
|
587
|
+
var import_node_fs2 = __toESM(require("fs"));
|
|
583
588
|
var import_path14 = __toESM(require("path"));
|
|
584
589
|
var import_metro_cache = require("metro-cache");
|
|
585
590
|
function withPersistentCache(config, options = {}) {
|
|
@@ -597,6 +602,17 @@ function withPersistentCache(config, options = {}) {
|
|
|
597
602
|
const existingStores = config.cacheStores;
|
|
598
603
|
const firstStore = Array.isArray(existingStores) ? existingStores[0] : void 0;
|
|
599
604
|
const StoreClass = firstStore ? Object.getPrototypeOf(firstStore).constructor : import_metro_cache.FileStore;
|
|
605
|
+
const logFile = process.env["METRO_TRANSFORM_LOG"];
|
|
606
|
+
if (logFile) {
|
|
607
|
+
const line = JSON.stringify({
|
|
608
|
+
type: "CACHE_CONFIG",
|
|
609
|
+
cache_root: cacheRoot,
|
|
610
|
+
store_class: StoreClass.name || "unknown",
|
|
611
|
+
source: envCacheDir ? "env" : cacheDir ? "option" : "default",
|
|
612
|
+
t: Date.now()
|
|
613
|
+
});
|
|
614
|
+
import_node_fs2.default.appendFileSync(logFile, line + "\n");
|
|
615
|
+
}
|
|
600
616
|
return {
|
|
601
617
|
...config,
|
|
602
618
|
cacheStores: [new StoreClass({ root: cacheRoot })]
|
package/dist/metro.mjs
CHANGED
|
@@ -455,6 +455,7 @@ function withWasmSupport(config) {
|
|
|
455
455
|
import fs4 from "fs";
|
|
456
456
|
import path14 from "path";
|
|
457
457
|
import { Logger } from "metro-core";
|
|
458
|
+
var currentMissCount = 0;
|
|
458
459
|
function installPerfLogger(logFile, existingFactory) {
|
|
459
460
|
const dir = path14.dirname(logFile);
|
|
460
461
|
if (!fs4.existsSync(dir)) {
|
|
@@ -466,6 +467,7 @@ function installPerfLogger(logFile, existingFactory) {
|
|
|
466
467
|
const startTime = process.hrtime.bigint();
|
|
467
468
|
const points = {};
|
|
468
469
|
const annotations = {};
|
|
470
|
+
const missCountAtStart = currentMissCount;
|
|
469
471
|
const logger = {
|
|
470
472
|
start() {
|
|
471
473
|
upstream?.start?.();
|
|
@@ -477,6 +479,7 @@ function installPerfLogger(logFile, existingFactory) {
|
|
|
477
479
|
status,
|
|
478
480
|
duration_ms: Math.round(duration_ms),
|
|
479
481
|
...annotations,
|
|
482
|
+
transform_miss_count: currentMissCount - missCountAtStart,
|
|
480
483
|
points,
|
|
481
484
|
t: Date.now()
|
|
482
485
|
});
|
|
@@ -508,6 +511,7 @@ function installFileLogger(logFile) {
|
|
|
508
511
|
fileLoggerInstalled = true;
|
|
509
512
|
Logger.on("log", (entry) => {
|
|
510
513
|
if (entry.action_name === "Transforming file" && entry.action_phase === "end") {
|
|
514
|
+
currentMissCount++;
|
|
511
515
|
const line = JSON.stringify({
|
|
512
516
|
type: "TRANSFORM_FILE",
|
|
513
517
|
file: entry.file_name,
|
|
@@ -531,6 +535,7 @@ function withTransformLogger(config) {
|
|
|
531
535
|
}
|
|
532
536
|
|
|
533
537
|
// src/metro/withPersistentCache.ts
|
|
538
|
+
import fs5 from "fs";
|
|
534
539
|
import path15 from "path";
|
|
535
540
|
import { FileStore } from "metro-cache";
|
|
536
541
|
function withPersistentCache(config, options = {}) {
|
|
@@ -548,6 +553,17 @@ function withPersistentCache(config, options = {}) {
|
|
|
548
553
|
const existingStores = config.cacheStores;
|
|
549
554
|
const firstStore = Array.isArray(existingStores) ? existingStores[0] : void 0;
|
|
550
555
|
const StoreClass = firstStore ? Object.getPrototypeOf(firstStore).constructor : FileStore;
|
|
556
|
+
const logFile = process.env["METRO_TRANSFORM_LOG"];
|
|
557
|
+
if (logFile) {
|
|
558
|
+
const line = JSON.stringify({
|
|
559
|
+
type: "CACHE_CONFIG",
|
|
560
|
+
cache_root: cacheRoot,
|
|
561
|
+
store_class: StoreClass.name || "unknown",
|
|
562
|
+
source: envCacheDir ? "env" : cacheDir ? "option" : "default",
|
|
563
|
+
t: Date.now()
|
|
564
|
+
});
|
|
565
|
+
fs5.appendFileSync(logFile, line + "\n");
|
|
566
|
+
}
|
|
551
567
|
return {
|
|
552
568
|
...config,
|
|
553
569
|
cacheStores: [new StoreClass({ root: cacheRoot })]
|