@meforma/vue-toaster 清除功能仅在拉入本地项目文件夹时有效,而不是从 node_modules

@meforma/vue-toaster clear function only works when pulled into local project folder, not from node_modules

如前所述,包 @meforma/vue-toasterAPI here.

中有一个 clear() 函数

我的vue和vite项目设置:

main.js

import Toaster from '@meforma/vue-toaster'

app.use(Toaster, {
  position: 'top',
  useDefaultCss: false,
  pauseOnHover: false
}).provide('toast', app.config.globalProperties.$toast)

Example.vue

<template>
  <div class="view">
    <div class="mt-10 flex gap-5">
      <button class="btn btn-stealth" @click="showToast('default')">Default</button>
      <button class="btn btn-primary" @click="showToast('primary')">Primary</button>
      <button class="btn btn-success" @click="showToast('success')">Success</button>
      <button class="btn btn-info" @click="showToast('info')">Info</button>
      <button class="btn btn-warning" @click="showToast('warning')">Warning</button>
      <button class="btn btn-danger" @click="showToast('error')">Error</button>
    </div>

    <div class="mt-10">
      <button class="btn" @click="toast.clear">Clear Toasts</button>
      <br><br>
      <button class="btn" @click="clearToasts">Timeout Clear</button>
    </div>
  </div>
</template>

<script setup>
import { inject } from 'vue'

const toast = inject('toast')

// this works
function showToast (type) {
  toast.show(`This is the ${type} type toast.`, {
    type: type,
    duration: false
  })
}

// only works when vue-toaster is local in my projects src folder :S
function clearToasts () {
  toast.clear()
}
</script>

package.json

{
  "name": "test-project",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "vite --open",
    "build": "vite build --out-dir dist",
    "lint": "eslint src"
  },
  "dependencies": {
    "@meforma/vue-toaster": "^1.3.0",
    "@vitejs/plugin-vue": "^2.2.4",
    "animate.css": "^4.1.1",
    "axios": "^0.26.0",
    "axios-auth-refresh": "^3.2.2",
    "core-js": "^3.21.1",
    "microtip": "^0.2.2",
    "pinia": "^2.0.13",
    "pinia-plugin-persistedstate": "^1.5.1",
    "sass": "^1.49.9",
    "vue": "^3.2.31",
    "vue-meta": "^3.0.0-alpha.10",
    "vue-router": "^4.0.13"
  },
  "devDependencies": {
    "@tailwindcss/aspect-ratio": "^0.4.0",
    "@tailwindcss/forms": "^0.5.0",
    "@tailwindcss/line-clamp": "^0.3.1",
    "@tailwindcss/typography": "^0.5.2",
    "@vue/compiler-sfc": "^3.2.31",
    "@vue/eslint-config-standard": "^6.1.0",
    "autoprefixer": "^10.4.2",
    "eslint": "^8.12.0",
    "eslint-plugin-import": "^2.25.4",
    "eslint-plugin-node": "^11.1.0",
    "eslint-plugin-promise": "^6.0.0",
    "eslint-plugin-standard": "^4.1.0",
    "eslint-plugin-vue": "^8.6.0",
    "postcss": "^8.4.7",
    "tailwindcss": "^3.0.23",
    "vite": "^2.8.6"
  },
  "eslintConfig": {
    "root": true,
    "env": {
      "node": true
    },
    "extends": [
      "plugin:vue/vue3-essential",
      "@vue/standard"
    ],
    "rules": {}
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not dead"
  ]
}

但是,当我将包拉入本地 src 文件夹并通过那里导入时,clear 工作得很好。除了移动代码所在的位置外,没有任何代码更改。

我完全不知道为什么会这样,如果有人见过类似的东西,将不胜感激。

我查看了 project github 的所有代码并在那里创建了一个问题。

我认为这可能与事件总线有关,但话又说回来,当从 node_modules 中拉出时它会起作用,所以为什么这让我头疼。

谢谢!


编辑 1:

更新了代码示例,您可以在本地 运行 遇到同样的问题:https://codesandbox.io/s/vue3-toaster-test-forked-m64htx?file=/src/components/HelloWorld.vue:854-868

特别是在 main.js 中,交换 vue-toaster 从中拉入的位置会导致清除功能 stop/start 工作。当 vue-toaster 位于我的项目 /src 中时清除工作正常,但从 node_modules.

拉入时无法工作

编辑 2:

这是一个显示相同问题的 stackblitz(也使用 vite):https://stackblitz.com/edit/vitejs-vite-uqcdgd?file=src%2Fmain.js,src%2FApp.vue

原回答是误会。所以我根据问题的要点对其进行了编辑。

问题

  • node_modules.
  • 使用时,该软件包不起作用
  • 当人们将它添加到项目中并直接使用它时,该包确实有效

原因

Vite只缓存包中的JS文件。我们可以在node_modules/.vite/deps/@meforma_vue-toaster.js

中看到
// The .vue file is point to original file
// node_modules/@meforma/vue-toaster/src/index.js
import Toaster2 from "/Users/admin/Work/test-projects/vite-demo-vue-plugin/node_modules/@meforma/vue-toaster/src/Toaster.vue";

// node_modules/@meforma/vue-toaster/src/api.js
import Toaster from "/Users/admin/Work/test-projects/vite-demo-vue-plugin/node_modules/@meforma/vue-toaster/src/Toaster.vue";

// The js file is cached here so Singleton pattern will breaks
// node_modules/@meforma/vue-toaster/src/helpers/event-bus.js
var Event = class {
  constructor() {
    this.queue = {};
  }
...
}

event-bus.js 缓存在 .vite 文件夹中,但 Toaster.vue 文件不是。因此,当 Toaster.vue 使用 EventBus 时,它将调用 node_modules/@meforma/vue-toaster/ 中的实例,而不是 .vite 缓存文件夹中的实例。并且打破了原包的单例模式

任何包含不可缓存文件和 JS 文件的包都可能发生此错误。

解决方法

这个bug只能从Vite端修复。所以在 Vite 修复它之前,我们需要从 Vite 缓存中排除包,正如 指出的那样:

// vite.config.js

export default defineConfig({
  optimizeDeps: {
    exclude: [
      "@meforma/vue-toaster"
    ]
  },
  ....

Github issue

所以在 forking @meforma/vue-toaster, rewriting the Toaster in the composition API and changing the event bus to use mitt, even went as far as to publish it to npmjs 之后,我可以复制所有内容,尽可能接近我最初使用包的方式....结果我的 re-written 包有完全相同的问题维特

进一步挖掘,我注意到在我的 /node_modules/ 中有一个文件夹:/node_modules/.vite/deps/,其中包含如下文件:@shanehoban_vue-toaster.js... 所以我开始谷歌搜索,发现也许我应该从 Vite 优化中排除包...像这样:

vite.config.js

export default defineConfig({
  optimizeDeps: {
    exclude: [
      "@meforma/vue-toaster"
    ]
  },
  ....

现在,清除...正在发挥作用。