miaoda-expo-devkit 0.1.1-beta.25 → 0.1.1-beta.27
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/babel/plugin-lucide-react-native.d.ts +6 -0
- package/dist/babel/plugin-lucide-react-native.js +30 -24
- package/dist/metro.d.mts +67 -72
- package/dist/metro.d.ts +67 -72
- package/dist/metro.js +31 -15
- package/dist/metro.mjs +30 -15
- package/package.json +1 -27
|
@@ -18,6 +18,12 @@ interface Config extends babelCore.PluginPass {
|
|
|
18
18
|
opts: {
|
|
19
19
|
/** 使用 ESM 格式(dist/esm)。默认 false,使用 CJS(dist/cjs)。 */
|
|
20
20
|
useES?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* lucide-react-native 包根目录的绝对路径(含 package.json 的那一层)。
|
|
23
|
+
* 不传时通过 require.resolve 自动定位,适用于生产场景。
|
|
24
|
+
* 测试时可传入特定版本的路径,验证不同版本的兼容性。
|
|
25
|
+
*/
|
|
26
|
+
lucidePkgRoot?: string;
|
|
21
27
|
};
|
|
22
28
|
}
|
|
23
29
|
declare function lucideReactNativePlugin({ types: t }: Core): babelCore.PluginObj<Config>;
|
|
@@ -14591,8 +14591,8 @@ var import_node_fs = __toESM(require("fs"));
|
|
|
14591
14591
|
var import_node_path = __toESM(require("path"));
|
|
14592
14592
|
var import_helper_module_imports = __toESM(require_lib4());
|
|
14593
14593
|
var LUCIDE_REACT_NATIVE = "lucide-react-native";
|
|
14594
|
-
function resolveIconsLocation(moduleDir) {
|
|
14595
|
-
const lucideDistPath = import_node_path.default.dirname(import_node_path.default.dirname(require.resolve(LUCIDE_REACT_NATIVE)));
|
|
14594
|
+
function resolveIconsLocation(moduleDir, pkgRoot) {
|
|
14595
|
+
const lucideDistPath = pkgRoot ? import_node_path.default.join(pkgRoot, "dist") : import_node_path.default.dirname(import_node_path.default.dirname(require.resolve(LUCIDE_REACT_NATIVE)));
|
|
14596
14596
|
if (moduleDir === "cjs") {
|
|
14597
14597
|
const withSubdir = import_node_path.default.join(lucideDistPath, "cjs/icons");
|
|
14598
14598
|
const hasSubdir = import_node_fs.default.existsSync(withSubdir);
|
|
@@ -14611,12 +14611,14 @@ function resolveIconsLocation(moduleDir) {
|
|
|
14611
14611
|
};
|
|
14612
14612
|
}
|
|
14613
14613
|
var iconMapCache = /* @__PURE__ */ new Map();
|
|
14614
|
-
var
|
|
14615
|
-
function buildAliasMap(moduleDir) {
|
|
14616
|
-
|
|
14617
|
-
const
|
|
14614
|
+
var aliasMapCache = /* @__PURE__ */ new Map();
|
|
14615
|
+
function buildAliasMap(moduleDir, pkgRoot) {
|
|
14616
|
+
const cacheKey = pkgRoot ?? "";
|
|
14617
|
+
const cached = aliasMapCache.get(cacheKey);
|
|
14618
|
+
if (cached) return cached;
|
|
14619
|
+
const { map: fileMap } = buildIconMap(moduleDir, pkgRoot);
|
|
14618
14620
|
const map = /* @__PURE__ */ new Map();
|
|
14619
|
-
const lucideDistPath = import_node_path.default.dirname(import_node_path.default.dirname(require.resolve(LUCIDE_REACT_NATIVE)));
|
|
14621
|
+
const lucideDistPath = pkgRoot ? import_node_path.default.join(pkgRoot, "dist") : import_node_path.default.dirname(import_node_path.default.dirname(require.resolve(LUCIDE_REACT_NATIVE)));
|
|
14620
14622
|
const cjsBundle = import_node_path.default.join(lucideDistPath, "cjs/lucide-react-native.js");
|
|
14621
14623
|
if (import_node_fs.default.existsSync(cjsBundle)) {
|
|
14622
14624
|
const content = import_node_fs.default.readFileSync(cjsBundle, "utf-8");
|
|
@@ -14645,13 +14647,14 @@ function buildAliasMap(moduleDir) {
|
|
|
14645
14647
|
}
|
|
14646
14648
|
}
|
|
14647
14649
|
}
|
|
14648
|
-
|
|
14650
|
+
aliasMapCache.set(cacheKey, map);
|
|
14649
14651
|
return map;
|
|
14650
14652
|
}
|
|
14651
|
-
function buildIconMap(moduleDir) {
|
|
14652
|
-
const
|
|
14653
|
+
function buildIconMap(moduleDir, pkgRoot) {
|
|
14654
|
+
const cacheKey = `${moduleDir}:${pkgRoot ?? ""}`;
|
|
14655
|
+
const cached = iconMapCache.get(cacheKey);
|
|
14653
14656
|
if (cached) return cached;
|
|
14654
|
-
const { dir, ext, importBasePath } = resolveIconsLocation(moduleDir);
|
|
14657
|
+
const { dir, ext, importBasePath } = resolveIconsLocation(moduleDir, pkgRoot);
|
|
14655
14658
|
const map = /* @__PURE__ */ new Map();
|
|
14656
14659
|
for (const file of import_node_fs.default.readdirSync(dir)) {
|
|
14657
14660
|
if (!file.endsWith(ext) || file.endsWith(".map")) continue;
|
|
@@ -14659,15 +14662,15 @@ function buildIconMap(moduleDir) {
|
|
|
14659
14662
|
map.set(slug.replace(/-/g, ""), slug);
|
|
14660
14663
|
}
|
|
14661
14664
|
const data = { map, importBasePath };
|
|
14662
|
-
iconMapCache.set(
|
|
14665
|
+
iconMapCache.set(cacheKey, data);
|
|
14663
14666
|
return data;
|
|
14664
14667
|
}
|
|
14665
|
-
function resolveModule(useES, name) {
|
|
14668
|
+
function resolveModule(useES, name, pkgRoot) {
|
|
14666
14669
|
const moduleDir = useES ? "esm" : "cjs";
|
|
14667
|
-
const { map, importBasePath } = buildIconMap(moduleDir);
|
|
14670
|
+
const { map, importBasePath } = buildIconMap(moduleDir, pkgRoot);
|
|
14668
14671
|
let slug = map.get(name.toLowerCase());
|
|
14669
14672
|
if (!slug) {
|
|
14670
|
-
const canonical = buildAliasMap(moduleDir).get(name.toLowerCase());
|
|
14673
|
+
const canonical = buildAliasMap(moduleDir, pkgRoot).get(name.toLowerCase());
|
|
14671
14674
|
if (canonical) {
|
|
14672
14675
|
slug = map.get(canonical);
|
|
14673
14676
|
}
|
|
@@ -14688,23 +14691,26 @@ function lucideReactNativePlugin({ types: t }) {
|
|
|
14688
14691
|
let selectedIcons = /* @__PURE__ */ Object.create(null);
|
|
14689
14692
|
let specifiedLocal4Imported = /* @__PURE__ */ Object.create(null);
|
|
14690
14693
|
let removablePaths = [];
|
|
14691
|
-
function importMethod(useES, iconName, nodePath, nameHint) {
|
|
14694
|
+
function importMethod(useES, iconName, nodePath, nameHint, pkgRoot) {
|
|
14692
14695
|
const existedImport = selectedIcons[iconName];
|
|
14693
14696
|
if (existedImport) {
|
|
14694
14697
|
return t.cloneNode(existedImport);
|
|
14695
14698
|
}
|
|
14696
|
-
const identifier = (0, import_helper_module_imports.addDefault)(nodePath, resolveModule(useES, iconName), { nameHint });
|
|
14699
|
+
const identifier = (0, import_helper_module_imports.addDefault)(nodePath, resolveModule(useES, iconName, pkgRoot), { nameHint });
|
|
14697
14700
|
selectedIcons[iconName] = identifier;
|
|
14698
14701
|
return t.cloneNode(identifier);
|
|
14699
14702
|
}
|
|
14700
14703
|
function matchesLucideIcon(nodePath, localName) {
|
|
14701
|
-
|
|
14704
|
+
if (!specifiedLocal4Imported[localName]) return false;
|
|
14705
|
+
const binding = nodePath.scope.getBinding(localName);
|
|
14706
|
+
if (!binding) return true;
|
|
14707
|
+
return binding.path.type === "ImportSpecifier";
|
|
14702
14708
|
}
|
|
14703
|
-
function replaceIconRef(nodePath, useES, makeNode) {
|
|
14709
|
+
function replaceIconRef(nodePath, useES, makeNode, pkgRoot) {
|
|
14704
14710
|
const localName = nodePath.node.name;
|
|
14705
14711
|
const iconImportedName = specifiedLocal4Imported[localName];
|
|
14706
14712
|
if (!iconImportedName || !matchesLucideIcon(nodePath, localName) || isSpecialTypes(t, nodePath.parent, nodePath.node)) return;
|
|
14707
|
-
const newNode = importMethod(useES, iconImportedName, nodePath, localName);
|
|
14713
|
+
const newNode = importMethod(useES, iconImportedName, nodePath, localName, pkgRoot);
|
|
14708
14714
|
nodePath.replaceWith(makeNode(newNode.name, nodePath.node));
|
|
14709
14715
|
}
|
|
14710
14716
|
return {
|
|
@@ -14742,7 +14748,7 @@ function lucideReactNativePlugin({ types: t }) {
|
|
|
14742
14748
|
// 将 re-export 转换为:先插入各图标的默认导入,再导出本地标识符
|
|
14743
14749
|
ExportNamedDeclaration(nodePath, state) {
|
|
14744
14750
|
const { node } = nodePath;
|
|
14745
|
-
const { useES = false } = state.opts;
|
|
14751
|
+
const { useES = false, lucidePkgRoot } = state.opts;
|
|
14746
14752
|
if (!node.source || node.source.value !== LUCIDE_REACT_NATIVE) return;
|
|
14747
14753
|
const specifiers = [];
|
|
14748
14754
|
node.specifiers.forEach((spec) => {
|
|
@@ -14753,7 +14759,7 @@ function lucideReactNativePlugin({ types: t }) {
|
|
|
14753
14759
|
}
|
|
14754
14760
|
const exportedName = t.isIdentifier(spec.exported) ? spec.exported.name : spec.exported.value;
|
|
14755
14761
|
const localName = spec.local.name;
|
|
14756
|
-
const importIdentifier = importMethod(useES, localName, nodePath, exportedName);
|
|
14762
|
+
const importIdentifier = importMethod(useES, localName, nodePath, exportedName, lucidePkgRoot);
|
|
14757
14763
|
specifiers.push(t.exportSpecifier(importIdentifier, t.identifier(exportedName)));
|
|
14758
14764
|
});
|
|
14759
14765
|
node.specifiers = specifiers;
|
|
@@ -14769,14 +14775,14 @@ function lucideReactNativePlugin({ types: t }) {
|
|
|
14769
14775
|
},
|
|
14770
14776
|
// 处理 JSX 中的图标使用:<Star /> <BookHeart size={24} />
|
|
14771
14777
|
JSXIdentifier(nodePath, state) {
|
|
14772
|
-
replaceIconRef(nodePath, state.opts.useES ?? false, (name) => t.jsxIdentifier(name));
|
|
14778
|
+
replaceIconRef(nodePath, state.opts.useES ?? false, (name) => t.jsxIdentifier(name), state.opts.lucidePkgRoot);
|
|
14773
14779
|
},
|
|
14774
14780
|
// 处理非 JSX 场景中的图标引用:React.createElement(Star)、const icon = Star
|
|
14775
14781
|
Identifier(nodePath, state) {
|
|
14776
14782
|
replaceIconRef(nodePath, state.opts.useES ?? false, (name, orig) => ({
|
|
14777
14783
|
type: orig.type,
|
|
14778
14784
|
name
|
|
14779
|
-
}));
|
|
14785
|
+
}), state.opts.lucidePkgRoot);
|
|
14780
14786
|
}
|
|
14781
14787
|
}
|
|
14782
14788
|
};
|
package/dist/metro.d.mts
CHANGED
|
@@ -58,37 +58,18 @@ declare function withNativeWind(config: MetroConfig, options?: any): MetroConfig
|
|
|
58
58
|
/**
|
|
59
59
|
* withEntryInjection — 在 expo-router 启动前注入脚本
|
|
60
60
|
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
* (注入脚本),再 require expo-router/entry-classic(原入口),
|
|
65
|
-
* 从而在 expo-router 启动前执行注入逻辑。
|
|
61
|
+
* 拦截 expo-router/entry-classic 的解析,重定向到 expo-router-entry-stub.js。
|
|
62
|
+
* stub 先 require entry-inject.js,再 require expo-router/entry-classic,
|
|
63
|
+
* 使注入脚本在 expo-router renderRootComponent 之前执行。
|
|
66
64
|
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
* 不经过 resolveRequest。
|
|
70
|
-
* - expo-router/entry 内部第一行是 import 'expo-router/entry-classic',
|
|
71
|
-
* 这条 import 语句经过 resolveRequest,可以被拦截。
|
|
72
|
-
*
|
|
73
|
-
* 执行顺序(在 bundle 中):
|
|
74
|
-
* entry-inject.js → expo-router/entry-classic → renderRootComponent(App)
|
|
75
|
-
*
|
|
76
|
-
* 注入的脚本经过完整 Babel 编译,支持现代语法,web + native 双平台均有效。
|
|
77
|
-
* 支持与 withDevStubs 及其他 Metro wrapper 链式组合。
|
|
78
|
-
*
|
|
79
|
-
* 用法(metro.config.js):
|
|
80
|
-
* const { withEntryInjection } = require('miaoda-expo-devkit/metro');
|
|
81
|
-
* module.exports = withEntryInjection(withDevStubs(config));
|
|
65
|
+
* 拦截 entry-classic 而非 entry 本身:expo-router/entry 通过 <script src="...entry.bundle">
|
|
66
|
+
* 直接加载,不经过 resolveRequest;其内部的 import 'expo-router/entry-classic' 才经过 resolveRequest。
|
|
82
67
|
*/
|
|
83
68
|
|
|
84
|
-
/** withEntryInjection 的配置选项(预留,供未来支持自定义注入脚本路径扩展) */
|
|
85
69
|
interface InjectOptions {
|
|
86
70
|
}
|
|
87
71
|
/**
|
|
88
|
-
* 在 expo-router 启动前注入一段脚本。
|
|
89
|
-
*
|
|
90
72
|
* @param config Metro config 对象
|
|
91
|
-
* @param options 注入选项(当前预留,未来支持自定义注入脚本路径)
|
|
92
73
|
* @returns 注入 resolveRequest 后的新 Metro config
|
|
93
74
|
*/
|
|
94
75
|
declare function withEntryInjection(config: MetroConfig, options?: InjectOptions): MetroConfig;
|
|
@@ -129,12 +110,11 @@ declare function withRouteEndpoint(config: MetroConfig, options: RouteEndpointOp
|
|
|
129
110
|
/**
|
|
130
111
|
* withDevkit — 一站式 Metro 配置入口
|
|
131
112
|
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
* withLucideResolver — 消除 lucide 子路径未在 exports 中声明的警告
|
|
113
|
+
* 按固定顺序依次应用:
|
|
114
|
+
* withWorkspaceNodeModules — 修复沙箱中 node_modules 位于祖先目录时的模块解析问题
|
|
115
|
+
* withCssInterop — 为 expo-image / expo-camera 等注入 NativeWind cssInterop
|
|
116
|
+
* withEsbuildMinify — 将 Metro minifier 切换为 esbuild(仅生产构建生效)
|
|
117
|
+
* withLucideResolver — 消除 lucide 子路径未在 exports 声明时的 warning
|
|
138
118
|
* withExpoNotificationsStub — Android:expo-notifications → stub(Expo Go no-op,Dev Build 透传)
|
|
139
119
|
* withEntryInjection — 在 expo-router 启动前注入脚本(仅 __DEV__)
|
|
140
120
|
* withDevStubs — 替换 Sentry DSN / 屏蔽 LogBox(仅 __DEV__)
|
|
@@ -148,14 +128,6 @@ declare function withRouteEndpoint(config: MetroConfig, options: RouteEndpointOp
|
|
|
148
128
|
* module.exports = withDevkit(getDefaultConfig(__dirname));
|
|
149
129
|
*/
|
|
150
130
|
|
|
151
|
-
/**
|
|
152
|
-
* Android 平台:将 expo-notifications 替换为 stub。
|
|
153
|
-
* stub 内部根据 isRunningInExpoGo() 决定是 no-op(Expo Go)还是透传真实模块(Development Build)。
|
|
154
|
-
*
|
|
155
|
-
* 注意:此 wrapper 必须在 if (__DEV__) 外部调用,因为它需要在所有构建模式下生效。
|
|
156
|
-
* Expo Go 中 native module 的缺失是运行时问题,与开发/生产模式无关。
|
|
157
|
-
*/
|
|
158
|
-
declare function withExpoNotificationsStub(config: MetroConfig): MetroConfig;
|
|
159
131
|
/** withDevkit 的配置选项 */
|
|
160
132
|
interface DevkitOptions {
|
|
161
133
|
/**
|
|
@@ -174,23 +146,14 @@ interface DevkitOptions {
|
|
|
174
146
|
declare function withDevkit(config: MetroConfig, options?: DevkitOptions): MetroConfig;
|
|
175
147
|
|
|
176
148
|
/**
|
|
177
|
-
* withDevStubs —
|
|
149
|
+
* withDevStubs — 开发阶段模块替换
|
|
178
150
|
*
|
|
179
|
-
*
|
|
180
|
-
*
|
|
181
|
-
* 2. 所有平台:@sentry/react-native → sentry-react-native-stub(替换 DSN,注入内置捕获器)
|
|
182
|
-
*
|
|
183
|
-
* 自动保留并调用已有的 resolveRequest,支持与其他 Metro 配置链式组合。
|
|
184
|
-
*
|
|
185
|
-
* 用法(metro.config.js):
|
|
186
|
-
* const { withDevStubs } = require('miaoda-expo-devkit/metro');
|
|
187
|
-
* module.exports = withDevStubs(getDefaultConfig(__dirname));
|
|
151
|
+
* 1. web:@expo/log-box / ErrorOverlayWebControls → no-op stub(屏蔽全屏错误遮罩)
|
|
152
|
+
* 2. 所有平台:@sentry/react-native → stub(替换 DSN,注入内置捕获器)
|
|
188
153
|
*/
|
|
189
154
|
|
|
190
155
|
/**
|
|
191
|
-
*
|
|
192
|
-
*
|
|
193
|
-
* @param config Metro config 对象(来自 getDefaultConfig 或 getSentryExpoConfig)
|
|
156
|
+
* @param config Metro config 对象
|
|
194
157
|
* @returns 注入 resolveRequest 后的新 Metro config
|
|
195
158
|
*/
|
|
196
159
|
declare function withDevStubs(config: MetroConfig): MetroConfig;
|
|
@@ -231,37 +194,69 @@ declare function withWorkspaceNodeModules(config: MetroConfig): MetroConfig;
|
|
|
231
194
|
/**
|
|
232
195
|
* withCssInterop — 为第三方 Expo 组件注入 NativeWind cssInterop
|
|
233
196
|
*
|
|
234
|
-
*
|
|
235
|
-
* stub
|
|
236
|
-
* stub
|
|
197
|
+
* 在 Metro resolver 层拦截目标包的 import,重定向到对应 stub 文件。
|
|
198
|
+
* stub 透传原包所有导出,并调用 cssInterop 注册 className → style 映射。
|
|
199
|
+
* stub 内部再次 import 原包时,通过 originModulePath 检查避免循环依赖。
|
|
237
200
|
*
|
|
238
|
-
*
|
|
239
|
-
* - expo-image
|
|
240
|
-
* - expo-camera
|
|
241
|
-
* - expo-linear-gradient
|
|
242
|
-
* - expo-blur
|
|
201
|
+
* 支持的包:
|
|
202
|
+
* - expo-image(Image)
|
|
203
|
+
* - expo-camera(CameraView)
|
|
204
|
+
* - expo-linear-gradient(LinearGradient)
|
|
205
|
+
* - expo-blur(BlurView / BlurTargetView)
|
|
243
206
|
*
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
207
|
+
* 不拦截 react-native-reanimated:cssInterop 全局注册 Animated.* 会导致动画 style 注入失败。
|
|
208
|
+
* 不拦截 expo-video:VideoView 在 web 上直接渲染 DOM <video>,不经过 RN 样式系统。
|
|
209
|
+
*/
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* @param config Metro config 对象
|
|
213
|
+
* @returns 注入 resolveRequest 后的新 Metro config
|
|
214
|
+
*/
|
|
215
|
+
declare function withCssInterop(config: MetroConfig): MetroConfig;
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* withLucideResolver — 拦截 lucide-react-native 图标子路径导入
|
|
249
219
|
*
|
|
250
|
-
*
|
|
251
|
-
*
|
|
220
|
+
* babel-plugin-lucide-react-native 会将图标 import 改写为形如
|
|
221
|
+
* lucide-react-native/dist/cjs/icons/Star 的子路径。
|
|
222
|
+
* 这些路径未在 package.json exports 中声明,Metro 会报 warning 或解析失败。
|
|
252
223
|
*
|
|
253
|
-
*
|
|
254
|
-
*
|
|
255
|
-
* module.exports = withCssInterop(config);
|
|
224
|
+
* 此 resolver 将这些子路径直接映射到绝对文件路径,绕过 exports 检查。
|
|
225
|
+
* 扩展名规则:dist/cjs/** → .js,dist/esm/** → .mjs(新版)或 .js(v1.8.x 旧版)
|
|
256
226
|
*/
|
|
257
227
|
|
|
228
|
+
interface WithLucideResolverOptions {
|
|
229
|
+
/**
|
|
230
|
+
* lucide-react-native 包根目录的绝对路径。
|
|
231
|
+
* 不传时通过 require.resolve 自动定位,适用于生产场景。
|
|
232
|
+
* 测试时可传入特定版本的路径,验证不同版本的兼容性。
|
|
233
|
+
*/
|
|
234
|
+
lucidePkgRoot?: string;
|
|
235
|
+
}
|
|
258
236
|
/**
|
|
259
|
-
*
|
|
237
|
+
* @param config Metro config 对象
|
|
238
|
+
* @param options 可选配置
|
|
239
|
+
* @returns 注入 resolveRequest 后的新 Metro config
|
|
240
|
+
*/
|
|
241
|
+
declare function withLucideResolver(config: MetroConfig, options?: WithLucideResolverOptions): MetroConfig;
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* withExpoNotificationsStub — Android 平台将 expo-notifications 替换为 stub
|
|
260
245
|
*
|
|
246
|
+
* Expo Go 缺少 expo-notifications 所需的 native module,直接 import 会崩溃。
|
|
247
|
+
* stub 在运行时通过 isRunningInExpoGo() 判断:
|
|
248
|
+
* - Expo Go:no-op(所有 API 静默返回空值)
|
|
249
|
+
* - Development Build:透传真实 expo-notifications 模块
|
|
250
|
+
*
|
|
251
|
+
* 此 wrapper 需要在开发和生产构建中均生效,因为 native module 缺失是运行时问题,
|
|
252
|
+
* 与 __DEV__ 无关。
|
|
253
|
+
*/
|
|
254
|
+
|
|
255
|
+
/**
|
|
261
256
|
* @param config Metro config 对象
|
|
262
257
|
* @returns 注入 resolveRequest 后的新 Metro config
|
|
263
258
|
*/
|
|
264
|
-
declare function
|
|
259
|
+
declare function withExpoNotificationsStub(config: MetroConfig): MetroConfig;
|
|
265
260
|
|
|
266
261
|
/**
|
|
267
262
|
* 将 Metro transformer 的 minifier 切换为 esbuild。
|
|
@@ -275,4 +270,4 @@ declare function withCssInterop(config: MetroConfig): MetroConfig;
|
|
|
275
270
|
*/
|
|
276
271
|
declare function withEsbuildMinify(config: MetroConfig): MetroConfig;
|
|
277
272
|
|
|
278
|
-
export { type DevkitOptions, type InjectOptions, type PatchNativeWindCacheOptions, type RouteEndpointOptions, patchNativeWindCachePath, withCssInterop, withDevStubs, withDevkit, withEntryInjection, withEsbuildMinify, withExpoNotificationsStub, withNativeWind, withRouteEndpoint, withWorkspaceNodeModules };
|
|
273
|
+
export { type DevkitOptions, type InjectOptions, type PatchNativeWindCacheOptions, type RouteEndpointOptions, patchNativeWindCachePath, withCssInterop, withDevStubs, withDevkit, withEntryInjection, withEsbuildMinify, withExpoNotificationsStub, withLucideResolver, withNativeWind, withRouteEndpoint, withWorkspaceNodeModules };
|
package/dist/metro.d.ts
CHANGED
|
@@ -58,37 +58,18 @@ declare function withNativeWind(config: MetroConfig, options?: any): MetroConfig
|
|
|
58
58
|
/**
|
|
59
59
|
* withEntryInjection — 在 expo-router 启动前注入脚本
|
|
60
60
|
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
* (注入脚本),再 require expo-router/entry-classic(原入口),
|
|
65
|
-
* 从而在 expo-router 启动前执行注入逻辑。
|
|
61
|
+
* 拦截 expo-router/entry-classic 的解析,重定向到 expo-router-entry-stub.js。
|
|
62
|
+
* stub 先 require entry-inject.js,再 require expo-router/entry-classic,
|
|
63
|
+
* 使注入脚本在 expo-router renderRootComponent 之前执行。
|
|
66
64
|
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
* 不经过 resolveRequest。
|
|
70
|
-
* - expo-router/entry 内部第一行是 import 'expo-router/entry-classic',
|
|
71
|
-
* 这条 import 语句经过 resolveRequest,可以被拦截。
|
|
72
|
-
*
|
|
73
|
-
* 执行顺序(在 bundle 中):
|
|
74
|
-
* entry-inject.js → expo-router/entry-classic → renderRootComponent(App)
|
|
75
|
-
*
|
|
76
|
-
* 注入的脚本经过完整 Babel 编译,支持现代语法,web + native 双平台均有效。
|
|
77
|
-
* 支持与 withDevStubs 及其他 Metro wrapper 链式组合。
|
|
78
|
-
*
|
|
79
|
-
* 用法(metro.config.js):
|
|
80
|
-
* const { withEntryInjection } = require('miaoda-expo-devkit/metro');
|
|
81
|
-
* module.exports = withEntryInjection(withDevStubs(config));
|
|
65
|
+
* 拦截 entry-classic 而非 entry 本身:expo-router/entry 通过 <script src="...entry.bundle">
|
|
66
|
+
* 直接加载,不经过 resolveRequest;其内部的 import 'expo-router/entry-classic' 才经过 resolveRequest。
|
|
82
67
|
*/
|
|
83
68
|
|
|
84
|
-
/** withEntryInjection 的配置选项(预留,供未来支持自定义注入脚本路径扩展) */
|
|
85
69
|
interface InjectOptions {
|
|
86
70
|
}
|
|
87
71
|
/**
|
|
88
|
-
* 在 expo-router 启动前注入一段脚本。
|
|
89
|
-
*
|
|
90
72
|
* @param config Metro config 对象
|
|
91
|
-
* @param options 注入选项(当前预留,未来支持自定义注入脚本路径)
|
|
92
73
|
* @returns 注入 resolveRequest 后的新 Metro config
|
|
93
74
|
*/
|
|
94
75
|
declare function withEntryInjection(config: MetroConfig, options?: InjectOptions): MetroConfig;
|
|
@@ -129,12 +110,11 @@ declare function withRouteEndpoint(config: MetroConfig, options: RouteEndpointOp
|
|
|
129
110
|
/**
|
|
130
111
|
* withDevkit — 一站式 Metro 配置入口
|
|
131
112
|
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
* withLucideResolver — 消除 lucide 子路径未在 exports 中声明的警告
|
|
113
|
+
* 按固定顺序依次应用:
|
|
114
|
+
* withWorkspaceNodeModules — 修复沙箱中 node_modules 位于祖先目录时的模块解析问题
|
|
115
|
+
* withCssInterop — 为 expo-image / expo-camera 等注入 NativeWind cssInterop
|
|
116
|
+
* withEsbuildMinify — 将 Metro minifier 切换为 esbuild(仅生产构建生效)
|
|
117
|
+
* withLucideResolver — 消除 lucide 子路径未在 exports 声明时的 warning
|
|
138
118
|
* withExpoNotificationsStub — Android:expo-notifications → stub(Expo Go no-op,Dev Build 透传)
|
|
139
119
|
* withEntryInjection — 在 expo-router 启动前注入脚本(仅 __DEV__)
|
|
140
120
|
* withDevStubs — 替换 Sentry DSN / 屏蔽 LogBox(仅 __DEV__)
|
|
@@ -148,14 +128,6 @@ declare function withRouteEndpoint(config: MetroConfig, options: RouteEndpointOp
|
|
|
148
128
|
* module.exports = withDevkit(getDefaultConfig(__dirname));
|
|
149
129
|
*/
|
|
150
130
|
|
|
151
|
-
/**
|
|
152
|
-
* Android 平台:将 expo-notifications 替换为 stub。
|
|
153
|
-
* stub 内部根据 isRunningInExpoGo() 决定是 no-op(Expo Go)还是透传真实模块(Development Build)。
|
|
154
|
-
*
|
|
155
|
-
* 注意:此 wrapper 必须在 if (__DEV__) 外部调用,因为它需要在所有构建模式下生效。
|
|
156
|
-
* Expo Go 中 native module 的缺失是运行时问题,与开发/生产模式无关。
|
|
157
|
-
*/
|
|
158
|
-
declare function withExpoNotificationsStub(config: MetroConfig): MetroConfig;
|
|
159
131
|
/** withDevkit 的配置选项 */
|
|
160
132
|
interface DevkitOptions {
|
|
161
133
|
/**
|
|
@@ -174,23 +146,14 @@ interface DevkitOptions {
|
|
|
174
146
|
declare function withDevkit(config: MetroConfig, options?: DevkitOptions): MetroConfig;
|
|
175
147
|
|
|
176
148
|
/**
|
|
177
|
-
* withDevStubs —
|
|
149
|
+
* withDevStubs — 开发阶段模块替换
|
|
178
150
|
*
|
|
179
|
-
*
|
|
180
|
-
*
|
|
181
|
-
* 2. 所有平台:@sentry/react-native → sentry-react-native-stub(替换 DSN,注入内置捕获器)
|
|
182
|
-
*
|
|
183
|
-
* 自动保留并调用已有的 resolveRequest,支持与其他 Metro 配置链式组合。
|
|
184
|
-
*
|
|
185
|
-
* 用法(metro.config.js):
|
|
186
|
-
* const { withDevStubs } = require('miaoda-expo-devkit/metro');
|
|
187
|
-
* module.exports = withDevStubs(getDefaultConfig(__dirname));
|
|
151
|
+
* 1. web:@expo/log-box / ErrorOverlayWebControls → no-op stub(屏蔽全屏错误遮罩)
|
|
152
|
+
* 2. 所有平台:@sentry/react-native → stub(替换 DSN,注入内置捕获器)
|
|
188
153
|
*/
|
|
189
154
|
|
|
190
155
|
/**
|
|
191
|
-
*
|
|
192
|
-
*
|
|
193
|
-
* @param config Metro config 对象(来自 getDefaultConfig 或 getSentryExpoConfig)
|
|
156
|
+
* @param config Metro config 对象
|
|
194
157
|
* @returns 注入 resolveRequest 后的新 Metro config
|
|
195
158
|
*/
|
|
196
159
|
declare function withDevStubs(config: MetroConfig): MetroConfig;
|
|
@@ -231,37 +194,69 @@ declare function withWorkspaceNodeModules(config: MetroConfig): MetroConfig;
|
|
|
231
194
|
/**
|
|
232
195
|
* withCssInterop — 为第三方 Expo 组件注入 NativeWind cssInterop
|
|
233
196
|
*
|
|
234
|
-
*
|
|
235
|
-
* stub
|
|
236
|
-
* stub
|
|
197
|
+
* 在 Metro resolver 层拦截目标包的 import,重定向到对应 stub 文件。
|
|
198
|
+
* stub 透传原包所有导出,并调用 cssInterop 注册 className → style 映射。
|
|
199
|
+
* stub 内部再次 import 原包时,通过 originModulePath 检查避免循环依赖。
|
|
237
200
|
*
|
|
238
|
-
*
|
|
239
|
-
* - expo-image
|
|
240
|
-
* - expo-camera
|
|
241
|
-
* - expo-linear-gradient
|
|
242
|
-
* - expo-blur
|
|
201
|
+
* 支持的包:
|
|
202
|
+
* - expo-image(Image)
|
|
203
|
+
* - expo-camera(CameraView)
|
|
204
|
+
* - expo-linear-gradient(LinearGradient)
|
|
205
|
+
* - expo-blur(BlurView / BlurTargetView)
|
|
243
206
|
*
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
207
|
+
* 不拦截 react-native-reanimated:cssInterop 全局注册 Animated.* 会导致动画 style 注入失败。
|
|
208
|
+
* 不拦截 expo-video:VideoView 在 web 上直接渲染 DOM <video>,不经过 RN 样式系统。
|
|
209
|
+
*/
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* @param config Metro config 对象
|
|
213
|
+
* @returns 注入 resolveRequest 后的新 Metro config
|
|
214
|
+
*/
|
|
215
|
+
declare function withCssInterop(config: MetroConfig): MetroConfig;
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* withLucideResolver — 拦截 lucide-react-native 图标子路径导入
|
|
249
219
|
*
|
|
250
|
-
*
|
|
251
|
-
*
|
|
220
|
+
* babel-plugin-lucide-react-native 会将图标 import 改写为形如
|
|
221
|
+
* lucide-react-native/dist/cjs/icons/Star 的子路径。
|
|
222
|
+
* 这些路径未在 package.json exports 中声明,Metro 会报 warning 或解析失败。
|
|
252
223
|
*
|
|
253
|
-
*
|
|
254
|
-
*
|
|
255
|
-
* module.exports = withCssInterop(config);
|
|
224
|
+
* 此 resolver 将这些子路径直接映射到绝对文件路径,绕过 exports 检查。
|
|
225
|
+
* 扩展名规则:dist/cjs/** → .js,dist/esm/** → .mjs(新版)或 .js(v1.8.x 旧版)
|
|
256
226
|
*/
|
|
257
227
|
|
|
228
|
+
interface WithLucideResolverOptions {
|
|
229
|
+
/**
|
|
230
|
+
* lucide-react-native 包根目录的绝对路径。
|
|
231
|
+
* 不传时通过 require.resolve 自动定位,适用于生产场景。
|
|
232
|
+
* 测试时可传入特定版本的路径,验证不同版本的兼容性。
|
|
233
|
+
*/
|
|
234
|
+
lucidePkgRoot?: string;
|
|
235
|
+
}
|
|
258
236
|
/**
|
|
259
|
-
*
|
|
237
|
+
* @param config Metro config 对象
|
|
238
|
+
* @param options 可选配置
|
|
239
|
+
* @returns 注入 resolveRequest 后的新 Metro config
|
|
240
|
+
*/
|
|
241
|
+
declare function withLucideResolver(config: MetroConfig, options?: WithLucideResolverOptions): MetroConfig;
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* withExpoNotificationsStub — Android 平台将 expo-notifications 替换为 stub
|
|
260
245
|
*
|
|
246
|
+
* Expo Go 缺少 expo-notifications 所需的 native module,直接 import 会崩溃。
|
|
247
|
+
* stub 在运行时通过 isRunningInExpoGo() 判断:
|
|
248
|
+
* - Expo Go:no-op(所有 API 静默返回空值)
|
|
249
|
+
* - Development Build:透传真实 expo-notifications 模块
|
|
250
|
+
*
|
|
251
|
+
* 此 wrapper 需要在开发和生产构建中均生效,因为 native module 缺失是运行时问题,
|
|
252
|
+
* 与 __DEV__ 无关。
|
|
253
|
+
*/
|
|
254
|
+
|
|
255
|
+
/**
|
|
261
256
|
* @param config Metro config 对象
|
|
262
257
|
* @returns 注入 resolveRequest 后的新 Metro config
|
|
263
258
|
*/
|
|
264
|
-
declare function
|
|
259
|
+
declare function withExpoNotificationsStub(config: MetroConfig): MetroConfig;
|
|
265
260
|
|
|
266
261
|
/**
|
|
267
262
|
* 将 Metro transformer 的 minifier 切换为 esbuild。
|
|
@@ -275,4 +270,4 @@ declare function withCssInterop(config: MetroConfig): MetroConfig;
|
|
|
275
270
|
*/
|
|
276
271
|
declare function withEsbuildMinify(config: MetroConfig): MetroConfig;
|
|
277
272
|
|
|
278
|
-
export { type DevkitOptions, type InjectOptions, type PatchNativeWindCacheOptions, type RouteEndpointOptions, patchNativeWindCachePath, withCssInterop, withDevStubs, withDevkit, withEntryInjection, withEsbuildMinify, withExpoNotificationsStub, withNativeWind, withRouteEndpoint, withWorkspaceNodeModules };
|
|
273
|
+
export { type DevkitOptions, type InjectOptions, type PatchNativeWindCacheOptions, type RouteEndpointOptions, patchNativeWindCachePath, withCssInterop, withDevStubs, withDevkit, withEntryInjection, withEsbuildMinify, withExpoNotificationsStub, withLucideResolver, withNativeWind, withRouteEndpoint, withWorkspaceNodeModules };
|
package/dist/metro.js
CHANGED
|
@@ -37,6 +37,7 @@ __export(metro_exports, {
|
|
|
37
37
|
withEntryInjection: () => withEntryInjection,
|
|
38
38
|
withEsbuildMinify: () => withEsbuildMinify,
|
|
39
39
|
withExpoNotificationsStub: () => withExpoNotificationsStub,
|
|
40
|
+
withLucideResolver: () => withLucideResolver,
|
|
40
41
|
withNativeWind: () => withNativeWind,
|
|
41
42
|
withRouteEndpoint: () => withRouteEndpoint,
|
|
42
43
|
withWorkspaceNodeModules: () => withWorkspaceNodeModules
|
|
@@ -94,9 +95,7 @@ function withDevStubs(config) {
|
|
|
94
95
|
if (moduleName === "@sentry/react-native" && !context.originModulePath.includes(SENTRY_STUB_FILENAME)) {
|
|
95
96
|
return { filePath: SENTRY_STUB_PATH, type: "sourceFile" };
|
|
96
97
|
}
|
|
97
|
-
if (upstream)
|
|
98
|
-
return upstream(context, moduleName, platform);
|
|
99
|
-
}
|
|
98
|
+
if (upstream) return upstream(context, moduleName, platform);
|
|
100
99
|
return context.resolveRequest(context, moduleName, platform);
|
|
101
100
|
};
|
|
102
101
|
return {
|
|
@@ -110,8 +109,8 @@ function withDevStubs(config) {
|
|
|
110
109
|
|
|
111
110
|
// src/metro/withEntryInjection.ts
|
|
112
111
|
var import_path3 = __toESM(require("path"));
|
|
113
|
-
var EXPO_ROUTER_ENTRY_STUB_PATH = import_path3.default.resolve(__dirname, "stubs", "expo-router-entry-stub.js");
|
|
114
112
|
var EXPO_ROUTER_ENTRY_STUB_FILENAME = "expo-router-entry-stub.js";
|
|
113
|
+
var EXPO_ROUTER_ENTRY_STUB_PATH = import_path3.default.resolve(__dirname, "stubs", EXPO_ROUTER_ENTRY_STUB_FILENAME);
|
|
115
114
|
function withEntryInjection(config, options) {
|
|
116
115
|
void options;
|
|
117
116
|
const upstream = config.resolver?.resolveRequest ?? null;
|
|
@@ -284,8 +283,7 @@ function withCssInterop(config) {
|
|
|
284
283
|
}
|
|
285
284
|
|
|
286
285
|
// src/metro/withDevkit.ts
|
|
287
|
-
var
|
|
288
|
-
var import_path7 = __toESM(require("path"));
|
|
286
|
+
var import_path9 = __toESM(require("path"));
|
|
289
287
|
|
|
290
288
|
// src/metro/withEsbuildMinify.ts
|
|
291
289
|
function withEsbuildMinify(config) {
|
|
@@ -300,19 +298,21 @@ function withEsbuildMinify(config) {
|
|
|
300
298
|
};
|
|
301
299
|
}
|
|
302
300
|
|
|
303
|
-
// src/metro/
|
|
301
|
+
// src/metro/withLucideResolver.ts
|
|
302
|
+
var import_fs3 = __toESM(require("fs"));
|
|
303
|
+
var import_path7 = __toESM(require("path"));
|
|
304
304
|
var LUCIDE_PKG = "lucide-react-native";
|
|
305
305
|
var LUCIDE_DIST_PREFIX = `${LUCIDE_PKG}/dist/`;
|
|
306
|
-
var
|
|
306
|
+
var _lucidePkgRoot = null;
|
|
307
307
|
function getLucidePkgRoot() {
|
|
308
|
-
if (
|
|
308
|
+
if (_lucidePkgRoot) return _lucidePkgRoot;
|
|
309
309
|
let dir = import_path7.default.dirname(require.resolve(LUCIDE_PKG));
|
|
310
310
|
while (true) {
|
|
311
311
|
const pkgJson = import_path7.default.join(dir, "package.json");
|
|
312
312
|
if (import_fs3.default.existsSync(pkgJson)) {
|
|
313
313
|
const { name } = require(pkgJson);
|
|
314
314
|
if (name === LUCIDE_PKG) {
|
|
315
|
-
|
|
315
|
+
_lucidePkgRoot = dir;
|
|
316
316
|
return dir;
|
|
317
317
|
}
|
|
318
318
|
}
|
|
@@ -321,13 +321,23 @@ function getLucidePkgRoot() {
|
|
|
321
321
|
dir = parent;
|
|
322
322
|
}
|
|
323
323
|
}
|
|
324
|
-
|
|
324
|
+
var esmExtCache = /* @__PURE__ */ new Map();
|
|
325
|
+
function getEsmExt(pkgRoot) {
|
|
326
|
+
const cached = esmExtCache.get(pkgRoot);
|
|
327
|
+
if (cached) return cached;
|
|
328
|
+
const esmIconsDir = import_path7.default.join(pkgRoot, "dist/esm/icons");
|
|
329
|
+
const ext = import_fs3.default.existsSync(esmIconsDir) && import_fs3.default.readdirSync(esmIconsDir).some((f) => f.endsWith(".mjs")) ? ".mjs" : ".js";
|
|
330
|
+
esmExtCache.set(pkgRoot, ext);
|
|
331
|
+
return ext;
|
|
332
|
+
}
|
|
333
|
+
function withLucideResolver(config, options = {}) {
|
|
325
334
|
const upstream = config.resolver?.resolveRequest ?? null;
|
|
335
|
+
const pkgRoot = options.lucidePkgRoot ?? getLucidePkgRoot();
|
|
326
336
|
const resolveRequest = (context, moduleName, platform) => {
|
|
327
337
|
if (moduleName.startsWith(LUCIDE_DIST_PREFIX)) {
|
|
328
338
|
const subpath = moduleName.slice(LUCIDE_PKG.length + 1);
|
|
329
|
-
const ext = subpath.startsWith("dist/esm/") ?
|
|
330
|
-
const filePath = import_path7.default.join(
|
|
339
|
+
const ext = subpath.startsWith("dist/esm/") ? getEsmExt(pkgRoot) : ".js";
|
|
340
|
+
const filePath = import_path7.default.join(pkgRoot, subpath + ext);
|
|
331
341
|
return { filePath, type: "sourceFile" };
|
|
332
342
|
}
|
|
333
343
|
if (upstream) return upstream(context, moduleName, platform);
|
|
@@ -335,8 +345,11 @@ function withLucideResolver(config) {
|
|
|
335
345
|
};
|
|
336
346
|
return { ...config, resolver: { ...config.resolver, resolveRequest } };
|
|
337
347
|
}
|
|
348
|
+
|
|
349
|
+
// src/metro/withExpoNotificationsStub.ts
|
|
350
|
+
var import_path8 = __toESM(require("path"));
|
|
338
351
|
var EXPO_NOTIFICATIONS_STUB_FILENAME = "expo-notifications-stub.js";
|
|
339
|
-
var EXPO_NOTIFICATIONS_STUB_PATH =
|
|
352
|
+
var EXPO_NOTIFICATIONS_STUB_PATH = import_path8.default.resolve(__dirname, "stubs", EXPO_NOTIFICATIONS_STUB_FILENAME);
|
|
340
353
|
function withExpoNotificationsStub(config) {
|
|
341
354
|
const upstream = config.resolver?.resolveRequest ?? null;
|
|
342
355
|
const resolveRequest = (context, moduleName, platform) => {
|
|
@@ -348,6 +361,8 @@ function withExpoNotificationsStub(config) {
|
|
|
348
361
|
};
|
|
349
362
|
return { ...config, resolver: { ...config.resolver, resolveRequest } };
|
|
350
363
|
}
|
|
364
|
+
|
|
365
|
+
// src/metro/withDevkit.ts
|
|
351
366
|
function withDevkit(config, options = {}) {
|
|
352
367
|
const projectRoot = config.projectRoot ?? process.cwd();
|
|
353
368
|
const { input = "./src/global.css" } = options;
|
|
@@ -359,7 +374,7 @@ function withDevkit(config, options = {}) {
|
|
|
359
374
|
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
360
375
|
config = withEntryInjection(config);
|
|
361
376
|
config = withDevStubs(config);
|
|
362
|
-
config = withRouteEndpoint(config, { appDir:
|
|
377
|
+
config = withRouteEndpoint(config, { appDir: import_path9.default.join(projectRoot, "src", "app") });
|
|
363
378
|
}
|
|
364
379
|
return withNativeWind(config, { input, inlineRem: 16 });
|
|
365
380
|
}
|
|
@@ -380,6 +395,7 @@ try {
|
|
|
380
395
|
withEntryInjection,
|
|
381
396
|
withEsbuildMinify,
|
|
382
397
|
withExpoNotificationsStub,
|
|
398
|
+
withLucideResolver,
|
|
383
399
|
withNativeWind,
|
|
384
400
|
withRouteEndpoint,
|
|
385
401
|
withWorkspaceNodeModules
|
package/dist/metro.mjs
CHANGED
|
@@ -56,9 +56,7 @@ function withDevStubs(config) {
|
|
|
56
56
|
if (moduleName === "@sentry/react-native" && !context.originModulePath.includes(SENTRY_STUB_FILENAME)) {
|
|
57
57
|
return { filePath: SENTRY_STUB_PATH, type: "sourceFile" };
|
|
58
58
|
}
|
|
59
|
-
if (upstream)
|
|
60
|
-
return upstream(context, moduleName, platform);
|
|
61
|
-
}
|
|
59
|
+
if (upstream) return upstream(context, moduleName, platform);
|
|
62
60
|
return context.resolveRequest(context, moduleName, platform);
|
|
63
61
|
};
|
|
64
62
|
return {
|
|
@@ -72,8 +70,8 @@ function withDevStubs(config) {
|
|
|
72
70
|
|
|
73
71
|
// src/metro/withEntryInjection.ts
|
|
74
72
|
import path3 from "path";
|
|
75
|
-
var EXPO_ROUTER_ENTRY_STUB_PATH = path3.resolve(__dirname, "stubs", "expo-router-entry-stub.js");
|
|
76
73
|
var EXPO_ROUTER_ENTRY_STUB_FILENAME = "expo-router-entry-stub.js";
|
|
74
|
+
var EXPO_ROUTER_ENTRY_STUB_PATH = path3.resolve(__dirname, "stubs", EXPO_ROUTER_ENTRY_STUB_FILENAME);
|
|
77
75
|
function withEntryInjection(config, options) {
|
|
78
76
|
void options;
|
|
79
77
|
const upstream = config.resolver?.resolveRequest ?? null;
|
|
@@ -246,8 +244,7 @@ function withCssInterop(config) {
|
|
|
246
244
|
}
|
|
247
245
|
|
|
248
246
|
// src/metro/withDevkit.ts
|
|
249
|
-
import
|
|
250
|
-
import path7 from "path";
|
|
247
|
+
import path9 from "path";
|
|
251
248
|
|
|
252
249
|
// src/metro/withEsbuildMinify.ts
|
|
253
250
|
function withEsbuildMinify(config) {
|
|
@@ -262,19 +259,21 @@ function withEsbuildMinify(config) {
|
|
|
262
259
|
};
|
|
263
260
|
}
|
|
264
261
|
|
|
265
|
-
// src/metro/
|
|
262
|
+
// src/metro/withLucideResolver.ts
|
|
263
|
+
import fs3 from "fs";
|
|
264
|
+
import path7 from "path";
|
|
266
265
|
var LUCIDE_PKG = "lucide-react-native";
|
|
267
266
|
var LUCIDE_DIST_PREFIX = `${LUCIDE_PKG}/dist/`;
|
|
268
|
-
var
|
|
267
|
+
var _lucidePkgRoot = null;
|
|
269
268
|
function getLucidePkgRoot() {
|
|
270
|
-
if (
|
|
269
|
+
if (_lucidePkgRoot) return _lucidePkgRoot;
|
|
271
270
|
let dir = path7.dirname(__require.resolve(LUCIDE_PKG));
|
|
272
271
|
while (true) {
|
|
273
272
|
const pkgJson = path7.join(dir, "package.json");
|
|
274
273
|
if (fs3.existsSync(pkgJson)) {
|
|
275
274
|
const { name } = __require(pkgJson);
|
|
276
275
|
if (name === LUCIDE_PKG) {
|
|
277
|
-
|
|
276
|
+
_lucidePkgRoot = dir;
|
|
278
277
|
return dir;
|
|
279
278
|
}
|
|
280
279
|
}
|
|
@@ -283,13 +282,23 @@ function getLucidePkgRoot() {
|
|
|
283
282
|
dir = parent;
|
|
284
283
|
}
|
|
285
284
|
}
|
|
286
|
-
|
|
285
|
+
var esmExtCache = /* @__PURE__ */ new Map();
|
|
286
|
+
function getEsmExt(pkgRoot) {
|
|
287
|
+
const cached = esmExtCache.get(pkgRoot);
|
|
288
|
+
if (cached) return cached;
|
|
289
|
+
const esmIconsDir = path7.join(pkgRoot, "dist/esm/icons");
|
|
290
|
+
const ext = fs3.existsSync(esmIconsDir) && fs3.readdirSync(esmIconsDir).some((f) => f.endsWith(".mjs")) ? ".mjs" : ".js";
|
|
291
|
+
esmExtCache.set(pkgRoot, ext);
|
|
292
|
+
return ext;
|
|
293
|
+
}
|
|
294
|
+
function withLucideResolver(config, options = {}) {
|
|
287
295
|
const upstream = config.resolver?.resolveRequest ?? null;
|
|
296
|
+
const pkgRoot = options.lucidePkgRoot ?? getLucidePkgRoot();
|
|
288
297
|
const resolveRequest = (context, moduleName, platform) => {
|
|
289
298
|
if (moduleName.startsWith(LUCIDE_DIST_PREFIX)) {
|
|
290
299
|
const subpath = moduleName.slice(LUCIDE_PKG.length + 1);
|
|
291
|
-
const ext = subpath.startsWith("dist/esm/") ?
|
|
292
|
-
const filePath = path7.join(
|
|
300
|
+
const ext = subpath.startsWith("dist/esm/") ? getEsmExt(pkgRoot) : ".js";
|
|
301
|
+
const filePath = path7.join(pkgRoot, subpath + ext);
|
|
293
302
|
return { filePath, type: "sourceFile" };
|
|
294
303
|
}
|
|
295
304
|
if (upstream) return upstream(context, moduleName, platform);
|
|
@@ -297,8 +306,11 @@ function withLucideResolver(config) {
|
|
|
297
306
|
};
|
|
298
307
|
return { ...config, resolver: { ...config.resolver, resolveRequest } };
|
|
299
308
|
}
|
|
309
|
+
|
|
310
|
+
// src/metro/withExpoNotificationsStub.ts
|
|
311
|
+
import path8 from "path";
|
|
300
312
|
var EXPO_NOTIFICATIONS_STUB_FILENAME = "expo-notifications-stub.js";
|
|
301
|
-
var EXPO_NOTIFICATIONS_STUB_PATH =
|
|
313
|
+
var EXPO_NOTIFICATIONS_STUB_PATH = path8.resolve(__dirname, "stubs", EXPO_NOTIFICATIONS_STUB_FILENAME);
|
|
302
314
|
function withExpoNotificationsStub(config) {
|
|
303
315
|
const upstream = config.resolver?.resolveRequest ?? null;
|
|
304
316
|
const resolveRequest = (context, moduleName, platform) => {
|
|
@@ -310,6 +322,8 @@ function withExpoNotificationsStub(config) {
|
|
|
310
322
|
};
|
|
311
323
|
return { ...config, resolver: { ...config.resolver, resolveRequest } };
|
|
312
324
|
}
|
|
325
|
+
|
|
326
|
+
// src/metro/withDevkit.ts
|
|
313
327
|
function withDevkit(config, options = {}) {
|
|
314
328
|
const projectRoot = config.projectRoot ?? process.cwd();
|
|
315
329
|
const { input = "./src/global.css" } = options;
|
|
@@ -321,7 +335,7 @@ function withDevkit(config, options = {}) {
|
|
|
321
335
|
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
322
336
|
config = withEntryInjection(config);
|
|
323
337
|
config = withDevStubs(config);
|
|
324
|
-
config = withRouteEndpoint(config, { appDir:
|
|
338
|
+
config = withRouteEndpoint(config, { appDir: path9.join(projectRoot, "src", "app") });
|
|
325
339
|
}
|
|
326
340
|
return withNativeWind(config, { input, inlineRem: 16 });
|
|
327
341
|
}
|
|
@@ -341,6 +355,7 @@ export {
|
|
|
341
355
|
withEntryInjection,
|
|
342
356
|
withEsbuildMinify,
|
|
343
357
|
withExpoNotificationsStub,
|
|
358
|
+
withLucideResolver,
|
|
344
359
|
withNativeWind,
|
|
345
360
|
withRouteEndpoint,
|
|
346
361
|
withWorkspaceNodeModules
|
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.27",
|
|
4
4
|
"description": "Expo 应用开发工具集:Sentry DSN 替换 stub、错误/网络捕获、Metro 符号化",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -63,16 +63,6 @@
|
|
|
63
63
|
"tsconfig-base.json",
|
|
64
64
|
"!dist/**/*.map"
|
|
65
65
|
],
|
|
66
|
-
"scripts": {
|
|
67
|
-
"build": "tsup",
|
|
68
|
-
"typecheck": "tsc --noEmit && tsc -p tsconfig.check.json --noEmit",
|
|
69
|
-
"test": "vitest run",
|
|
70
|
-
"release": "pnpm run test && pnpm run build && npm publish",
|
|
71
|
-
"release:beta": "pnpm run test && pnpm run build && npm version prerelease --preid=beta && npm publish --tag beta",
|
|
72
|
-
"release:patch": "pnpm run test && pnpm run build && npm version patch && npm publish",
|
|
73
|
-
"release:minor": "pnpm run test && pnpm run build && npm version minor && npm publish",
|
|
74
|
-
"release:major": "pnpm run test && pnpm run build && npm version major && npm publish"
|
|
75
|
-
},
|
|
76
66
|
"dependencies": {
|
|
77
67
|
"connect": "^3.7.0",
|
|
78
68
|
"es-toolkit": "^1.45.1",
|
|
@@ -120,21 +110,5 @@
|
|
|
120
110
|
"publishConfig": {
|
|
121
111
|
"registry": "https://registry.npmjs.org/",
|
|
122
112
|
"access": "public"
|
|
123
|
-
},
|
|
124
|
-
"devDependencies": {
|
|
125
|
-
"@babel/core": "^7.26.0",
|
|
126
|
-
"@babel/helper-module-imports": "^7.28.6",
|
|
127
|
-
"@sentry/core": "^10.38.0",
|
|
128
|
-
"@sentry/react-native": ">=8.0.0",
|
|
129
|
-
"@types/babel__core": "^7.20.5",
|
|
130
|
-
"@types/babel__helper-module-imports": "^7.18.3",
|
|
131
|
-
"@types/connect": "^3.4.38",
|
|
132
|
-
"@types/node": "^25.0.0",
|
|
133
|
-
"metro": "^0.83.0",
|
|
134
|
-
"metro-config": "^0.83.0",
|
|
135
|
-
"metro-resolver": "^0.83.0",
|
|
136
|
-
"oxlint": "catalog:",
|
|
137
|
-
"tsup": "^8.5.1",
|
|
138
|
-
"vitest": "^4.1.5"
|
|
139
113
|
}
|
|
140
114
|
}
|