miaoda-expo-devkit 0.1.1-beta.5 → 0.1.1-beta.7
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 +160 -99
- package/dist/metro.d.ts +160 -99
- package/dist/metro.js +126 -98
- package/dist/metro.mjs +124 -99
- package/dist/stubs/lgui-control.js +38 -7
- package/package.json +1 -1
package/dist/metro.d.mts
CHANGED
|
@@ -1,52 +1,66 @@
|
|
|
1
1
|
import { MetroConfig } from 'metro-config';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* withNativeWind / patchNativeWindCachePath — NativeWind 缓存路径修复与 lazy wrapper
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
6
|
+
* patchNativeWindCachePath:
|
|
7
|
+
* 将 NativeWind 编译缓存从 node_modules/.cache 重定向到项目根目录下的自定义目录。
|
|
8
|
+
* ⚠️ 必须在 require('nativewind/metro') 之前调用,否则 outputDirectory 已经固化,patch 无效。
|
|
9
|
+
*
|
|
10
|
+
* withNativeWind:
|
|
11
|
+
* nativewind/metro 的 lazy wrapper,确保 nativewind 在 patchNativeWindCachePath 之后加载,
|
|
12
|
+
* 拿到已 patch 的 outputDirectory。用法与 nativewind 官方 withNativeWind 完全相同。
|
|
11
13
|
*
|
|
12
14
|
* 用法(metro.config.js):
|
|
15
|
+
* const { withNativeWind } = require('miaoda-expo-devkit/metro');
|
|
16
|
+
* // 不再需要单独 require('nativewind/metro')
|
|
17
|
+
* module.exports = withNativeWind(config, { input: './global.css' });
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/** patchNativeWindCachePath 的配置选项 */
|
|
21
|
+
interface PatchNativeWindCacheOptions {
|
|
22
|
+
/**
|
|
23
|
+
* 缓存目录,相对于 process.cwd()(Metro 项目根目录),默认 .native-wind-cache。
|
|
24
|
+
* 与 package.json 同级,避免写入只读的 node_modules。
|
|
25
|
+
*/
|
|
26
|
+
cacheDir?: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* 将 NativeWind 编译缓存从 node_modules/.cache 重定向到项目根目录下的自定义目录。
|
|
13
30
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
31
|
+
* ⚠️ 必须在 require('nativewind/metro') / require('react-native-css-interop/dist/metro')
|
|
32
|
+
* 之前调用,否则 outputDirectory 已经固化,patch 无效。
|
|
16
33
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* );
|
|
34
|
+
* 原理:react-native-css-interop/dist/metro 在模块顶层用
|
|
35
|
+
* const outputDirectory = path.resolve(__dirname, "../../.cache")
|
|
36
|
+
* 计算缓存路径。通过在 require 前临时替换 path.resolve,可将该值重定向到
|
|
37
|
+
* 项目根目录下的自定义缓存目录,而无需 fork 或修改 node_modules 源码。
|
|
22
38
|
*
|
|
23
|
-
*
|
|
39
|
+
* ⚠️ 已知限制:依赖 react-native-css-interop 使用 path.resolve 计算缓存路径,
|
|
40
|
+
* 升级该依赖时需确认此假设仍然成立。
|
|
24
41
|
*
|
|
25
|
-
*
|
|
42
|
+
* @param options 配置选项
|
|
26
43
|
*/
|
|
27
|
-
|
|
44
|
+
declare function patchNativeWindCachePath(options?: PatchNativeWindCacheOptions): void;
|
|
28
45
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* 注入行为:
|
|
32
|
-
* 1. web 平台:@expo/log-box 及 ErrorOverlayWebControls → no-op-logbox stub(屏蔽全屏错误遮罩)
|
|
33
|
-
* 2. 所有平台:@sentry/react-native → sentry-react-native-stub(替换 DSN,注入内置捕获器)
|
|
46
|
+
* withNativeWind 的 lazy wrapper。
|
|
34
47
|
*
|
|
35
|
-
*
|
|
48
|
+
* nativewind/metro 在模块顶层捕获 react-native-css-interop 的 withCssInterop 引用,
|
|
49
|
+
* 因此必须在 patchNativeWindCachePath() 执行完之后才能加载 nativewind/metro。
|
|
50
|
+
* 这里使用 lazy require(在函数调用时才加载),确保 nativewind 拿到已 patch 的
|
|
51
|
+
* outputDirectory,而不需要在 metro.config.js 中手动处理加载顺序。
|
|
36
52
|
*
|
|
37
|
-
* @param config Metro config
|
|
38
|
-
* @
|
|
53
|
+
* @param config Metro config 对象
|
|
54
|
+
* @param options nativewind withNativeWind 选项(与原包 API 完全一致)
|
|
39
55
|
*/
|
|
40
|
-
declare function
|
|
41
|
-
|
|
42
|
-
interface InjectOptions {
|
|
43
|
-
}
|
|
56
|
+
declare function withNativeWind(config: MetroConfig, options?: any): MetroConfig;
|
|
57
|
+
|
|
44
58
|
/**
|
|
45
|
-
* 在 expo-router
|
|
59
|
+
* withEntryInjection — 在 expo-router 启动前注入脚本
|
|
46
60
|
*
|
|
47
61
|
* 注入原理:
|
|
48
62
|
* 拦截 Metro 对 expo-router/entry-classic 的解析,将其重定向到
|
|
49
|
-
* dist/stubs/expo-router-entry-stub.js。
|
|
63
|
+
* dist/stubs/expo-router-entry-stub.js。stub 先 require entry-inject.js
|
|
50
64
|
* (注入脚本),再 require expo-router/entry-classic(原入口),
|
|
51
65
|
* 从而在 expo-router 启动前执行注入逻辑。
|
|
52
66
|
*
|
|
@@ -57,20 +71,46 @@ interface InjectOptions {
|
|
|
57
71
|
* 这条 import 语句经过 resolveRequest,可以被拦截。
|
|
58
72
|
*
|
|
59
73
|
* 执行顺序(在 bundle 中):
|
|
60
|
-
* entry-inject.js
|
|
61
|
-
* → expo-router/entry-classic(原 expo-router 入口)
|
|
62
|
-
* → renderRootComponent(App)
|
|
74
|
+
* entry-inject.js → expo-router/entry-classic → renderRootComponent(App)
|
|
63
75
|
*
|
|
64
76
|
* 注入的脚本经过完整 Babel 编译,支持现代语法,web + native 双平台均有效。
|
|
77
|
+
* 支持与 withDevStubs 及其他 Metro wrapper 链式组合。
|
|
65
78
|
*
|
|
66
|
-
*
|
|
79
|
+
* 用法(metro.config.js):
|
|
80
|
+
* const { withEntryInjection } = require('miaoda-expo-devkit/metro');
|
|
67
81
|
* module.exports = withEntryInjection(withDevStubs(config));
|
|
82
|
+
*/
|
|
83
|
+
|
|
84
|
+
/** withEntryInjection 的配置选项(预留,供未来支持自定义注入脚本路径扩展) */
|
|
85
|
+
interface InjectOptions {
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* 在 expo-router 启动前注入一段脚本。
|
|
68
89
|
*
|
|
69
90
|
* @param config Metro config 对象
|
|
70
91
|
* @param options 注入选项(当前预留,未来支持自定义注入脚本路径)
|
|
71
92
|
* @returns 注入 resolveRequest 后的新 Metro config
|
|
72
93
|
*/
|
|
73
94
|
declare function withEntryInjection(config: MetroConfig, options?: InjectOptions): MetroConfig;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* withRouteEndpoint — 为 Metro server 添加路由树查询端点
|
|
98
|
+
*
|
|
99
|
+
* 端点(默认 /__routes)返回 JSON 格式的路由树:
|
|
100
|
+
* {
|
|
101
|
+
* "routes": [
|
|
102
|
+
* { "title": "首页", "pageId": "/", "pageName": "index", "visible": true, "path": "src/app/index.tsx" },
|
|
103
|
+
* { "title": "id", "pageId": "/user/[id]", "pageName": "user-[id]", "visible": false, "path": "src/app/user/[id].tsx" }
|
|
104
|
+
* ]
|
|
105
|
+
* }
|
|
106
|
+
*
|
|
107
|
+
* 用法(metro.config.js):
|
|
108
|
+
* const { withRouteEndpoint } = require('miaoda-expo-devkit/metro');
|
|
109
|
+
* module.exports = withRouteEndpoint(config, {
|
|
110
|
+
* appDir: path.join(__dirname, 'src', 'app'),
|
|
111
|
+
* });
|
|
112
|
+
*/
|
|
113
|
+
|
|
74
114
|
/** withRouteEndpoint 的配置选项 */
|
|
75
115
|
interface RouteEndpointOptions {
|
|
76
116
|
/** app 目录的绝对路径(包含路由文件的目录) */
|
|
@@ -81,41 +121,98 @@ interface RouteEndpointOptions {
|
|
|
81
121
|
/**
|
|
82
122
|
* 为 Metro server 添加 /__routes 端点,返回路由树 JSON。
|
|
83
123
|
*
|
|
84
|
-
* 端点返回格式:
|
|
85
|
-
* {
|
|
86
|
-
* "routes": [
|
|
87
|
-
* { "title": "首页", "pageId": "/", "pageName": "index", "visible": true, "path": "src/app/index.tsx" },
|
|
88
|
-
* { "title": "id", "pageId": "/user/[id]", "pageName": "user-[id]", "visible": false, "path": "src/app/user/[id].tsx" }
|
|
89
|
-
* ]
|
|
90
|
-
* }
|
|
91
|
-
*
|
|
92
124
|
* @param config Metro config 对象
|
|
93
125
|
* @param options 配置选项,必须提供 appDir
|
|
94
126
|
* @returns 增强 server.enhanceMiddleware 后的新 Metro config
|
|
95
127
|
*/
|
|
96
128
|
declare function withRouteEndpoint(config: MetroConfig, options: RouteEndpointOptions): MetroConfig;
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* withDevkit — 一站式 Metro 配置入口
|
|
132
|
+
*
|
|
133
|
+
* 将模板 metro.config.js 所需的所有 devkit wrapper 封装为单个函数调用,
|
|
134
|
+
* 消除模板侧的 boilerplate。内部按固定顺序依次应用:
|
|
135
|
+
*
|
|
136
|
+
* withWorkspaceNodeModules — 修复沙箱中 node_modules 不在 projectRoot 内的问题
|
|
137
|
+
* withCssInterop — 为 expo-image / expo-camera 注入 NativeWind cssInterop
|
|
138
|
+
* withEntryInjection — 在 expo-router 启动前注入脚本(仅 __DEV__)
|
|
139
|
+
* withDevStubs — 替换 Sentry DSN / 屏蔽 LogBox(仅 __DEV__)
|
|
140
|
+
* withRouteEndpoint — 添加 /__routes 端点(仅 __DEV__)
|
|
141
|
+
* withNativeWind — NativeWind 支持(含缓存路径修复)
|
|
142
|
+
*
|
|
143
|
+
* 用法(metro.config.js):
|
|
144
|
+
* const { getDefaultConfig } = require('expo/metro-config');
|
|
145
|
+
* const { withDevkit } = require('miaoda-expo-devkit/metro');
|
|
146
|
+
*
|
|
147
|
+
* module.exports = withDevkit(getDefaultConfig(__dirname));
|
|
148
|
+
*/
|
|
149
|
+
|
|
150
|
+
/** withDevkit 的配置选项 */
|
|
151
|
+
interface DevkitOptions {
|
|
152
|
+
/**
|
|
153
|
+
* NativeWind 的 CSS 入口文件路径(相对于 projectRoot)。
|
|
154
|
+
* 默认:'./src/global.css'
|
|
155
|
+
*/
|
|
156
|
+
input?: string;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* 一站式应用所有 devkit Metro wrapper。
|
|
160
|
+
*
|
|
161
|
+
* @param config Metro config 对象(来自 getDefaultConfig)
|
|
162
|
+
* @param options 配置选项
|
|
163
|
+
* @returns 完整配置后的 Metro config
|
|
164
|
+
*/
|
|
165
|
+
declare function withDevkit(config: MetroConfig, options?: DevkitOptions): MetroConfig;
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* withDevStubs — Metro resolver 注入开发阶段 stub
|
|
169
|
+
*
|
|
170
|
+
* 注入行为:
|
|
171
|
+
* 1. web 平台:@expo/log-box 及 ErrorOverlayWebControls → no-op-logbox stub(屏蔽全屏错误遮罩)
|
|
172
|
+
* 2. 所有平台:@sentry/react-native → sentry-react-native-stub(替换 DSN,注入内置捕获器)
|
|
173
|
+
*
|
|
174
|
+
* 自动保留并调用已有的 resolveRequest,支持与其他 Metro 配置链式组合。
|
|
175
|
+
*
|
|
176
|
+
* 用法(metro.config.js):
|
|
177
|
+
* const { withDevStubs } = require('miaoda-expo-devkit/metro');
|
|
178
|
+
* module.exports = withDevStubs(getDefaultConfig(__dirname));
|
|
179
|
+
*/
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* 将开发阶段 stub 注入到 Metro config 中。
|
|
183
|
+
*
|
|
184
|
+
* @param config Metro config 对象(来自 getDefaultConfig 或 getSentryExpoConfig)
|
|
185
|
+
* @returns 注入 resolveRequest 后的新 Metro config
|
|
186
|
+
*/
|
|
187
|
+
declare function withDevStubs(config: MetroConfig): MetroConfig;
|
|
188
|
+
|
|
97
189
|
/**
|
|
98
|
-
*
|
|
190
|
+
* withWorkspaceNodeModules — 修复沙箱中 node_modules 不在 projectRoot 内时的模块解析问题
|
|
191
|
+
*
|
|
192
|
+
* 适用场景:node_modules 位于 projectRoot 的祖先目录(如 /workspace/node_modules),
|
|
193
|
+
* 而 projectRoot 自身的 node_modules 为空目录或不存在。
|
|
99
194
|
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
* 而非 projectRoot 内(如 /workspace/app/node_modules)。
|
|
103
|
-
* Metro 处理 /assets/?unstable_path=./node_modules/.pnpm/... 请求时,会将路径解析为
|
|
104
|
-
* path.resolve(projectRoot, './node_modules/.pnpm/...'),得到一个不存在的路径,返回 500。
|
|
105
|
-
* 实际文件在父级的 node_modules/.pnpm/ 下。
|
|
195
|
+
* 问题:Metro 只监听 projectRoot,不会自动爬取祖先目录的 node_modules,
|
|
196
|
+
* 导致 Metro 无法在 file map 中找到依赖的真实路径,bundle 请求返回 404。
|
|
106
197
|
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
* 和 resolver.nodeModulesPaths(让模块解析也能找到包)。
|
|
198
|
+
* 修复:将祖先目录中的 node_modules 加入 watchFolders 和 resolver.nodeModulesPaths,
|
|
199
|
+
* 使 Metro 能正确索引并解析其中的模块。
|
|
110
200
|
*
|
|
111
|
-
*
|
|
201
|
+
* 用法(metro.config.js):
|
|
202
|
+
* const { withWorkspaceNodeModules } = require('miaoda-expo-devkit/metro');
|
|
203
|
+
* module.exports = withWorkspaceNodeModules(config);
|
|
204
|
+
*/
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* 修复沙箱环境中 node_modules 位于祖先目录时,Metro 模块解析和 bundle 请求失败的问题。
|
|
112
208
|
*
|
|
113
209
|
* @param config Metro config 对象(来自 getDefaultConfig)
|
|
114
|
-
* @returns 修正 watchFolders
|
|
210
|
+
* @returns 修正 watchFolders、nodeModulesPaths 后的新 Metro config
|
|
115
211
|
*/
|
|
116
212
|
declare function withWorkspaceNodeModules(config: MetroConfig): MetroConfig;
|
|
213
|
+
|
|
117
214
|
/**
|
|
118
|
-
* 为第三方 Expo 组件注入 NativeWind cssInterop
|
|
215
|
+
* withCssInterop — 为第三方 Expo 组件注入 NativeWind cssInterop
|
|
119
216
|
*
|
|
120
217
|
* 注入方式:Metro resolver 层拦截对应包的 import,重定向到 stub 文件。
|
|
121
218
|
* stub 文件透传原包的所有导出,并调用 cssInterop 完成注册。
|
|
@@ -128,53 +225,17 @@ declare function withWorkspaceNodeModules(config: MetroConfig): MetroConfig;
|
|
|
128
225
|
* 此函数在开发和生产环境均需启用(cssInterop 注册与环境无关)。
|
|
129
226
|
* 支持与其他 Metro wrapper 链式组合。
|
|
130
227
|
*
|
|
131
|
-
* @param config Metro config 对象
|
|
132
|
-
* @returns 注入 resolveRequest 后的新 Metro config
|
|
133
|
-
*/
|
|
134
|
-
declare function withCssInterop(config: MetroConfig): MetroConfig;
|
|
135
|
-
/** patchNativeWindCachePath 的配置选项 */
|
|
136
|
-
interface PatchNativeWindCacheOptions {
|
|
137
|
-
/**
|
|
138
|
-
* 缓存目录,相对于 process.cwd()(Metro 项目根目录),默认 .native-wind-cache。
|
|
139
|
-
* 与 package.json 同级,避免写入只读的 node_modules。
|
|
140
|
-
*/
|
|
141
|
-
cacheDir?: string;
|
|
142
|
-
}
|
|
143
|
-
/**
|
|
144
|
-
* 将 NativeWind 编译缓存从 node_modules/.cache 重定向到项目根目录下的自定义目录。
|
|
145
|
-
*
|
|
146
|
-
* ⚠️ 必须在 require('nativewind/metro') / require('react-native-css-interop/dist/metro')
|
|
147
|
-
* 之前调用,否则 outputDirectory 已经固化,patch 无效。
|
|
148
|
-
*
|
|
149
|
-
* 原理:react-native-css-interop/dist/metro 在模块顶层用
|
|
150
|
-
* const outputDirectory = path.resolve(__dirname, "../../.cache")
|
|
151
|
-
* 计算缓存路径。通过在 require 前临时替换 path.resolve,可将该值重定向到
|
|
152
|
-
* 项目根目录下的自定义缓存目录,而无需 fork 或修改 node_modules 源码。
|
|
153
|
-
*
|
|
154
|
-
* 所有依赖 outputDirectory 的 NativeWind 行为(文件写入、虚拟模块 Map key、
|
|
155
|
-
* Metro resolver 返回值、haste 事件)都会一致使用新路径,无需额外 Metro 层面的 patch。
|
|
156
|
-
*
|
|
157
|
-
* ⚠️ 已知限制:依赖 react-native-css-interop 使用 path.resolve 计算缓存路径,
|
|
158
|
-
* 升级该依赖时需确认此假设仍然成立。
|
|
159
|
-
*
|
|
160
228
|
* 用法(metro.config.js):
|
|
161
|
-
* const {
|
|
162
|
-
*
|
|
163
|
-
* const { withNativeWind } = require('nativewind/metro');
|
|
229
|
+
* const { withCssInterop } = require('miaoda-expo-devkit/metro');
|
|
230
|
+
* module.exports = withCssInterop(config);
|
|
164
231
|
*/
|
|
165
|
-
|
|
232
|
+
|
|
166
233
|
/**
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
* nativewind/metro 在模块顶层捕获 react-native-css-interop 的 withCssInterop 引用,
|
|
170
|
-
* 因此必须在 patchNativeWindCachePath() 执行完之后才能加载 nativewind/metro。
|
|
171
|
-
* 这里使用 lazy require(在函数调用时才加载),确保 nativewind 拿到已 patch 的
|
|
172
|
-
* outputDirectory,而不需要在 metro.config.js 中手动处理加载顺序。
|
|
234
|
+
* 为第三方 Expo 组件注入 NativeWind cssInterop,使其支持 className prop。
|
|
173
235
|
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
* // 不再需要 require('nativewind/metro')
|
|
236
|
+
* @param config Metro config 对象
|
|
237
|
+
* @returns 注入 resolveRequest 后的新 Metro config
|
|
177
238
|
*/
|
|
178
|
-
declare function
|
|
239
|
+
declare function withCssInterop(config: MetroConfig): MetroConfig;
|
|
179
240
|
|
|
180
|
-
export { type InjectOptions, type PatchNativeWindCacheOptions, type RouteEndpointOptions, patchNativeWindCachePath, withCssInterop, withDevStubs, withEntryInjection, withNativeWind, withRouteEndpoint, withWorkspaceNodeModules };
|
|
241
|
+
export { type DevkitOptions, type InjectOptions, type PatchNativeWindCacheOptions, type RouteEndpointOptions, patchNativeWindCachePath, withCssInterop, withDevStubs, withDevkit, withEntryInjection, withNativeWind, withRouteEndpoint, withWorkspaceNodeModules };
|
package/dist/metro.d.ts
CHANGED
|
@@ -1,52 +1,66 @@
|
|
|
1
1
|
import { MetroConfig } from 'metro-config';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* withNativeWind / patchNativeWindCachePath — NativeWind 缓存路径修复与 lazy wrapper
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
6
|
+
* patchNativeWindCachePath:
|
|
7
|
+
* 将 NativeWind 编译缓存从 node_modules/.cache 重定向到项目根目录下的自定义目录。
|
|
8
|
+
* ⚠️ 必须在 require('nativewind/metro') 之前调用,否则 outputDirectory 已经固化,patch 无效。
|
|
9
|
+
*
|
|
10
|
+
* withNativeWind:
|
|
11
|
+
* nativewind/metro 的 lazy wrapper,确保 nativewind 在 patchNativeWindCachePath 之后加载,
|
|
12
|
+
* 拿到已 patch 的 outputDirectory。用法与 nativewind 官方 withNativeWind 完全相同。
|
|
11
13
|
*
|
|
12
14
|
* 用法(metro.config.js):
|
|
15
|
+
* const { withNativeWind } = require('miaoda-expo-devkit/metro');
|
|
16
|
+
* // 不再需要单独 require('nativewind/metro')
|
|
17
|
+
* module.exports = withNativeWind(config, { input: './global.css' });
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/** patchNativeWindCachePath 的配置选项 */
|
|
21
|
+
interface PatchNativeWindCacheOptions {
|
|
22
|
+
/**
|
|
23
|
+
* 缓存目录,相对于 process.cwd()(Metro 项目根目录),默认 .native-wind-cache。
|
|
24
|
+
* 与 package.json 同级,避免写入只读的 node_modules。
|
|
25
|
+
*/
|
|
26
|
+
cacheDir?: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* 将 NativeWind 编译缓存从 node_modules/.cache 重定向到项目根目录下的自定义目录。
|
|
13
30
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
31
|
+
* ⚠️ 必须在 require('nativewind/metro') / require('react-native-css-interop/dist/metro')
|
|
32
|
+
* 之前调用,否则 outputDirectory 已经固化,patch 无效。
|
|
16
33
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* );
|
|
34
|
+
* 原理:react-native-css-interop/dist/metro 在模块顶层用
|
|
35
|
+
* const outputDirectory = path.resolve(__dirname, "../../.cache")
|
|
36
|
+
* 计算缓存路径。通过在 require 前临时替换 path.resolve,可将该值重定向到
|
|
37
|
+
* 项目根目录下的自定义缓存目录,而无需 fork 或修改 node_modules 源码。
|
|
22
38
|
*
|
|
23
|
-
*
|
|
39
|
+
* ⚠️ 已知限制:依赖 react-native-css-interop 使用 path.resolve 计算缓存路径,
|
|
40
|
+
* 升级该依赖时需确认此假设仍然成立。
|
|
24
41
|
*
|
|
25
|
-
*
|
|
42
|
+
* @param options 配置选项
|
|
26
43
|
*/
|
|
27
|
-
|
|
44
|
+
declare function patchNativeWindCachePath(options?: PatchNativeWindCacheOptions): void;
|
|
28
45
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* 注入行为:
|
|
32
|
-
* 1. web 平台:@expo/log-box 及 ErrorOverlayWebControls → no-op-logbox stub(屏蔽全屏错误遮罩)
|
|
33
|
-
* 2. 所有平台:@sentry/react-native → sentry-react-native-stub(替换 DSN,注入内置捕获器)
|
|
46
|
+
* withNativeWind 的 lazy wrapper。
|
|
34
47
|
*
|
|
35
|
-
*
|
|
48
|
+
* nativewind/metro 在模块顶层捕获 react-native-css-interop 的 withCssInterop 引用,
|
|
49
|
+
* 因此必须在 patchNativeWindCachePath() 执行完之后才能加载 nativewind/metro。
|
|
50
|
+
* 这里使用 lazy require(在函数调用时才加载),确保 nativewind 拿到已 patch 的
|
|
51
|
+
* outputDirectory,而不需要在 metro.config.js 中手动处理加载顺序。
|
|
36
52
|
*
|
|
37
|
-
* @param config Metro config
|
|
38
|
-
* @
|
|
53
|
+
* @param config Metro config 对象
|
|
54
|
+
* @param options nativewind withNativeWind 选项(与原包 API 完全一致)
|
|
39
55
|
*/
|
|
40
|
-
declare function
|
|
41
|
-
|
|
42
|
-
interface InjectOptions {
|
|
43
|
-
}
|
|
56
|
+
declare function withNativeWind(config: MetroConfig, options?: any): MetroConfig;
|
|
57
|
+
|
|
44
58
|
/**
|
|
45
|
-
* 在 expo-router
|
|
59
|
+
* withEntryInjection — 在 expo-router 启动前注入脚本
|
|
46
60
|
*
|
|
47
61
|
* 注入原理:
|
|
48
62
|
* 拦截 Metro 对 expo-router/entry-classic 的解析,将其重定向到
|
|
49
|
-
* dist/stubs/expo-router-entry-stub.js。
|
|
63
|
+
* dist/stubs/expo-router-entry-stub.js。stub 先 require entry-inject.js
|
|
50
64
|
* (注入脚本),再 require expo-router/entry-classic(原入口),
|
|
51
65
|
* 从而在 expo-router 启动前执行注入逻辑。
|
|
52
66
|
*
|
|
@@ -57,20 +71,46 @@ interface InjectOptions {
|
|
|
57
71
|
* 这条 import 语句经过 resolveRequest,可以被拦截。
|
|
58
72
|
*
|
|
59
73
|
* 执行顺序(在 bundle 中):
|
|
60
|
-
* entry-inject.js
|
|
61
|
-
* → expo-router/entry-classic(原 expo-router 入口)
|
|
62
|
-
* → renderRootComponent(App)
|
|
74
|
+
* entry-inject.js → expo-router/entry-classic → renderRootComponent(App)
|
|
63
75
|
*
|
|
64
76
|
* 注入的脚本经过完整 Babel 编译,支持现代语法,web + native 双平台均有效。
|
|
77
|
+
* 支持与 withDevStubs 及其他 Metro wrapper 链式组合。
|
|
65
78
|
*
|
|
66
|
-
*
|
|
79
|
+
* 用法(metro.config.js):
|
|
80
|
+
* const { withEntryInjection } = require('miaoda-expo-devkit/metro');
|
|
67
81
|
* module.exports = withEntryInjection(withDevStubs(config));
|
|
82
|
+
*/
|
|
83
|
+
|
|
84
|
+
/** withEntryInjection 的配置选项(预留,供未来支持自定义注入脚本路径扩展) */
|
|
85
|
+
interface InjectOptions {
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* 在 expo-router 启动前注入一段脚本。
|
|
68
89
|
*
|
|
69
90
|
* @param config Metro config 对象
|
|
70
91
|
* @param options 注入选项(当前预留,未来支持自定义注入脚本路径)
|
|
71
92
|
* @returns 注入 resolveRequest 后的新 Metro config
|
|
72
93
|
*/
|
|
73
94
|
declare function withEntryInjection(config: MetroConfig, options?: InjectOptions): MetroConfig;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* withRouteEndpoint — 为 Metro server 添加路由树查询端点
|
|
98
|
+
*
|
|
99
|
+
* 端点(默认 /__routes)返回 JSON 格式的路由树:
|
|
100
|
+
* {
|
|
101
|
+
* "routes": [
|
|
102
|
+
* { "title": "首页", "pageId": "/", "pageName": "index", "visible": true, "path": "src/app/index.tsx" },
|
|
103
|
+
* { "title": "id", "pageId": "/user/[id]", "pageName": "user-[id]", "visible": false, "path": "src/app/user/[id].tsx" }
|
|
104
|
+
* ]
|
|
105
|
+
* }
|
|
106
|
+
*
|
|
107
|
+
* 用法(metro.config.js):
|
|
108
|
+
* const { withRouteEndpoint } = require('miaoda-expo-devkit/metro');
|
|
109
|
+
* module.exports = withRouteEndpoint(config, {
|
|
110
|
+
* appDir: path.join(__dirname, 'src', 'app'),
|
|
111
|
+
* });
|
|
112
|
+
*/
|
|
113
|
+
|
|
74
114
|
/** withRouteEndpoint 的配置选项 */
|
|
75
115
|
interface RouteEndpointOptions {
|
|
76
116
|
/** app 目录的绝对路径(包含路由文件的目录) */
|
|
@@ -81,41 +121,98 @@ interface RouteEndpointOptions {
|
|
|
81
121
|
/**
|
|
82
122
|
* 为 Metro server 添加 /__routes 端点,返回路由树 JSON。
|
|
83
123
|
*
|
|
84
|
-
* 端点返回格式:
|
|
85
|
-
* {
|
|
86
|
-
* "routes": [
|
|
87
|
-
* { "title": "首页", "pageId": "/", "pageName": "index", "visible": true, "path": "src/app/index.tsx" },
|
|
88
|
-
* { "title": "id", "pageId": "/user/[id]", "pageName": "user-[id]", "visible": false, "path": "src/app/user/[id].tsx" }
|
|
89
|
-
* ]
|
|
90
|
-
* }
|
|
91
|
-
*
|
|
92
124
|
* @param config Metro config 对象
|
|
93
125
|
* @param options 配置选项,必须提供 appDir
|
|
94
126
|
* @returns 增强 server.enhanceMiddleware 后的新 Metro config
|
|
95
127
|
*/
|
|
96
128
|
declare function withRouteEndpoint(config: MetroConfig, options: RouteEndpointOptions): MetroConfig;
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* withDevkit — 一站式 Metro 配置入口
|
|
132
|
+
*
|
|
133
|
+
* 将模板 metro.config.js 所需的所有 devkit wrapper 封装为单个函数调用,
|
|
134
|
+
* 消除模板侧的 boilerplate。内部按固定顺序依次应用:
|
|
135
|
+
*
|
|
136
|
+
* withWorkspaceNodeModules — 修复沙箱中 node_modules 不在 projectRoot 内的问题
|
|
137
|
+
* withCssInterop — 为 expo-image / expo-camera 注入 NativeWind cssInterop
|
|
138
|
+
* withEntryInjection — 在 expo-router 启动前注入脚本(仅 __DEV__)
|
|
139
|
+
* withDevStubs — 替换 Sentry DSN / 屏蔽 LogBox(仅 __DEV__)
|
|
140
|
+
* withRouteEndpoint — 添加 /__routes 端点(仅 __DEV__)
|
|
141
|
+
* withNativeWind — NativeWind 支持(含缓存路径修复)
|
|
142
|
+
*
|
|
143
|
+
* 用法(metro.config.js):
|
|
144
|
+
* const { getDefaultConfig } = require('expo/metro-config');
|
|
145
|
+
* const { withDevkit } = require('miaoda-expo-devkit/metro');
|
|
146
|
+
*
|
|
147
|
+
* module.exports = withDevkit(getDefaultConfig(__dirname));
|
|
148
|
+
*/
|
|
149
|
+
|
|
150
|
+
/** withDevkit 的配置选项 */
|
|
151
|
+
interface DevkitOptions {
|
|
152
|
+
/**
|
|
153
|
+
* NativeWind 的 CSS 入口文件路径(相对于 projectRoot)。
|
|
154
|
+
* 默认:'./src/global.css'
|
|
155
|
+
*/
|
|
156
|
+
input?: string;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* 一站式应用所有 devkit Metro wrapper。
|
|
160
|
+
*
|
|
161
|
+
* @param config Metro config 对象(来自 getDefaultConfig)
|
|
162
|
+
* @param options 配置选项
|
|
163
|
+
* @returns 完整配置后的 Metro config
|
|
164
|
+
*/
|
|
165
|
+
declare function withDevkit(config: MetroConfig, options?: DevkitOptions): MetroConfig;
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* withDevStubs — Metro resolver 注入开发阶段 stub
|
|
169
|
+
*
|
|
170
|
+
* 注入行为:
|
|
171
|
+
* 1. web 平台:@expo/log-box 及 ErrorOverlayWebControls → no-op-logbox stub(屏蔽全屏错误遮罩)
|
|
172
|
+
* 2. 所有平台:@sentry/react-native → sentry-react-native-stub(替换 DSN,注入内置捕获器)
|
|
173
|
+
*
|
|
174
|
+
* 自动保留并调用已有的 resolveRequest,支持与其他 Metro 配置链式组合。
|
|
175
|
+
*
|
|
176
|
+
* 用法(metro.config.js):
|
|
177
|
+
* const { withDevStubs } = require('miaoda-expo-devkit/metro');
|
|
178
|
+
* module.exports = withDevStubs(getDefaultConfig(__dirname));
|
|
179
|
+
*/
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* 将开发阶段 stub 注入到 Metro config 中。
|
|
183
|
+
*
|
|
184
|
+
* @param config Metro config 对象(来自 getDefaultConfig 或 getSentryExpoConfig)
|
|
185
|
+
* @returns 注入 resolveRequest 后的新 Metro config
|
|
186
|
+
*/
|
|
187
|
+
declare function withDevStubs(config: MetroConfig): MetroConfig;
|
|
188
|
+
|
|
97
189
|
/**
|
|
98
|
-
*
|
|
190
|
+
* withWorkspaceNodeModules — 修复沙箱中 node_modules 不在 projectRoot 内时的模块解析问题
|
|
191
|
+
*
|
|
192
|
+
* 适用场景:node_modules 位于 projectRoot 的祖先目录(如 /workspace/node_modules),
|
|
193
|
+
* 而 projectRoot 自身的 node_modules 为空目录或不存在。
|
|
99
194
|
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
* 而非 projectRoot 内(如 /workspace/app/node_modules)。
|
|
103
|
-
* Metro 处理 /assets/?unstable_path=./node_modules/.pnpm/... 请求时,会将路径解析为
|
|
104
|
-
* path.resolve(projectRoot, './node_modules/.pnpm/...'),得到一个不存在的路径,返回 500。
|
|
105
|
-
* 实际文件在父级的 node_modules/.pnpm/ 下。
|
|
195
|
+
* 问题:Metro 只监听 projectRoot,不会自动爬取祖先目录的 node_modules,
|
|
196
|
+
* 导致 Metro 无法在 file map 中找到依赖的真实路径,bundle 请求返回 404。
|
|
106
197
|
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
* 和 resolver.nodeModulesPaths(让模块解析也能找到包)。
|
|
198
|
+
* 修复:将祖先目录中的 node_modules 加入 watchFolders 和 resolver.nodeModulesPaths,
|
|
199
|
+
* 使 Metro 能正确索引并解析其中的模块。
|
|
110
200
|
*
|
|
111
|
-
*
|
|
201
|
+
* 用法(metro.config.js):
|
|
202
|
+
* const { withWorkspaceNodeModules } = require('miaoda-expo-devkit/metro');
|
|
203
|
+
* module.exports = withWorkspaceNodeModules(config);
|
|
204
|
+
*/
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* 修复沙箱环境中 node_modules 位于祖先目录时,Metro 模块解析和 bundle 请求失败的问题。
|
|
112
208
|
*
|
|
113
209
|
* @param config Metro config 对象(来自 getDefaultConfig)
|
|
114
|
-
* @returns 修正 watchFolders
|
|
210
|
+
* @returns 修正 watchFolders、nodeModulesPaths 后的新 Metro config
|
|
115
211
|
*/
|
|
116
212
|
declare function withWorkspaceNodeModules(config: MetroConfig): MetroConfig;
|
|
213
|
+
|
|
117
214
|
/**
|
|
118
|
-
* 为第三方 Expo 组件注入 NativeWind cssInterop
|
|
215
|
+
* withCssInterop — 为第三方 Expo 组件注入 NativeWind cssInterop
|
|
119
216
|
*
|
|
120
217
|
* 注入方式:Metro resolver 层拦截对应包的 import,重定向到 stub 文件。
|
|
121
218
|
* stub 文件透传原包的所有导出,并调用 cssInterop 完成注册。
|
|
@@ -128,53 +225,17 @@ declare function withWorkspaceNodeModules(config: MetroConfig): MetroConfig;
|
|
|
128
225
|
* 此函数在开发和生产环境均需启用(cssInterop 注册与环境无关)。
|
|
129
226
|
* 支持与其他 Metro wrapper 链式组合。
|
|
130
227
|
*
|
|
131
|
-
* @param config Metro config 对象
|
|
132
|
-
* @returns 注入 resolveRequest 后的新 Metro config
|
|
133
|
-
*/
|
|
134
|
-
declare function withCssInterop(config: MetroConfig): MetroConfig;
|
|
135
|
-
/** patchNativeWindCachePath 的配置选项 */
|
|
136
|
-
interface PatchNativeWindCacheOptions {
|
|
137
|
-
/**
|
|
138
|
-
* 缓存目录,相对于 process.cwd()(Metro 项目根目录),默认 .native-wind-cache。
|
|
139
|
-
* 与 package.json 同级,避免写入只读的 node_modules。
|
|
140
|
-
*/
|
|
141
|
-
cacheDir?: string;
|
|
142
|
-
}
|
|
143
|
-
/**
|
|
144
|
-
* 将 NativeWind 编译缓存从 node_modules/.cache 重定向到项目根目录下的自定义目录。
|
|
145
|
-
*
|
|
146
|
-
* ⚠️ 必须在 require('nativewind/metro') / require('react-native-css-interop/dist/metro')
|
|
147
|
-
* 之前调用,否则 outputDirectory 已经固化,patch 无效。
|
|
148
|
-
*
|
|
149
|
-
* 原理:react-native-css-interop/dist/metro 在模块顶层用
|
|
150
|
-
* const outputDirectory = path.resolve(__dirname, "../../.cache")
|
|
151
|
-
* 计算缓存路径。通过在 require 前临时替换 path.resolve,可将该值重定向到
|
|
152
|
-
* 项目根目录下的自定义缓存目录,而无需 fork 或修改 node_modules 源码。
|
|
153
|
-
*
|
|
154
|
-
* 所有依赖 outputDirectory 的 NativeWind 行为(文件写入、虚拟模块 Map key、
|
|
155
|
-
* Metro resolver 返回值、haste 事件)都会一致使用新路径,无需额外 Metro 层面的 patch。
|
|
156
|
-
*
|
|
157
|
-
* ⚠️ 已知限制:依赖 react-native-css-interop 使用 path.resolve 计算缓存路径,
|
|
158
|
-
* 升级该依赖时需确认此假设仍然成立。
|
|
159
|
-
*
|
|
160
228
|
* 用法(metro.config.js):
|
|
161
|
-
* const {
|
|
162
|
-
*
|
|
163
|
-
* const { withNativeWind } = require('nativewind/metro');
|
|
229
|
+
* const { withCssInterop } = require('miaoda-expo-devkit/metro');
|
|
230
|
+
* module.exports = withCssInterop(config);
|
|
164
231
|
*/
|
|
165
|
-
|
|
232
|
+
|
|
166
233
|
/**
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
* nativewind/metro 在模块顶层捕获 react-native-css-interop 的 withCssInterop 引用,
|
|
170
|
-
* 因此必须在 patchNativeWindCachePath() 执行完之后才能加载 nativewind/metro。
|
|
171
|
-
* 这里使用 lazy require(在函数调用时才加载),确保 nativewind 拿到已 patch 的
|
|
172
|
-
* outputDirectory,而不需要在 metro.config.js 中手动处理加载顺序。
|
|
234
|
+
* 为第三方 Expo 组件注入 NativeWind cssInterop,使其支持 className prop。
|
|
173
235
|
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
* // 不再需要 require('nativewind/metro')
|
|
236
|
+
* @param config Metro config 对象
|
|
237
|
+
* @returns 注入 resolveRequest 后的新 Metro config
|
|
177
238
|
*/
|
|
178
|
-
declare function
|
|
239
|
+
declare function withCssInterop(config: MetroConfig): MetroConfig;
|
|
179
240
|
|
|
180
|
-
export { type InjectOptions, type PatchNativeWindCacheOptions, type RouteEndpointOptions, patchNativeWindCachePath, withCssInterop, withDevStubs, withEntryInjection, withNativeWind, withRouteEndpoint, withWorkspaceNodeModules };
|
|
241
|
+
export { type DevkitOptions, type InjectOptions, type PatchNativeWindCacheOptions, type RouteEndpointOptions, patchNativeWindCachePath, withCssInterop, withDevStubs, withDevkit, withEntryInjection, withNativeWind, withRouteEndpoint, withWorkspaceNodeModules };
|