miaoda-expo-devkit 0.1.1-beta.6 → 0.1.1-beta.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/metro.d.mts CHANGED
@@ -189,24 +189,22 @@ declare function withDevStubs(config: MetroConfig): MetroConfig;
189
189
  /**
190
190
  * withWorkspaceNodeModules — 修复沙箱中 node_modules 不在 projectRoot 内时的模块解析问题
191
191
  *
192
- * 覆盖两种场景:
193
- *
194
- * 场景 A — node_modules 在 projectRoot 的上层目录(如 /workspace/node_modules):
195
- * Metro 处理资源请求 /assets/?unstable_path=./node_modules/.pnpm/... 时,将路径解析为
196
- * path.resolve(projectRoot, './node_modules/.pnpm/...'),得到不存在的路径,返回 500。
197
- * 修复:将上层的 node_modules 加入 watchFolders 和 resolver.nodeModulesPaths。
198
- *
199
- * 场景 B — node_modules 在与 projectRoot 完全不同的路径(如 /data/expo/node_modules):
200
- * Expo CLI 将入口文件的绝对路径(/data/expo/node_modules/.../expo-router/entry)
201
- * 直接用作 bundle URL 路径。Metro 收到后去掉前导 "/" 并加上 "./",
202
- * 得到 "./data/expo/node_modules/...",再从 projectRoot 解析,找不到文件。
203
- * 修复:在上述两项基础上,追加自定义 resolver,
204
- * "./data/expo/..." 还原为 "/data/expo/..." 后直接返回文件路径。
205
- *
206
- * node_modules 定位策略(按优先级):
207
- * 1. projectRoot 向上逐级查找 node_modules 目录;
208
- * 2. 若未找到,通过 require.resolve 定位当前包所在的 node_modules 根目录
209
- * (适用于 node_modules 位于完全不同路径的情况)。
192
+ * 适用场景:node_modules 位于 projectRoot 的祖先目录(如 /workspace/node_modules),
193
+ * 而 projectRoot 自身的 node_modules 为空目录或不存在。
194
+ *
195
+ * 问题:
196
+ * 1. Metro 只监听 projectRoot,祖先目录的 node_modules 不在 watchFolders 内,
197
+ * 导致模块无法被 file map 索引。
198
+ * 2. pnpm 的 .pnpm 目录可能是指向外部路径的 symlink
199
+ * (如 /workspace/node_modules/.pnpm /data/expo/node_modules/.pnpm)。
200
+ * Metro 跟随 symlink 后,将文件以真实路径(/data/expo/...)存入 file map,
201
+ * HTML 入口的 bundle URL 也随之变为 /data/expo/...bundle。
202
+ * /data/expo/node_modules/ 不在 watchFolders,Metro HTTP server 会返回 404。
203
+ *
204
+ * 修复:
205
+ * 1. 将祖先目录的 node_modules 加入 watchFolders 和 resolver.nodeModulesPaths。
206
+ * 2. 若该 node_modules 下的 .pnpm 是指向外部路径的 symlink,
207
+ * 同样将外部真实路径加入 watchFolders resolver.nodeModulesPaths。
210
208
  *
211
209
  * 用法(metro.config.js):
212
210
  * const { withWorkspaceNodeModules } = require('miaoda-expo-devkit/metro');
@@ -214,10 +212,10 @@ declare function withDevStubs(config: MetroConfig): MetroConfig;
214
212
  */
215
213
 
216
214
  /**
217
- * 修复沙箱环境中 node_modules 不在 projectRoot 内时,Metro 资源和入口模块解析失败的问题。
215
+ * 修复沙箱环境中 node_modules 位于祖先目录时,Metro 模块解析和 bundle 请求失败的问题。
218
216
  *
219
217
  * @param config Metro config 对象(来自 getDefaultConfig)
220
- * @returns 修正 watchFolders、nodeModulesPaths(及必要时 resolveRequest)后的新 Metro config
218
+ * @returns 修正 watchFolders、nodeModulesPaths 后的新 Metro config
221
219
  */
222
220
  declare function withWorkspaceNodeModules(config: MetroConfig): MetroConfig;
223
221
 
