miaoda-expo-devkit 0.1.1-beta.25 → 0.1.1-beta.26

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.
@@ -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 aliasMap = null;
14615
- function buildAliasMap(moduleDir) {
14616
- if (aliasMap) return aliasMap;
14617
- const { map: fileMap } = buildIconMap(moduleDir);
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
- aliasMap = map;
14650
+ aliasMapCache.set(cacheKey, map);
14649
14651
  return map;
14650
14652
  }
14651
- function buildIconMap(moduleDir) {
14652
- const cached = iconMapCache.get(moduleDir);
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(moduleDir, data);
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
- return specifiedLocal4Imported[localName] && nodePath.scope.hasBinding(localName) && nodePath.scope.getBinding(localName)?.path.type === "ImportSpecifier";
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
- * 拦截 Metro expo-router/entry-classic 的解析,将其重定向到
63
- * dist/stubs/expo-router-entry-stub.js。stub require entry-inject.js
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
- * 拦截 entry-classic 而非 entry 本身,原因:
68
- * - expo-router/entry <script src="...entry.bundle..."> 方式直接加载,
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
- * 将模板 metro.config.js 所需的所有 devkit wrapper 封装为单个函数调用,
133
- * 消除模板侧的 boilerplate。内部按固定顺序依次应用:
134
- *
135
- * withWorkspaceNodeModules 修复沙箱中 node_modules 不在 projectRoot 内的问题
136
- * withCssInterop expo-image / expo-camera 注入 NativeWind cssInterop
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 — Metro resolver 注入开发阶段 stub
149
+ * withDevStubs — 开发阶段模块替换
178
150
  *
179
- * 注入行为:
180
- * 1. web 平台:@expo/log-box 及 ErrorOverlayWebControls no-op-logbox stub(屏蔽全屏错误遮罩)
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-nativestub(替换 DSN,注入内置捕获器)
188
153
  */
189
154
 
190
155
  /**
191
- * 将开发阶段 stub 注入到 Metro config 中。
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
- * 注入方式:Metro resolver 层拦截对应包的 import,重定向到 stub 文件。
235
- * stub 文件透传原包的所有导出,并调用 cssInterop 完成注册。
236
- * stub 内部 import 原包时,originModulePath 检查避免循环依赖。
197
+ * Metro resolver 层拦截目标包的 import,重定向到对应 stub 文件。
198
+ * stub 透传原包所有导出,并调用 cssInterop 注册 className → style 映射。
199
+ * stub 内部再次 import 原包时,通过 originModulePath 检查避免循环依赖。
237
200
  *
238
- * 当前支持的包:
239
- * - expo-imageImage 组件(className → style
240
- * - expo-cameraCameraView 组件(className → style
241
- * - expo-linear-gradientLinearGradient 组件(className → style
242
- * - expo-blurBlurView / BlurTargetView 组件(className → style
201
+ * 支持的包:
202
+ * - expo-imageImage)
203
+ * - expo-cameraCameraView)
204
+ * - expo-linear-gradientLinearGradient)
205
+ * - expo-blurBlurView / BlurTargetView)
243
206
  *
244
- * 注意:react-native-reanimated 不拦截。cssInterop 全局注册 Animated.* 会导致所有动画 style 注入失败。
245
- * 需要同时使用 Tailwind className 和动画的场景,请在组件层面单独用 createAnimatedComponent + cssInterop 封装。
246
- *
247
- * 注意:expo-video 的 VideoView 在 web 上直接渲染 DOM <video> 元素,不经过 RN 样式系统,
248
- * cssInterop/remapProps 均无效,不做拦截。需要 className 时请用 View 包裹 VideoView。
207
+ * 不拦截 react-native-reanimatedcssInterop 全局注册 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
- * 此函数在开发和生产环境均需启用(cssInterop 注册与环境无关)。
251
- * 支持与其他 Metro wrapper 链式组合。
220
+ * babel-plugin-lucide-react-native 会将图标 import 改写为形如
221
+ * lucide-react-native/dist/cjs/icons/Star 的子路径。
222
+ * 这些路径未在 package.json exports 中声明,Metro 会报 warning 或解析失败。
252
223
  *
253
- * 用法(metro.config.js):
254
- * const { withCssInterop } = require('miaoda-expo-devkit/metro');
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
- * 为第三方 Expo 组件注入 NativeWind cssInterop,使其支持 className prop。
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 withCssInterop(config: MetroConfig): MetroConfig;
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
- * 拦截 Metro expo-router/entry-classic 的解析,将其重定向到
63
- * dist/stubs/expo-router-entry-stub.js。stub require entry-inject.js
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
- * 拦截 entry-classic 而非 entry 本身,原因:
68
- * - expo-router/entry <script src="...entry.bundle..."> 方式直接加载,
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
- * 将模板 metro.config.js 所需的所有 devkit wrapper 封装为单个函数调用,
133
- * 消除模板侧的 boilerplate。内部按固定顺序依次应用:
134
- *
135
- * withWorkspaceNodeModules 修复沙箱中 node_modules 不在 projectRoot 内的问题
136
- * withCssInterop expo-image / expo-camera 注入 NativeWind cssInterop
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 — Metro resolver 注入开发阶段 stub
149
+ * withDevStubs — 开发阶段模块替换
178
150
  *
179
- * 注入行为:
180
- * 1. web 平台:@expo/log-box 及 ErrorOverlayWebControls no-op-logbox stub(屏蔽全屏错误遮罩)
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-nativestub(替换 DSN,注入内置捕获器)
188
153
  */
189
154
 
190
155
  /**
191
- * 将开发阶段 stub 注入到 Metro config 中。
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
- * 注入方式:Metro resolver 层拦截对应包的 import,重定向到 stub 文件。
235
- * stub 文件透传原包的所有导出,并调用 cssInterop 完成注册。
236
- * stub 内部 import 原包时,originModulePath 检查避免循环依赖。
197
+ * Metro resolver 层拦截目标包的 import,重定向到对应 stub 文件。
198
+ * stub 透传原包所有导出,并调用 cssInterop 注册 className → style 映射。
199
+ * stub 内部再次 import 原包时,通过 originModulePath 检查避免循环依赖。
237
200
  *
238
- * 当前支持的包:
239
- * - expo-imageImage 组件(className → style
240
- * - expo-cameraCameraView 组件(className → style
241
- * - expo-linear-gradientLinearGradient 组件(className → style
242
- * - expo-blurBlurView / BlurTargetView 组件(className → style
201
+ * 支持的包:
202
+ * - expo-imageImage)
203
+ * - expo-cameraCameraView)
204
+ * - expo-linear-gradientLinearGradient)
205
+ * - expo-blurBlurView / BlurTargetView)
243
206
  *
244
- * 注意:react-native-reanimated 不拦截。cssInterop 全局注册 Animated.* 会导致所有动画 style 注入失败。
245
- * 需要同时使用 Tailwind className 和动画的场景,请在组件层面单独用 createAnimatedComponent + cssInterop 封装。
246
- *
247
- * 注意:expo-video 的 VideoView 在 web 上直接渲染 DOM <video> 元素,不经过 RN 样式系统,
248
- * cssInterop/remapProps 均无效,不做拦截。需要 className 时请用 View 包裹 VideoView。
207
+ * 不拦截 react-native-reanimatedcssInterop 全局注册 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
- * 此函数在开发和生产环境均需启用(cssInterop 注册与环境无关)。
251
- * 支持与其他 Metro wrapper 链式组合。
220
+ * babel-plugin-lucide-react-native 会将图标 import 改写为形如
221
+ * lucide-react-native/dist/cjs/icons/Star 的子路径。
222
+ * 这些路径未在 package.json exports 中声明,Metro 会报 warning 或解析失败。
252
223
  *
253
- * 用法(metro.config.js):
254
- * const { withCssInterop } = require('miaoda-expo-devkit/metro');
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
- * 为第三方 Expo 组件注入 NativeWind cssInterop,使其支持 className prop。
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 withCssInterop(config: MetroConfig): MetroConfig;
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 import_fs3 = __toESM(require("fs"));
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/withDevkit.ts
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 lucidePkgRoot = null;
306
+ var _lucidePkgRoot = null;
307
307
  function getLucidePkgRoot() {
308
- if (lucidePkgRoot) return lucidePkgRoot;
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
- lucidePkgRoot = dir;
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
- function withLucideResolver(config) {
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/") ? ".mjs" : ".js";
330
- const filePath = import_path7.default.join(getLucidePkgRoot(), subpath + ext);
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 = import_path7.default.resolve(__dirname, "stubs", EXPO_NOTIFICATIONS_STUB_FILENAME);
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: import_path7.default.join(projectRoot, "src", "app") });
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 fs3 from "fs";
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/withDevkit.ts
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 lucidePkgRoot = null;
267
+ var _lucidePkgRoot = null;
269
268
  function getLucidePkgRoot() {
270
- if (lucidePkgRoot) return lucidePkgRoot;
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
- lucidePkgRoot = dir;
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
- function withLucideResolver(config) {
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/") ? ".mjs" : ".js";
292
- const filePath = path7.join(getLucidePkgRoot(), subpath + ext);
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 = path7.resolve(__dirname, "stubs", EXPO_NOTIFICATIONS_STUB_FILENAME);
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: path7.join(projectRoot, "src", "app") });
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.25",
3
+ "version": "0.1.1-beta.26",
4
4
  "description": "Expo 应用开发工具集:Sentry DSN 替换 stub、错误/网络捕获、Metro 符号化",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.js",