miaoda-expo-devkit 0.1.1-beta.46 → 0.1.1-beta.47

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/dist/metro.d.mts CHANGED
@@ -339,36 +339,46 @@ declare function withEsbuildMinify(config: MetroConfig): MetroConfig;
339
339
  declare function withWasmSupport(config: MetroConfig): MetroConfig;
340
340
 
341
341
  /**
342
- * withTransformLogger — Metro bundle 整体耗时日志
342
+ * withTransformLogger — Metro bundle 整体耗时日志 + 单文件 transform 耗时日志
343
343
  *
344
- * 通过 unstable_perfLoggerFactory 收集每次 bundle 请求的性能数据,写入 JSONL 文件。
345
- * 该回调在主进程执行,不受 --max-workers 多进程影响。
344
+ * 写入两类 JSONL 条目:
346
345
  *
347
- * 激活条件(两者同时满足):
348
- * 1. 环境变量 METRO_TRANSFORM_LOG 设置为目标文件路径
349
- * 2. 当前处于开发模式(__DEV__ === true),expo export 生产构建时不记录
350
- *
351
- * 每行格式(一次 bundle 请求写一条):
346
+ * 1. BUNDLING_REQUEST — 每次完整 bundle 请求写一条(通过 unstable_perfLoggerFactory)
352
347
  * {
353
- * "type": "BUNDLING_REQUEST", // START_UP | BUNDLING_REQUEST | HMR
348
+ * "type": "BUNDLING_REQUEST",
354
349
  * "status": "SUCCESS", // SUCCESS | FAIL | CANCEL
355
350
  * "duration_ms": 1234,
356
351
  * "bundle_url": "index.bundle",
357
352
  * "initial_build": true, // true=首次构建 false=增量更新
358
- * "graph_node_count": 220, // 模块数量
359
- * "bundle_length": 512000, // bundle 字节数
360
- * "points": { // 各阶段耗时(ms,从 start 计算)
353
+ * "graph_node_count": 220,
354
+ * "bundle_length": 512000,
355
+ * "points": {
361
356
  * "resolvingAndTransformingDependencies_start": 5,
362
357
  * "resolvingAndTransformingDependencies_end": 980,
363
358
  * "serializingBundle_start": 981,
364
359
  * "serializingBundle_end": 1200
365
360
  * },
366
- * "t": 1234567890 // bundle 完成时的时间戳
361
+ * "t": 1234567890
367
362
  * }
363
+ *
364
+ * 2. TRANSFORM_FILE — 每个 cache miss 的文件写一条(通过 metro-core Logger)
365
+ * {
366
+ * "type": "TRANSFORM_FILE",
367
+ * "file": "src/components/Button.tsx",
368
+ * "duration_ms": 45,
369
+ * "t": 1234567890
370
+ * }
371
+ * 注意:缓存命中的文件不会触发此条目。
372
+ *
373
+ * 激活条件(两者同时满足):
374
+ * 1. 环境变量 METRO_TRANSFORM_LOG 设置为目标文件路径
375
+ * 2. 当前处于开发模式(__DEV__ === true),expo export 生产构建时不记录
368
376
  */
369
377
 
370
378
  /**
371
- * 在开发模式下,若 METRO_TRANSFORM_LOG 已设置,则注入 unstable_perfLoggerFactory。
379
+ * 在开发模式下,若 METRO_TRANSFORM_LOG 已设置,则注入:
380
+ * - unstable_perfLoggerFactory(整体 bundle 耗时)
381
+ * - metro-core Logger 监听器(单文件 transform 耗时,仅 cache miss)
372
382
  */
373
383
  declare function withTransformLogger(config: MetroConfig): MetroConfig;
374
384
 
package/dist/metro.d.ts CHANGED
@@ -339,36 +339,46 @@ declare function withEsbuildMinify(config: MetroConfig): MetroConfig;
339
339
  declare function withWasmSupport(config: MetroConfig): MetroConfig;
340
340
 
