Что вызывает эту vue -router asyn c ошибка компонента - TypeError: undefined не является объектом (оценивая 't .__ esModule')? - PullRequest
1 голос
/ 14 февраля 2020

Я замечаю много ошибок в Sentry со следующей трассировкой стека:

TypeError: undefined is not an object (evaluating 't.__esModule')
  at isESModule(./node_modules/vue-router/dist/vue-router.esm.js:1955:3)
  at ? (./node_modules/vue-router/dist/vue-router.esm.js:1882:27)
  at promiseReactionJob([native code])

У меня много проблем с воспроизведением самой ошибки и выяснением ее причины. Глядя на источник vue -router, он исходит из этой функции:

  function isESModule (obj) {
    return obj.__esModule || (hasSymbol && obj[Symbol.toStringTag] === 'Module')
  }

Так что obj не определено. Если мы go на один уровень выше, мы получим эту функцию:

  function resolveAsyncComponents (matched) {
    return function (to, from, next) {
      var hasAsync = false;
      var pending = 0;
      var error = null;

      flatMapComponents(matched, function (def, _, match, key) {
        // if it's a function and doesn't have cid attached,
        // assume it's an async component resolve function.
        // we are not using Vue's default async resolving mechanism because
        // we want to halt the navigation until the incoming component has been
        // resolved.
        if (typeof def === 'function' && def.cid === undefined) {
          hasAsync = true;
          pending++;

          var resolve = once(function (resolvedDef) {
            if (isESModule(resolvedDef)) {
              resolvedDef = resolvedDef.default;
            }
            // save resolved on async factory in case it's used elsewhere
            def.resolved = typeof resolvedDef === 'function'
              ? resolvedDef
              : _Vue.extend(resolvedDef);
            match.components[key] = resolvedDef;
            pending--;
            if (pending <= 0) {
              next();
            }
          });

...

Таким образом, похоже, что resolvedDef не определено.

Я предполагаю, что маршрутизатор Vue разрешает асинхронность Компонент c успешно завершен, но в итоге он не определен, и в коде нет ничего, что могло бы объяснить этот случай.

Я использую vue -router 3.1.3, и эти ошибки всегда происходят только на iOS (Safari или Chrome).

Я пытался найти ошибку и не могу найти ни одной ссылки на нее где-либо еще. Я также не могу опубликовать проблему на Github vue, потому что я не могу обеспечить минимальное воспроизведение.

Часто (но не всегда) Sentry также показывает этот журнал консоли, предшествующий ошибка:

console [vue-analytics] An error occured! Please check your connection or disable your AD blocker
logger console
extra {"arguments":["[vue-analytics] An error occured! Please check your connection or disable your AD blocker"]}

Я не уверен, что это связано, хотя.

Одно сумасшедшее решение, о котором я думаю, - это развертывание пропатченной версии vue -router, где он выдает ошибку с более полезным контекстом в случае, когда resolvedDef не определено. Мы надеемся, что эта ошибка окажется в наших журналах Sentry.

Что является причиной этой ошибки?

1 Ответ

2 голосов
/ 18 февраля 2020

Я разветвил библиотеку vue -router и пропатчил resolveAsyncComponents этой строкой:

if (!resolvedDef) {
  window.onerror(`router wtf ${matched.join(',')} ${def} ${_} ${match} ${key} ${pending} ${hasAsync} ${error}`);
}

В итоге в Sentry появилась следующая ошибка:

router wtf [object Object] function(){return u(Promise.all([n.e("dashboard~orders~products~publicUser"),n.e("dashboard~discounts~products~publicUser"),n.e("orders~publicUser~tips"),n.e("publicUser~tips"),n.e("publicUser")]).then(n.bind(null,"89c6")))...

В работе, наше приложение Vue, кажется, загружает эти компоненты с помощью инициатора bootstrap:

asycn component loading

Затем мне показалось, что мы используем следующую оболочку вокруг каждый отдельный асин c импорт компонента в router.js:

      {
        path: 'dashboard',
        name: 'dashboard',
        component: () =>
          handleChunkLoadError(
            import(/* webpackChunkName: 'dashboard' */ '../views/Dashboard')
          ),
      },
function handleChunkLoadError(importPromise) {
  return importPromise.catch(() => {
    Vue.toasted.error('Network error encountered', {
      duration: null,
      action: {
        text: 'Reload',
        onClick: () => window.location.reload(),
      },
    });
  });
}

Предполагается, что в нем должен отображаться тост, который позволяет пользователю обновить sh страницу, если не удалось загрузить чанк.

Но мы забыли передать ошибку на vue -router:

function handleChunkLoadError(importPromise) {
  return importPromise.catch(error => {
    Vue.toasted.error('Network error encountered', {
      duration: null,
      action: {
        text: 'Reload',
        onClick: () => window.location.reload(),
      },
    });

    return error;
  });
}

Возвращение ошибки в обработчике .catch устраняет проблему.

?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...