package/dist/metro.d.ts CHANGED
@@ -189,24 +189,22 @@ declare function withDevStubs(config: MetroConfig): MetroConfig;
189
189
  /**
190
190
  * withWorkspaceNodeModules — 修复沙箱中 node_modules 不在 projectRoot 内时的模块解析问题
191
191
  *
192
- * 覆盖两种场景:
193
- *
194
- * 场景 A — node_modules 在 projectRoot 的上层目录(如 /workspace/node_modules):
195
- * Metro 处理资源请求 /assets/?unstable_path=./node_modules/.pnpm/... 时,将路径解析为
196
- * path.resolve(projectRoot, './node_modules/.pnpm/...'),得到不存在的路径,返回 500。
197
- * 修复:将上层的 node_modules 加入 watchFolders 和 resolver.nodeModulesPaths。
198
- *
199
- * 场景 B — node_modules 在与 projectRoot 完全不同的路径(如 /data/expo/node_modules):
200
- * Expo CLI 将入口文件的绝对路径(/data/expo/node_modules/.../expo-router/entry)
201
- * 直接用作 bundle URL 路径。Metro 收到后去掉前导 "/" 并加上 "./",
202
- * 得到 "./data/expo/node_modules/...",再从 projectRoot 解析,找不到文件。
203
- * 修复:在上述两项基础上,追加自定义 resolver,
204
- * "./data/expo/..." 还原为 "/data/expo/..." 后直接返回文件路径。
205
- *
206
- * node_modules 定位策略(按优先级):
207
- * 1. projectRoot 向上逐级查找 node_modules 目录;
208
- * 2. 若未找到,通过 require.resolve 定位当前包所在的 node_modules 根目录
209
- * (适用于 node_modules 位于完全不同路径的情况)。
192
+ * 适用场景:node_modules 位于 projectRoot 的祖先目录(如 /workspace/node_modules),
193
+ * 而 projectRoot 自身的 node_modules 为空目录或不存在。
194
+ *
195
+ * 问题:
196
+ * 1. Metro 只监听 projectRoot,祖先目录的 node_modules 不在 watchFolders 内,
197
+ * 导致模块无法被 file map 索引。
198
+ * 2. pnpm 的 .pnpm 目录可能是指向外部路径的 symlink
199
+ * (如 /workspace/node_modules/.pnpm /data/expo/node_modules/.pnpm)。
200
+ * Metro 跟随 symlink 后,将文件以真实路径(/data/expo/...)存入 file map,
201
+ * HTML 入口的 bundle URL 也随之变为 /data/expo/...bundle。
202
+ * /data/expo/node_modules/ 不在 watchFolders,Metro HTTP server 会返回 404。
203
+ *
204
+ * 修复:
205
+ * 1. 将祖先目录的 node_modules 加入 watchFolders 和 resolver.nodeModulesPaths。
206
+ * 2. 若该 node_modules 下的 .pnpm 是指向外部路径的 symlink,
207
+ * 同样将外部真实路径加入 watchFolders resolver.nodeModulesPaths。
210
208
  *
211
209
  * 用法(metro.config.js):
212
210
  * const { withWorkspaceNodeModules } = require('miaoda-expo-devkit/metro');
@@ -214,10 +212,10 @@ declare function withDevStubs(config: MetroConfig): MetroConfig;
214
212
  */
215
213
 
216
214
  /**
217
- * 修复沙箱环境中 node_modules 不在 projectRoot 内时,Metro 资源和入口模块解析失败的问题。
215
+ * 修复沙箱环境中 node_modules 位于祖先目录时,Metro 模块解析和 bundle 请求失败的问题。
218
216
  *
219
217
  * @param config Metro config 对象(来自 getDefaultConfig)
220
- * @returns 修正 watchFolders、nodeModulesPaths(及必要时 resolveRequest)后的新 Metro config
218
+ * @returns 修正 watchFolders、nodeModulesPaths 后的新 Metro config
221
219
  */
222
220
  declare function withWorkspaceNodeModules(config: MetroConfig): MetroConfig;
223
221
 
