miaoda-expo-devkit 0.1.1-beta.45 → 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 +32 -8
- package/dist/metro.d.ts +32 -8
- package/dist/metro.js +62 -13
- package/dist/metro.mjs +61 -12
- package/dist/rules/no-inline-box-shadow-string.js +56 -0
- package/oxlint-config.json +5 -2
- package/package.json +2 -1
package/dist/metro.d.mts
CHANGED
|
@@ -339,22 +339,46 @@ declare function withEsbuildMinify(config: MetroConfig): MetroConfig;
|
|
|
339
339
|
declare function withWasmSupport(config: MetroConfig): MetroConfig;
|
|
340
340
|
|
|
341
341
|
/**
|
|
342
|
-
* withTransformLogger — Metro 单文件 transform 耗时日志
|
|
342
|
+
* withTransformLogger — Metro bundle 整体耗时日志 + 单文件 transform 耗时日志
|
|
343
343
|
*
|
|
344
|
-
*
|
|
344
|
+
* 写入两类 JSONL 条目:
|
|
345
|
+
*
|
|
346
|
+
* 1. BUNDLING_REQUEST — 每次完整 bundle 请求写一条(通过 unstable_perfLoggerFactory)
|
|
347
|
+
* {
|
|
348
|
+
* "type": "BUNDLING_REQUEST",
|
|
349
|
+
* "status": "SUCCESS", // SUCCESS | FAIL | CANCEL
|
|
350
|
+
* "duration_ms": 1234,
|
|
351
|
+
* "bundle_url": "index.bundle",
|
|
352
|
+
* "initial_build": true, // true=首次构建 false=增量更新
|
|
353
|
+
* "graph_node_count": 220,
|
|
354
|
+
* "bundle_length": 512000,
|
|
355
|
+
* "points": {
|
|
356
|
+
* "resolvingAndTransformingDependencies_start": 5,
|
|
357
|
+
* "resolvingAndTransformingDependencies_end": 980,
|
|
358
|
+
* "serializingBundle_start": 981,
|
|
359
|
+
* "serializingBundle_end": 1200
|
|
360
|
+
* },
|
|
361
|
+
* "t": 1234567890
|
|
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
|
+
* 注意:缓存命中的文件不会触发此条目。
|
|
345
372
|
*
|
|
346
373
|
* 激活条件(两者同时满足):
|
|
347
374
|
* 1. 环境变量 METRO_TRANSFORM_LOG 设置为目标文件路径
|
|
348
375
|
* 2. 当前处于开发模式(__DEV__ === true),expo export 生产构建时不记录
|
|
349
|
-
*
|
|
350
|
-
* 每行格式:
|
|
351
|
-
* {"phase":"start","file":"...","duration_ms":null,"t":1234567890}
|
|
352
|
-
* {"phase":"end","file":"...","duration_ms":42,"t":1234567890}
|
|
353
376
|
*/
|
|
354
377
|
|
|
355
378
|
/**
|
|
356
|
-
* 在开发模式下,若 METRO_TRANSFORM_LOG
|
|
357
|
-
*
|
|
379
|
+
* 在开发模式下,若 METRO_TRANSFORM_LOG 已设置,则注入:
|
|
380
|
+
* - unstable_perfLoggerFactory(整体 bundle 耗时)
|
|
381
|
+
* - metro-core Logger 监听器(单文件 transform 耗时,仅 cache miss)
|
|
358
382
|
*/
|
|
359
383
|
declare function withTransformLogger(config: MetroConfig): MetroConfig;
|
|
360
384
|
|
package/dist/metro.d.ts
CHANGED
|
@@ -339,22 +339,46 @@ declare function withEsbuildMinify(config: MetroConfig): MetroConfig;
|
|
|
339
339
|
declare function withWasmSupport(config: MetroConfig): MetroConfig;
|
|
340
340
|
|
|
341
341
|
/**
|
|
342
|
-
* withTransformLogger — Metro 单文件 transform 耗时日志
|
|
342
|
+
* withTransformLogger — Metro bundle 整体耗时日志 + 单文件 transform 耗时日志
|
|
343
343
|
*
|
|
344
|
-
*
|
|
344
|
+
* 写入两类 JSONL 条目:
|
|
345
|
+
*
|
|
346
|
+
* 1. BUNDLING_REQUEST — 每次完整 bundle 请求写一条(通过 unstable_perfLoggerFactory)
|
|
347
|
+
* {
|
|
348
|
+
* "type": "BUNDLING_REQUEST",
|
|
349
|
+
* "status": "SUCCESS", // SUCCESS | FAIL | CANCEL
|
|
350
|
+
* "duration_ms": 1234,
|
|
351
|
+
* "bundle_url": "index.bundle",
|
|
352
|
+
* "initial_build": true, // true=首次构建 false=增量更新
|
|
353
|
+
* "graph_node_count": 220,
|
|
354
|
+
* "bundle_length": 512000,
|
|
355
|
+
* "points": {
|
|
356
|
+
* "resolvingAndTransformingDependencies_start": 5,
|
|
357
|
+
* "resolvingAndTransformingDependencies_end": 980,
|
|
358
|
+
* "serializingBundle_start": 981,
|
|
359
|
+
* "serializingBundle_end": 1200
|
|
360
|
+
* },
|
|
361
|
+
* "t": 1234567890
|
|
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
|
+
* 注意:缓存命中的文件不会触发此条目。
|
|
345
372
|
*
|
|
346
373
|
* 激活条件(两者同时满足):
|
|
347
374
|
* 1. 环境变量 METRO_TRANSFORM_LOG 设置为目标文件路径
|
|
348
375
|
* 2. 当前处于开发模式(__DEV__ === true),expo export 生产构建时不记录
|
|
349
|
-
*
|
|
350
|
-
* 每行格式:
|
|
351
|
-
* {"phase":"start","file":"...","duration_ms":null,"t":1234567890}
|
|
352
|
-
* {"phase":"end","file":"...","duration_ms":42,"t":1234567890}
|
|
353
376
|
*/
|
|
354
377
|
|
|
355
378
|
/**
|
|
356
|
-
* 在开发模式下,若 METRO_TRANSFORM_LOG
|
|
357
|
-
*
|
|
379
|
+
* 在开发模式下,若 METRO_TRANSFORM_LOG 已设置,则注入:
|
|
380
|
+
* - unstable_perfLoggerFactory(整体 bundle 耗时)
|
|
381
|
+
* - metro-core Logger 监听器(单文件 transform 耗时,仅 cache miss)
|
|
358
382
|
*/
|
|
359
383
|
declare function withTransformLogger(config: MetroConfig): MetroConfig;
|
|
360
384
|
|
package/dist/metro.js
CHANGED
|
@@ -443,22 +443,68 @@ 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
|
-
|
|
447
|
-
|
|
446
|
+
var import_metro_core = require("metro-core");
|
|
447
|
+
function installPerfLogger(logFile, existingFactory) {
|
|
448
448
|
const dir = import_node_path.default.dirname(logFile);
|
|
449
449
|
if (!import_node_fs.default.existsSync(dir)) {
|
|
450
450
|
import_node_fs.default.mkdirSync(dir, { recursive: true });
|
|
451
451
|
}
|
|
452
452
|
import_node_fs.default.writeFileSync(logFile, "");
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
const
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
453
|
+
return (type, opts) => {
|
|
454
|
+
const upstream = existingFactory?.(type, opts) ?? null;
|
|
455
|
+
const startTime = process.hrtime.bigint();
|
|
456
|
+
const points = {};
|
|
457
|
+
const annotations = {};
|
|
458
|
+
const logger = {
|
|
459
|
+
start() {
|
|
460
|
+
upstream?.start?.();
|
|
461
|
+
},
|
|
462
|
+
end(status) {
|
|
463
|
+
const duration_ms = Number(process.hrtime.bigint() - startTime) / 1e6;
|
|
464
|
+
const line = JSON.stringify({
|
|
465
|
+
type,
|
|
466
|
+
status,
|
|
467
|
+
duration_ms: Math.round(duration_ms),
|
|
468
|
+
...annotations,
|
|
469
|
+
points,
|
|
470
|
+
t: Date.now()
|
|
471
|
+
});
|
|
472
|
+
import_node_fs.default.appendFileSync(logFile, line + "\n");
|
|
473
|
+
upstream?.end?.(status);
|
|
474
|
+
},
|
|
475
|
+
annotate(ann) {
|
|
476
|
+
for (const [, kv] of Object.entries(ann)) {
|
|
477
|
+
if (kv && typeof kv === "object") {
|
|
478
|
+
Object.assign(annotations, kv);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
upstream?.annotate?.(ann);
|
|
482
|
+
},
|
|
483
|
+
point(name) {
|
|
484
|
+
points[name] = Math.round(Number(process.hrtime.bigint() - startTime) / 1e6);
|
|
485
|
+
upstream?.point?.(name);
|
|
486
|
+
},
|
|
487
|
+
subSpan(label) {
|
|
488
|
+
return upstream?.subSpan?.(label) ?? logger;
|
|
489
|
+
}
|
|
490
|
+
};
|
|
491
|
+
return logger;
|
|
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
|
+
}
|
|
462
508
|
});
|
|
463
509
|
}
|
|
464
510
|
function withTransformLogger(config) {
|
|
@@ -466,8 +512,11 @@ function withTransformLogger(config) {
|
|
|
466
512
|
if (!logFile) return config;
|
|
467
513
|
const isDev = typeof __DEV__ !== "undefined" ? __DEV__ : process.env["NODE_ENV"] !== "production";
|
|
468
514
|
if (!isDev) return config;
|
|
469
|
-
|
|
470
|
-
return
|
|
515
|
+
installFileLogger(logFile);
|
|
516
|
+
return {
|
|
517
|
+
...config,
|
|
518
|
+
unstable_perfLoggerFactory: installPerfLogger(logFile, config.unstable_perfLoggerFactory)
|
|
519
|
+
};
|
|
471
520
|
}
|
|
472
521
|
|
|
473
522
|
// src/metro/withDevkit.ts
|
package/dist/metro.mjs
CHANGED
|
@@ -399,22 +399,68 @@ function withWasmSupport(config) {
|
|
|
399
399
|
// src/metro/withTransformLogger.ts
|
|
400
400
|
import fs4 from "fs";
|
|
401
401
|
import path12 from "path";
|
|
402
|
-
|
|
403
|
-
|
|
402
|
+
import { Logger } from "metro-core";
|
|
403
|
+
function installPerfLogger(logFile, existingFactory) {
|
|
404
404
|
const dir = path12.dirname(logFile);
|
|
405
405
|
if (!fs4.existsSync(dir)) {
|
|
406
406
|
fs4.mkdirSync(dir, { recursive: true });
|
|
407
407
|
}
|
|
408
408
|
fs4.writeFileSync(logFile, "");
|
|
409
|
+
return (type, opts) => {
|
|
410
|
+
const upstream = existingFactory?.(type, opts) ?? null;
|
|
411
|
+
const startTime = process.hrtime.bigint();
|
|
412
|
+
const points = {};
|
|
413
|
+
const annotations = {};
|
|
414
|
+
const logger = {
|
|
415
|
+
start() {
|
|
416
|
+
upstream?.start?.();
|
|
417
|
+
},
|
|
418
|
+
end(status) {
|
|
419
|
+
const duration_ms = Number(process.hrtime.bigint() - startTime) / 1e6;
|
|
420
|
+
const line = JSON.stringify({
|
|
421
|
+
type,
|
|
422
|
+
status,
|
|
423
|
+
duration_ms: Math.round(duration_ms),
|
|
424
|
+
...annotations,
|
|
425
|
+
points,
|
|
426
|
+
t: Date.now()
|
|
427
|
+
});
|
|
428
|
+
fs4.appendFileSync(logFile, line + "\n");
|
|
429
|
+
upstream?.end?.(status);
|
|
430
|
+
},
|
|
431
|
+
annotate(ann) {
|
|
432
|
+
for (const [, kv] of Object.entries(ann)) {
|
|
433
|
+
if (kv && typeof kv === "object") {
|
|
434
|
+
Object.assign(annotations, kv);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
upstream?.annotate?.(ann);
|
|
438
|
+
},
|
|
439
|
+
point(name) {
|
|
440
|
+
points[name] = Math.round(Number(process.hrtime.bigint() - startTime) / 1e6);
|
|
441
|
+
upstream?.point?.(name);
|
|
442
|
+
},
|
|
443
|
+
subSpan(label) {
|
|
444
|
+
return upstream?.subSpan?.(label) ?? logger;
|
|
445
|
+
}
|
|
446
|
+
};
|
|
447
|
+
return logger;
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
var fileLoggerInstalled = false;
|
|
451
|
+
function installFileLogger(logFile) {
|
|
452
|
+
if (fileLoggerInstalled) return;
|
|
453
|
+
fileLoggerInstalled = true;
|
|
409
454
|
Logger.on("log", (entry) => {
|
|
410
|
-
if (entry
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
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
|
+
}
|
|
418
464
|
});
|
|
419
465
|
}
|
|
420
466
|
function withTransformLogger(config) {
|
|
@@ -422,8 +468,11 @@ function withTransformLogger(config) {
|
|
|
422
468
|
if (!logFile) return config;
|
|
423
469
|
const isDev = typeof __DEV__ !== "undefined" ? __DEV__ : process.env["NODE_ENV"] !== "production";
|
|
424
470
|
if (!isDev) return config;
|
|
425
|
-
|
|
426
|
-
return
|
|
471
|
+
installFileLogger(logFile);
|
|
472
|
+
return {
|
|
473
|
+
...config,
|
|
474
|
+
unstable_perfLoggerFactory: installPerfLogger(logFile, config.unstable_perfLoggerFactory)
|
|
475
|
+
};
|
|
427
476
|
}
|
|
428
477
|
|
|
429
478
|
// src/metro/withDevkit.ts
|
|
@@ -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;
|
package/oxlint-config.json
CHANGED
|
@@ -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",
|
|
@@ -48,7 +50,8 @@
|
|
|
48
50
|
"metro.config.js",
|
|
49
51
|
"babel.config.js",
|
|
50
52
|
".pnpmfile.cjs",
|
|
51
|
-
"output/**"
|
|
53
|
+
"output/**",
|
|
54
|
+
"supabase/**"
|
|
52
55
|
],
|
|
53
56
|
|
|
54
57
|
"overrides": [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "miaoda-expo-devkit",
|
|
3
|
-
"version": "0.1.1-beta.
|
|
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"
|