341
341
  /**
342
- * withTransformLogger — Metro bundle 整体耗时日志
342
+ * withTransformLogger — Metro bundle 整体耗时日志 + 单文件 transform 耗时日志
343
343
  *
344
- * 通过 unstable_perfLoggerFactory 收集每次 bundle 请求的性能数据,写入 JSONL 文件。
345
- * 该回调在主进程执行,不受 --max-workers 多进程影响。
344
+ * 写入两类 JSONL 条目:
346
345
  *
347
- * 激活条件(两者同时满足):
348
- * 1. 环境变量 METRO_TRANSFORM_LOG 设置为目标文件路径
349
- * 2. 当前处于开发模式(__DEV__ === true),expo export 生产构建时不记录
350
- *
351
- * 每行格式(一次 bundle 请求写一条):
346
+ * 1. BUNDLING_REQUEST — 每次完整 bundle 请求写一条(通过 unstable_perfLoggerFactory)
352
347
  * {
353
- * "type": "BUNDLING_REQUEST", // START_UP | BUNDLING_REQUEST | HMR
348
+ * "type": "BUNDLING_REQUEST",
354
349
  * "status": "SUCCESS", // SUCCESS | FAIL | CANCEL
355
350
  * "duration_ms": 1234,
356
351
  * "bundle_url": "index.bundle",
357
352
  * "initial_build": true, // true=首次构建 false=增量更新
358
- * "graph_node_count": 220, // 模块数量
359
- * "bundle_length": 512000, // bundle 字节数
360
- * "points": { // 各阶段耗时(ms,从 start 计算)
353
+ * "graph_node_count": 220,
354
+ * "bundle_length": 512000,
355
+ * "points": {
361
356
  * "resolvingAndTransformingDependencies_start": 5,
362
357
  * "resolvingAndTransformingDependencies_end": 980,
363
358
  * "serializingBundle_start": 981,
364
359
  * "serializingBundle_end": 1200
365
360
  * },
366
- * "t": 1234567890 // bundle 完成时的时间戳
361
+ * "t": 1234567890
367
362
  * }
363
+ *
364
+ * 2. TRANSFORM_FILE — 每个 cache miss 的文件写一条(通过 metro-core Logger)
365
+ * {
366
+ * "type": "TRANSFORM_FILE",
367
+ * "file": "src/components/Button.tsx",
368
+ * "duration_ms": 45,
369
+ * "t": 1234567890
370
+ * }
371
+ * 注意:缓存命中的文件不会触发此条目。
372
+ *
373
+ * 激活条件(两者同时满足):
374
+ * 1. 环境变量 METRO_TRANSFORM_LOG 设置为目标文件路径
375
+ * 2. 当前处于开发模式(__DEV__ === true),expo export 生产构建时不记录
368
376
  */
369
377
 
370
378
  /**
371
- * 在开发模式下,若 METRO_TRANSFORM_LOG 已设置,则注入 unstable_perfLoggerFactory。
379
+ * 在开发模式下,若 METRO_TRANSFORM_LOG 已设置,则注入:
380
+ * - unstable_perfLoggerFactory(整体 bundle 耗时)
381
+ * - metro-core Logger 监听器(单文件 transform 耗时,仅 cache miss)
372
382
  */
373
383
  declare function withTransformLogger(config: MetroConfig): MetroConfig;
374
384
 