package/dist/metro.js CHANGED
@@ -202,7 +202,7 @@ function withRouteEndpoint(config, options) {
202
202
  // src/metro/withWorkspaceNodeModules.ts
203
203
  var import_fs2 = __toESM(require("fs"));
204
204
  var import_path5 = __toESM(require("path"));
205
- function findAncestorNodeModulesDir(projectRoot, resolvePackage = require.resolve) {
205
+ function findAncestorNodeModulesDir(projectRoot) {
206
206
  let dir = import_path5.default.dirname(projectRoot);
207
207
  while (true) {
208
208
  const candidate = import_path5.default.join(dir, "node_modules");
@@ -211,15 +211,15 @@ function findAncestorNodeModulesDir(projectRoot, resolvePackage = require.resolv
211
211
  if (parent === dir) break;
212
212
  dir = parent;
213
213
  }
214
+ return null;
215
+ }
216
+ function resolveExternalPnpmStore(nodeModulesDir) {
217
+ const pnpmDir = import_path5.default.join(nodeModulesDir, ".pnpm");
214
218
  try {
215
- const resolved = resolvePackage("metro-config/package.json");
216
- const parts = resolved.split(import_path5.default.sep);
217
- const nmIndex = parts.indexOf("node_modules");
218
- if (nmIndex > 0) {
219
- const candidate = parts.slice(0, nmIndex + 1).join(import_path5.default.sep) || import_path5.default.sep;
220
- if (import_fs2.default.existsSync(candidate) && candidate !== import_path5.default.join(projectRoot, "node_modules")) {
221
- return candidate;
222
- }
219
+ const realPnpmDir = import_fs2.default.realpathSync(pnpmDir);
220
+ const realNmDir = import_path5.default.dirname(realPnpmDir);
221
+ if (realNmDir !== nodeModulesDir) {
222
+ return realNmDir;
223
223
  }
224
224
  } catch {
225
225
  }
@@ -227,49 +227,19 @@ function findAncestorNodeModulesDir(projectRoot, resolvePackage = require.resolv
227
227
  }
228
228
  function withWorkspaceNodeModules(config) {
229
229
  const projectRoot = config.projectRoot ?? process.cwd();
230
- if (import_fs2.default.existsSync(import_path5.default.join(projectRoot, "node_modules"))) {
231
- return config;
232
- }
233
230
  const found = findAncestorNodeModulesDir(projectRoot);
234
231
  if (!found) return config;
235
- const existingWatchFolders = config.watchFolders ?? [];
236
- const existingNodeModulesPaths = config.resolver?.nodeModulesPaths ?? [];
237
- const foundParent = import_path5.default.dirname(found);
238
- const foundParentWithSep = foundParent.endsWith(import_path5.default.sep) ? foundParent : foundParent + import_path5.default.sep;
239
- const isExternalPath = !projectRoot.startsWith(foundParentWithSep);
240
- if (!isExternalPath) {
241
- return {
242
- ...config,
243
- watchFolders: [...existingWatchFolders, found],
244
- resolver: {
245
- ...config.resolver,
246
- nodeModulesPaths: [...existingNodeModulesPaths, found]
247
- }
248
- };
232
+ const foldersToAdd = [found];
233
+ const externalStore = resolveExternalPnpmStore(found);
234
+ if (externalStore) {
235
+ foldersToAdd.push(externalStore);
249
236
  }
250
- const upstream = config.resolver?.resolveRequest ?? null;
251
- const foundRelativePrefix = found.slice(1) + import_path5.default.sep;
252
- const resolveRequest = (context, moduleName, platform) => {
253
- if (moduleName.startsWith("./") && moduleName.slice(2).startsWith(foundRelativePrefix)) {
254
- const absolutePath = import_path5.default.sep + moduleName.slice(2);
255
- const extsToTry = ["", ".js", ".ts", ".tsx", ".jsx", ".json"];
256
- for (const ext of extsToTry) {
257
- const candidate = absolutePath + ext;
258
- if (import_fs2.default.existsSync(candidate)) {
259
- return { filePath: candidate, type: "sourceFile" };
260
- }
261
- }
262
- }
263
- if (upstream) return upstream(context, moduleName, platform);
264
- return context.resolveRequest(context, moduleName, platform);
265
- };
266
237
  return {
267
238
  ...config,
268
- watchFolders: [...existingWatchFolders, found],
239
+ watchFolders: [...config.watchFolders ?? [], ...foldersToAdd],
269
240
  resolver: {
270
241
  ...config.resolver,
271
- nodeModulesPaths: [...existingNodeModulesPaths, found],
272
- resolveRequest
242
+ nodeModulesPaths: [...config.resolver?.nodeModulesPaths ?? [], ...foldersToAdd]
273
243
  }
274
244
  };
275
245
  }
package/dist/metro.mjs CHANGED
@@ -166,7 +166,7 @@ function withRouteEndpoint(config, options) {
166
166
  // src/metro/withWorkspaceNodeModules.ts
167
167
  import fs2 from "fs";
168
168
  import path5 from "path";
169
- function findAncestorNodeModulesDir(projectRoot, resolvePackage = __require.resolve) {
169
+ function findAncestorNodeModulesDir(projectRoot) {
170
170
  let dir = path5.dirname(projectRoot);
171
171
  while (true) {
172
172
  const candidate = path5.join(dir, "node_modules");
@@ -175,15 +175,15 @@ function findAncestorNodeModulesDir(projectRoot, resolvePackage = __require.reso
175
175
  if (parent === dir) break;
176
176
  dir = parent;
177
177
  }
178
+ return null;
179
+ }
180
+ function resolveExternalPnpmStore(nodeModulesDir) {
181
+ const pnpmDir = path5.join(nodeModulesDir, ".pnpm");
178
182
  try {
179
- const resolved = resolvePackage("metro-config/package.json");
180
- const parts = resolved.split(path5.sep);
181
- const nmIndex = parts.indexOf("node_modules");
182
- if (nmIndex > 0) {
183
- const candidate = parts.slice(0, nmIndex + 1).join(path5.sep) || path5.sep;
184
- if (fs2.existsSync(candidate) && candidate !== path5.join(projectRoot, "node_modules")) {
185
- return candidate;
186
- }
183
+ const realPnpmDir = fs2.realpathSync(pnpmDir);
184
+ const realNmDir = path5.dirname(realPnpmDir);
185
+ if (realNmDir !== nodeModulesDir) {
186
+ return realNmDir;
187
187
  }
188
188
  } catch {
189
189
  }
@@ -191,49 +191,19 @@ function findAncestorNodeModulesDir(projectRoot, resolvePackage = __require.reso
191
191
  }
192
192
  function withWorkspaceNodeModules(config) {
193
193
  const projectRoot = config.projectRoot ?? process.cwd();
194
- if (fs2.existsSync(path5.join(projectRoot, "node_modules"))) {
195
- return config;
196
- }
197
194
  const found = findAncestorNodeModulesDir(projectRoot);
198
195
  if (!found) return config;
199
- const existingWatchFolders = config.watchFolders ?? [];
200
- const existingNodeModulesPaths = config.resolver?.nodeModulesPaths ?? [];
201
- const foundParent = path5.dirname(found);
202
- const foundParentWithSep = foundParent.endsWith(path5.sep) ? foundParent : foundParent + path5.sep;
203
- const isExternalPath = !projectRoot.startsWith(foundParentWithSep);
204
- if (!isExternalPath) {
205
- return {
206
- ...config,
207
- watchFolders: [...existingWatchFolders, found],
208
- resolver: {
209
- ...config.resolver,
210
- nodeModulesPaths: [...existingNodeModulesPaths, found]
211
- }
212
- };
196
+ const foldersToAdd = [found];
197
+ const externalStore = resolveExternalPnpmStore(found);
198
+ if (externalStore) {
199
+ foldersToAdd.push(externalStore);
213
200
  }
214
- const upstream = config.resolver?.resolveRequest ?? null;
215
- const foundRelativePrefix = found.slice(1) + path5.sep;
216
- const resolveRequest = (context, moduleName, platform) => {
217
- if (moduleName.startsWith("./") && moduleName.slice(2).startsWith(foundRelativePrefix)) {
218
- const absolutePath = path5.sep + moduleName.slice(2);
219
- const extsToTry = ["", ".js", ".ts", ".tsx", ".jsx", ".json"];
220
- for (const ext of extsToTry) {
221
- const candidate = absolutePath + ext;
222
- if (fs2.existsSync(candidate)) {
223
- return { filePath: candidate, type: "sourceFile" };
224
- }
225
- }
226
- }
227
- if (upstream) return upstream(context, moduleName, platform);
228
- return context.resolveRequest(context, moduleName, platform);
229
- };
230
201
  return {
231
202
  ...config,
232
- watchFolders: [...existingWatchFolders, found],
203
+ watchFolders: [...config.watchFolders ?? [], ...foldersToAdd],
233
204
  resolver: {
234
205
  ...config.resolver,
235
- nodeModulesPaths: [...existingNodeModulesPaths, found],
236
- resolveRequest
206
+ nodeModulesPaths: [...config.resolver?.nodeModulesPaths ?? [], ...foldersToAdd]
237
207
  }
238
208
  };
239
209
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "miaoda-expo-devkit",
3
- "version": "0.1.1-beta.6",
3
+ "version": "0.1.1-beta.8",
4
4
  "description": "Expo 应用开发工具集:Sentry DSN 替换 stub、错误/网络捕获、Metro 符号化",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.js",