'@meforma/vue-toaster clear function only works when pulled into local project folder, not from node_modules
As stated, the package @meforma/vue-toaster
has a clear()
function in the API here.
My vue and vite project setup:
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"
]
}
But, when I pull the package into the local src
folder and import it via there, the clear works perfectly. No code changes other than moving where the code lives.
I have absolutely no idea why this is the case, if anyone has ever seen anything similar, it would be greatly appreciated.
I looked through all the code of the project github and created an issue there.
I thought it might be something to do with the event bus, but then again, it works when pulled from node_modules
so hence why this is such a head scratcher for me.
Thanks!
Edit 1:
Updated code example that you can run locally to experience the same issue: https://codesandbox.io/s/vue3-toaster-test-forked-m64htx?file=/src/components/HelloWorld.vue:854-868
Specifically in the main.js
, swapping where the vue-toaster
is pulled in from causes the clear function to stop/start working. Clearing works when vue-toaster
is located within my project /src
but fails to work when pulled in from node_modules
.
Edit 2:
Here is a stackblitz showing the same issue (using vite too): https://stackblitz.com/edit/vitejs-vite-uqcdgd?file=src%2Fmain.js,src%2FApp.vue
Solution 1:[1]
So after 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 so I could replicate everything as close as possible to how I use the package originally.... it turns out that my re-written package was having the exact same issue with Vite.
Digging in further, I noticed in my /node_modules/
there was a folder: /node_modules/.vite/deps/
which had files like: @shanehoban_vue-toaster.js
... so I started googling and found out that perhaps I should exclude the package from Vite optimizations... like so:
vite.config.js
export default defineConfig({
optimizeDeps: {
exclude: [
"@meforma/vue-toaster"
]
},
....
And now, the clear... is working.
Solution 2:[2]
The original answer is a misunderstanding. So I edited it to follow the point of the question.
Problem
- The package does NOT work when using it from
node_modules
. - The package does work when folks it into the project and use it directly
Reason
Vite only caches JS files from the package. We can see it in 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 = {};
}
...
}
The event-bus.js is cached in the .vite
folder but the Toaster.vue
file is not. So when the Toaster.vue
uses the EventBus
, it will call the instance from node_modules/@meforma/vue-toaster/
instead of the one in the .vite
cached folder. And it breaks the Singleton pattern of the original package.
This bug might happen to any package with uncachable files mixed with JS files.
Workaround
This bug can be fixed only from the Vite side. So before Vite fixes it we need to exclude the package from the Vite cache as shanehoban's answer points out:
// vite.config.js
export default defineConfig({
optimizeDeps: {
exclude: [
"@meforma/vue-toaster"
]
},
....
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | shanehoban |
Solution 2 |