package/dist/metro.js CHANGED
@@ -443,6 +443,7 @@ function withWasmSupport(config) {
443
443
  // src/metro/withTransformLogger.ts
444
444
  var import_node_fs = __toESM(require("fs"));
445
445
  var import_node_path = __toESM(require("path"));
446
+ var import_metro_core = require("metro-core");
446
447
  function installPerfLogger(logFile, existingFactory) {
447
448
  const dir = import_node_path.default.dirname(logFile);
448
449
  if (!import_node_fs.default.existsSync(dir)) {
@@ -490,11 +491,28 @@ function installPerfLogger(logFile, existingFactory) {
490
491
  return logger;
491
492
  };
492
493
  }
494
+ var fileLoggerInstalled = false;
495
+ function installFileLogger(logFile) {
496
+ if (fileLoggerInstalled) return;
497
+ fileLoggerInstalled = true;
498
+ import_metro_core.Logger.on("log", (entry) => {
499
+ if (entry.action_name === "Transforming file" && entry.action_phase === "end") {
500
+ const line = JSON.stringify({
501
+ type: "TRANSFORM_FILE",
502
+ file: entry.file_name,
503
+ duration_ms: entry.duration_ms,
504
+ t: Date.now()
505
+ });
506
+ import_node_fs.default.appendFileSync(logFile, line + "\n");
507
+ }
508
+ });
509
+ }
493
510
  function withTransformLogger(config) {
494
511
  const logFile = process.env["METRO_TRANSFORM_LOG"];
495
512
  if (!logFile) return config;
496
513
  const isDev = typeof __DEV__ !== "undefined" ? __DEV__ : process.env["NODE_ENV"] !== "production";
497
514
  if (!isDev) return config;
515
+ installFileLogger(logFile);
498
516
  return {
499
517
  ...config,
500
518
  unstable_perfLoggerFactory: installPerfLogger(logFile, config.unstable_perfLoggerFactory)
package/dist/metro.mjs CHANGED
@@ -399,6 +399,7 @@ function withWasmSupport(config) {
399
399
  // src/metro/withTransformLogger.ts
400
400
  import fs4 from "fs";
401
401
  import path12 from "path";
402
+ import { Logger } from "metro-core";
402
403
  function installPerfLogger(logFile, existingFactory) {
403
404
  const dir = path12.dirname(logFile);
404
405
  if (!fs4.existsSync(dir)) {
@@ -446,11 +447,28 @@ function installPerfLogger(logFile, existingFactory) {
446
447
  return logger;
447
448
  };
448
449
  }
450
+ var fileLoggerInstalled = false;
451
+ function installFileLogger(logFile) {
452
+ if (fileLoggerInstalled) return;
453
+ fileLoggerInstalled = true;
454
+ Logger.on("log", (entry) => {
455
+ if (entry.action_name === "Transforming file" && entry.action_phase === "end") {
456
+ const line = JSON.stringify({
457
+ type: "TRANSFORM_FILE",
458
+ file: entry.file_name,
459
+ duration_ms: entry.duration_ms,
460
+ t: Date.now()
461
+ });
462
+ fs4.appendFileSync(logFile, line + "\n");
463
+ }
464
+ });
465
+ }
449
466
  function withTransformLogger(config) {
450
467
  const logFile = process.env["METRO_TRANSFORM_LOG"];
451
468
  if (!logFile) return config;
452
469
  const isDev = typeof __DEV__ !== "undefined" ? __DEV__ : process.env["NODE_ENV"] !== "production";
453
470
  if (!isDev) return config;
471
+ installFileLogger(logFile);
454
472
  return {
455
473
  ...config,
456
474
  unstable_perfLoggerFactory: installPerfLogger(logFile, config.unstable_perfLoggerFactory)
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/rules/no-inline-box-shadow-string.ts
21
+ var no_inline_box_shadow_string_exports = {};
22
+ __export(no_inline_box_shadow_string_exports, {
23
+ default: () => no_inline_box_shadow_string_default
24
+ });
25
+ module.exports = __toCommonJS(no_inline_box_shadow_string_exports);
26
+ var noInlineBoxShadowStringRule = {
27
+ meta: {
28
+ type: "problem",
29
+ docs: {
30
+ description: "Disallow boxShadow string in inline style objects. NativeWind drops all styles including backgroundColor on Android when a function-style prop contains a boxShadow string."
31
+ },
32
+ schema: [],
33
+ messages: {
34
+ noInlineBoxShadowString: 'boxShadow string in inline style is not supported by NativeWind on Android \u2014 it causes backgroundColor and other styles to be lost. Use the object form instead: boxShadow: [{ offsetX: 0, offsetY: 4, blurRadius: 12, color: "rgba(33,150,243,0.35)" }], or replace with elevation + shadowColor for Android.'
35
+ }
36
+ },
37
+ create(context) {
38
+ return {
39
+ // 匹配所有属性键为 boxShadow 且值为字符串字面量的节点。
40
+ // 覆盖两种写法:
41
+ // style={{ boxShadow: '...' }}
42
+ // style={({ pressed }) => ({ boxShadow: '...' })}
43
+ Property(node) {
44
+ if (node.key.type === "Identifier" && node.key.name === "boxShadow" && node.value.type === "Literal" && typeof node.value.value === "string") {
45
+ context.report({ node, messageId: "noInlineBoxShadowString" });
46
+ }
47
+ }
48
+ };
49
+ }
50
+ };
51
+ var plugin = {
52
+ meta: { name: "no-inline-box-shadow-string" },
53
+ rules: { "no-inline-box-shadow-string": noInlineBoxShadowStringRule }
54
+ };
55
+ var no_inline_box_shadow_string_default = plugin;
56
+ module.exports = module.exports.default;
@@ -218,6 +218,9 @@ class EditorController {
218
218
  case "editor-delete":
219
219
  this.deleteActiveNode();
220
220
  break;
221
+ case "editor-text-update":
222
+ this.updateActiveNodeText(e);
223
+ break;
221
224
  }
222
225
  };
223
226
  }
@@ -360,6 +363,16 @@ class EditorController {
360
363
  this.activeNode = null;
361
364
  postToParent("iframe-node-clear");
362
365
  }
366
+ /**
367
+ * 更新选中元素的文本内容
368
+ */
369
+ updateActiveNodeText(e) {
370
+ if (!this.activeNode) return;
371
+ const text = e.data.value;
372
+ if (typeof text !== "string") return;
373
+ const node = this.activeNode;
374
+ node.innerHTML = text;
375
+ }
363
376
  }
364
377
  let controller = null;
365
378
  function onGlobalMessage(e) {
@@ -10,7 +10,8 @@
10
10
  { "name": "expo-router-layout", "specifier": "miaoda-expo-devkit/rules/no-invalid-tabs-screen" },
11
11
  { "name": "expo-router-dynamic-tab", "specifier": "miaoda-expo-devkit/rules/no-unregistered-dynamic-tab-route" },
12
12
  { "name": "rn-pressable", "specifier": "miaoda-expo-devkit/rules/no-pressable-without-on-press" },
13
- { "name": "expo-video-compat", "specifier": "miaoda-expo-devkit/rules/no-expo-video-compat" }
13
+ { "name": "expo-video-compat", "specifier": "miaoda-expo-devkit/rules/no-expo-video-compat" },
14
+ { "name": "rn-style", "specifier": "miaoda-expo-devkit/rules/no-inline-box-shadow-string" }
14
15
  ],
15
16
 
16
17
  "categories": {
@@ -27,6 +28,7 @@
27
28
  "expo-router-dynamic-tab/no-unregistered-dynamic-tab-route": "error",
28
29
  "rn-pressable/no-pressable-without-on-press": "error",
29
30
  "expo-video-compat/no-expo-video-compat": "warn",
31
+ "rn-style/no-inline-box-shadow-string": "error",
30
32
 
31
33
  "expo/no-dynamic-env-var": "error",
32
34
  "expo/no-env-var-destructuring": "error",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "miaoda-expo-devkit",
3
- "version": "0.1.1-beta.46",
3
+ "version": "0.1.1-beta.47",
4
4
  "description": "Expo 应用开发工具集:Sentry DSN 替换 stub、错误/网络捕获、Metro 符号化",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.js",
@@ -58,6 +58,7 @@
58
58
  "./rules/no-expo-audio-compat": "./dist/rules/no-expo-audio-compat.js",
59
59
  "./rules/no-pressable-without-on-press": "./dist/rules/no-pressable-without-on-press.js",
60
60
  "./rules/no-expo-video-compat": "./dist/rules/no-expo-video-compat.js",
61
+ "./rules/no-inline-box-shadow-string": "./dist/rules/no-inline-box-shadow-string.js",
61
62
  "./biome": "./biome-config.json",
62
63
  "./oxlint": "./oxlint-config.json",
63
64
  "./tsconfig-base": "./tsconfig-base.json"
@@ -83,6 +84,7 @@
83
84
  "@sentry/react-native": ">=8.0.0",
84
85
  "metro": ">=0.80.0",
85
86
  "metro-config": ">=0.80.0",
87
+ "metro-core": ">=0.80.0",
86
88
  "metro-resolver": ">=0.80.0",
87
89
  "nativewind": ">=4.0.0",
88
90
  "react-native": ">=0.79.0",
@@ -102,6 +104,9 @@
102
104
  "metro-config": {
103
105
  "optional": true
104
106
  },
107
+ "metro-core": {
108
+ "optional": true
109
+ },
105
110
  "metro-resolver": {
106
111
  "optional": true
107
112
  },