vue upgrade: ResizeObserver loop completed with undelivered notifications

1,571 阅读3分钟

背景

我在升级Vue2的项目依赖及开发工具从npm切换至pnpm过程中,当重新运行pnpm run serve出现了令人困扰的运行时错误。

问题

Uncaught runtime errors:     ×

ERROR

ResizeObserver loop completed with undelivered notifications. at handleError (webpack-internal:///./node_modules/.pnpm/webpack-dev-server@4.15.2_webpack@5.94.0/node_modules/webpack-dev-server/client/overlay.js:252:58) at eval (webpack-internal:///./node_modules/.pnpm/webpack-dev-server@4.15.2_webpack@5.94.0/node_modules/webpack-dev-server/client/overlay.js:271:7)

截屏2024-09-13 下午2.30.07.png

那么怎么解决呢???

首先我肯定搜索项目代码中是否有存在关键字ResizeObserver,我在源代码里并没有发现哦! 但是我在一个异步远程加载打包的组件产物里找到了(如下图)。

为什么产物里有ResizeObserver和源代码里没有?这里我没有深入去研究,以下是一些可能的原因。

  1. Third-Party Libraries or Dependencies

  2. Webpack Transpilation

  3. Auto-Injected Polyfills

  4. Dynamic Imports and Code Splitting

    Summary: The ResizeObserver might be coming from third-party libraries, Webpack’s polyfill behavior, or dynamically loaded modules. To resolve this, inspect your dependencies, tweak your Babel configuration, and investigate how Webpack is bundling the app.

截屏2024-09-13 下午2.36.55.png

我在解决这个问题的思路历程大致如下:
1. 直接通过搜索引擎譬如Chrome或者百度搜索的解决方案:

我可以搜索到满屏的答案,如下如所示

截屏2024-09-13 下午2.33.21.png

以上方案基本上不约而同的使用了防抖函数(如下图所示)

但是我尝试了没有用哦!

截屏2024-09-13 下午2.52.28.png

2. 通过ChatGPT提供的解决方案:

截屏2024-09-13 下午2.58.04.png

1.它也提供了类似防抖函数debounce的方案,如下面代码所示

但是我刷新错误依然无法解决哦!

// 1. **debounced-observer.js**: Use `requestAnimationFrame` and throttle updates

const debounce = (fn, delay) => {
  let timer = null;
  return function () {
    const context = this;
    const args = arguments;
    clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(context, args);
    }, delay);
  };
};

// Throttle function using requestAnimationFrame
const throttleWithRaf = (fn) => {
  let isRequestPending = false;
  return function () {
    if (isRequestPending) return;
    isRequestPending = true;
    requestAnimationFrame(() => {
      fn.apply(this, arguments);
      isRequestPending = false;
    });
  };
};

// Create a debounced ResizeObserver class with raf-throttled callback
class DebouncedResizeObserver {
  constructor(callback, delay = 16) {
    this.observer = new ResizeObserver(throttleWithRaf(debounce(callback, delay)));
  }

  observe(...args) {
    this.observer.observe(...args);
  }

  unobserve(...args) {
    this.observer.unobserve(...args);
  }

  disconnect() {
    this.observer.disconnect();
  }
}

export default DebouncedResizeObserver;
// 2. **In App.vue**: Use the `DebouncedResizeObserver`
<script>
import DebouncedResizeObserver from '@/utils/debounced-observer';

export default {
  name: 'App',
  mounted() {
    // Create a new debounced observer instance with raf-throttling
    this.resizeObserver = new DebouncedResizeObserver((entries) => {
      entries.forEach(entry => {
        console.log(entry.target.getBoundingClientRect());
      });
    });

    const element = this.$refs.resizableElement;
    if (element) {
      // Observe the element
      this.resizeObserver.observe(element);
    }
  },
  beforeDestroy() {
    // Clean up observer on component destroy
    if (this.resizeObserver) {
      this.resizeObserver.disconnect();
    }
  }
}
</script>

<template>
  <div ref="resizableElement">
    <!-- Your resizable content goes here -->
  </div>
</template>

2.通过Adding an Overlay来配置 vue.config.js,如下面配置

// 这里就差一点点啊,没有给出runtimeErrors的配置,导致error依然无法消失
devServer: {
  client: {
    overlay: {
      warnings: false,
      errors: true,
    },
  },
}

接下来。。。

1.放弃防抖函数:由于以上方案,我尝试了很久,都没能阻止overlayError,随后开启了循环操作模式:尝试卸载依赖——>重新安装依赖——>不断重启项目——>胡乱验证,尽管如此依然没能解决问题,最后决定放弃了防抖函数的方案。

2.进一步跟随ChatGPT的启示:即使ChatGPT提供了很全面的思路参考,甚至代码范例,但它似乎总是和你绕口令似的,最后似乎总是差了那么一点,但是它依然是很好的助手,在前进的道路上指引着向前。

3.基于前期的努力,我想既然Error是来自于webpack-dev-server/client/overlay.js,那么问题是由它抛出来的,是不是可以通过配置或者通过源码找寻答案呢,于是我顺理成章的进入了如下的第三步。

3. 通过Webpack文档的解决方案(webpack-dev-server/overlay)

截屏2024-09-13 下午3.38.04.png

通过在vue.config.js打印console.log(error),如下的三张图所示,审查源码添加的打印日志,在匹配到相应的错误信息时,通过return false成功临时关闭了overlay的报错信息。

截屏2024-09-13 下午2.21.33.png

截屏2024-09-13 下午2.13.28.png

截屏2024-09-13 下午2.14.07.png

答案(配置runtimeErrors,关闭特定的Error

只是一个简单配置的兜兜转转,最终做的是我们很多时候需要回归文档、始终遵循文档,这是一个解决问题的起点。

截屏2024-09-13 下午3.24.07.png

缺陷

这是一个开发环境下出现的Error,通过配置runtimeErrors,临时关闭特定的Error,这是一个很不完美的方案,可能触发此Error的原因来源于Bad代码,这个需要不断验证,需要致力于编写稳健且性能好的代码。

参考

How to Migrate from Vue CLI to Vite - Vue School Articles

vue-cli-to-vite-migration-example

【Bug】ERROR ResizeObserver loop completed with undelivered notifications.-阿里云开发者社区

react-resizeobserver-loop-completed-with-undelivered-notifications

webpack-dev-server/client/overlay