Бессерверный стек: Максимальный размер стека вызовов превышен только в Windows во время запуска npm

#javascript #node.js #npm #serverless-stack

Вопрос:

Я начал руководство по бессерверному стеку и довольно скоро наткнулся на стену в Windows 10 (те же шаги не вызывают никаких проблем в Mac или Linux).

Я создал простой проект стека без сервера и выполнил: запуск npm

Я получил это:

Ошибка диапазона: Превышен максимальный размер стека вызовов в Object.resolve (путь.js:153:10) в getManager (D:Sourcesdemo-notes-appnode_modules@serverless-stackcoredistpackagerpackager.js:48:38) в getManager (D:Sourcesdemo-notes-appnode_modules@serverless-stackcoredistpackagerpackager.js:48:12) в getManager (D:Sourcesdemo-notes-appnode_modules@serverless-stackcoredistpackagerpackager.js:48:12) в getManager (D:Sourcesdemo-notes-appnode_modules@serverless-stackcoredistpackagerpackager.js:48:12) в getManager (D:Sourcesdemo-notes-appnode_modules@serverless-stackcoredistpackagerpackager.js:48:12) в getManager (D:Sourcesdemo-notes-appnode_modules@serverless-stackcoredistpackagerpackager.js:48:12) в getManager (D:Sourcesdemo-notes-appnode_modules@serverless-stackcoredistpackagerpackager.js:48:12) в getManager (D:Sourcesdemo-notes-appnode_modules@serverless-stackcoredistpackagerpackager.js:48:12) в getManager (D:Sourcesdemo-notes-appnode_modules@serverless-stackcoredistpackagerpackager.js:48:12)

Версия узла-v14.17.5, npm-7.21.1

Поскольку я едва создал экземпляр проекта и он работает на других платформах, я действительно не понимаю, как устранить эту проблему.

Спасибо

Ответ №1:

Ну, обычно вы начинаете с изучения кода/файлов в стеке вызовов и смотрите, даст ли это вам какие-либо подсказки. Это видно из того немногого, что мы можем там видеть, что getManager() снова и снова называет себя. Просто догадываюсь, но, возможно, это ошибка конфигурации или какой-то другой путь ошибки, который заставляет его это делать.

Если вы пойдете, посмотрите на serverless-stack/core/dist/packager/packager.js на github вы видите эту функцию:

 export function getManager(dir: string): Manager {
  const lock = path.join(dir, "yarn.lock");
  if (fs.existsSync(lock)) return Yarn;
  if (dir === "/") return NPM;
  return getManager(path.resolve(dir, ".."));
}
 

Итак, похоже, что это попытка найти yarn.lock файл. Если таковой будет найден, return Yarn . Если мы уже находимся на пути высшего уровня / , то return NPM . В противном случае вызовите себя рекурсивно, но поднимитесь на один уровень в иерархии каталогов и начните все сначала. Итак, если бы код действительно работал таким образом, он должен dir === "/" был бы находиться на верхнем уровне в *nix, за исключением того, что это может быть не так в Windows по двум возможным причинам:

  1. В Windows может быть буква диска в начале пути.
  2. Windows использует «» в качестве разделителя пути, а не «/».

Один из способов сузить это — временно ввести некоторые записи в эту getManager() функцию, чтобы увидеть, что она передается (просто временно отредактируйте версию в своем каталоге dist-убедитесь, что вы редактируете скомпилированную/транспилированную версию, а не версию машинописного текста, если вы не собираетесь создавать ее снова).

 export function getManager(dir: string): Manager {
  console.log("getManager()", dir);            // <== add this
  const lock = path.join(dir, "yarn.lock");
  if (fs.existsSync(lock)) return Yarn;
  if (dir === "/") return NPM;
  return getManager(path.resolve(dir, ".."));
}
 

Просмотр того, что передается здесь, покажет, какая из двух вышеперечисленных проблем может быть причиной проблемы. Судя по коду, его, вероятно, можно заставить работать, просто убедившись, что вы передаете ему путь только с косыми чертами, но это нужно будет проверить, чтобы убедиться, что другой код, задействованный здесь, с этим согласен.

К вашему сведению, этот код можно было бы сделать более терпимым к миру Windows, изменив код на этот:

 // regex that matches / or  or d:/ or d:
const topPath = /^(/|\|[a-z]:[/\]|)$/i;

export function getManager(dir: string): Manager {
  console.log("getManager()", dir);
  const lock = path.join(dir, "yarn.lock");
  if (fs.existsSync(lock)) return Yarn;
  if (topPath.test(dir)) return NPM;
  return getManager(path.resolve(dir, ".."));
}
 

Обратите внимание, что это не было закодировано для обработки UNC-путей в окнах, которые начинаются с»\», но, безусловно, его можно было бы адаптировать и для этого.


Если подумать об этом немного подробнее, вот более простой способ избежать бесконечного цикла, когда вы доберетесь до вершины. Если попытка подняться вверх .. не меняет пути, значит, вы на вершине:

 export function getManager(dir: string): Manager {
  const lock = path.join(dir, "yarn.lock");
  if (fs.existsSync(lock)) return Yarn;
  let upDir = path.resolve(dir, "..");
  // if we didn't actually go up any more, then we're at the top
  if (upDir === dir) {
      return NPM;
  }
  return getManager(upDir);
}
 

Комментарии:

1. спасибо @jfriend00! В этом был весь фокус. Более того, я отправил PR с аналогичным изменением, чтобы избежать этой головной боли кому-то другому github.com/serverless-stack/serverless-stack/pull/770

2. @ff8mania — Я думаю, что последнее решение (которое я добавил) лучше, чем решение для регулярных выражений, поскольку оно полностью кросс-платформенное и обрабатывает такие случаи, как пути UNC в Windows, которых нет в регулярном выражении.

3. Да @jfriend00 хорошая мысль. Я соответствующим образом обновил PR. Большое спасибо!

4. Это было исправлено в версии 0.40.6!