smastrom / notivue

🔔 Powerful toast notification system for Vue and Nuxt.
https://notivue.smastrom.io
MIT License
633 stars 7 forks source link

Uncaught ReferenceError: Cannot access 'router' before initialization #35

Closed Einzieg closed 6 months ago

Einzieg commented 6 months ago

package.json

{
  "name": "view",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vue-tsc && vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "axios": "^1.6.2",
    "material-icons": "^1.13.12",
    "notivue": "^1.4.5",
    "pinia": "^2.1.7",
    "pinia-plugin-persistedstate": "^3.2.0",
    "vue": "^3.3.8",
    "vue-router": "^4.2.5"
  },
  "devDependencies": {
    "@types/node": "^20.10.4",
    "@vitejs/plugin-vue": "^4.5.0",
    "eslint": "^8.55.0",
    "eslint-plugin-vue": "^9.19.2",
    "less": "^4.2.0",
    "sass": "^1.69.5",
    "sass-loader": "^13.3.2",
    "typescript": "^5.2.2",
    "unplugin-auto-import": "^0.17.2",
    "vite": "^5.0.0",
    "vite-plugin-vue-devtools": "^1.0.0-rc.8",
    "vue-tsc": "^1.8.22"
  }
}

main.ts:

import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import { createNotivue } from "notivue";
import { createPinia } from "pinia";
import piniaPluginPersistedstate from "pinia-plugin-persistedstate";

import "./assets/fonts/font.css";
import "notivue/notifications.css"; 
import "notivue/animations.css"; 

const pinia = createPinia();
pinia.use(piniaPluginPersistedstate);

const app = createApp(App);
app.use(router).use(pinia);
export const push = createNotivue(app); 
app.mount("#app");

App.vue:

<script setup lang="ts">
</script>
<template>
    <router-view />
    <Notivue v-slot="item">
        <Notifications :item="item" />
    </Notivue>
</template>

<style></style>

Home,vue:

<template>
    <div class="home">
        <h1>Welcome to the Home page</h1>
    </div>

    <div class="test">
        <button @click="tst">测试</button>
    </div>
</template>

<script lang="ts" setup>
import { useRouter } from "vue-router";
import { push } from "../main";
const router = useRouter();
const test = () => {
    push.success({
        title: "成功",
        message: "这是一条成功的提示消息",
    })
};
</script>

<style scoped></style>

image image

smastrom commented 6 months ago

Hi @Einzieg, I don't think this has nothing to do with Notivue as you can see from the debugger.

I guess the problem is that you are missing the following import in App.vue:

import { Notivue, Notifications } from 'notivue'

Check out this working example on Stackblitz using your setup.

Einzieg commented 6 months ago

你好@Einzieg,我不认为这与 Notivue 无关,正如您从调试器中看到的那样。

我猜问题是您在 App.vue 中缺少以下导入:

import { Notivue, Notifications } from 'notivue'

使用您的设置在 Stackblitz 上查看此工作示例。

Yes,you are right.I know it's stupid, but it bothered me for a long time,Thk.

Einzieg commented 6 months ago

Hi @Einzieg, I don't think this has nothing to do with Notivue as you can see from the debugger.

I guess the problem is that you are missing the following import in App.vue:

import { Notivue, Notifications } from 'notivue'

Check out this working example on Stackblitz using your setup.

This does work, but this issue still occurs when VITE is hot-updated.I can only restart the project after each modification.😂

smastrom commented 6 months ago

Hi @Einzieg, without a reproduction it's impossible for me to understand what's the cause of your issue or if it has to do with Notivue.

As far as I can tell from the error you're getting, you're trying to access the router instance from some place in your app where your router is not available, I don't think this has nothing to do with Notivue.

Einzieg commented 6 months ago

Hi @Einzieg, without a reproduction it's impossible for me to understand what's the cause of your issue or if it has to do with Notivue.

As far as I can tell from the error you're getting, you're trying to access the router instance from some place in your app where your router is not available, I don't think this has nothing to do with Notivue.

I'm sure there's no problem with the router because the project works fine when I remove. I've created a new repositoryNotivue

smastrom commented 6 months ago

I have investigated a bit and this seems to be an issue with Vite HMR happening only in development mode. More context at this issue.

I've run your codebase with a different dev server (Rspack) and also tried to build and preview the production build with Vite and the error doesn't occur.

The error persists as long as a variable of any value is exported from main and imported in your routes.

Not sure on what to do here honestly other than keeping this issue open and suggest two workarounds I've found so far:

Workaround 1 Use usePush. Please note that this can only called inside the setup function of a Vue component or wherever the app context is accessible (plugins, route guards, pinia setup stores, etc).

<script setup>
import { usePush } from 'notivue'

const push = usePush()

push.sucess('Hello!')
</script>

Workaround 2 If you prefer to keep using push imported from main.ts, add this plugin to vite.config.ts which will make that error disapper (thanks @SuspiciousLookingOwl).

export default defineConfig({
   plugins: [
      // ...
      {
         name: 'SingleHMR',
         handleHotUpdate({ modules }) {
            modules.map((m) => {
               m.importers = new Set()
            })

            return modules
         },
      },
   ],
})
Einzieg commented 6 months ago

Okay, thank you!

我进行了一些调查,这似乎是 Vite HMR 仅在开发模式下发生的问题。有关此问题的更多背景信息。

我已经使用不同的开发服务器(Rspack)运行了您的代码库,并且还尝试使用 Vite 构建和预览生产版本,并且没有发生错误。

只要从 main 导出任何值的变量并将其导入到路由中,该错误就会持续存在。

老实说,除了保持这个问题开放并建议我到目前为止发现的两种解决方法之外,不知道该怎么做:

解决方法 1 使用usePush。请注意,这只能在 Vue 组件的设置函数内部或可访问应用程序上下文的任何地方(插件、路由防护、pinia 设置存储等)调用。

<script setup>
import { usePush } from 'notivue'

const push = usePush()

push.sucess('Hello!')
</script>

解决方法 2 如果您希望继续使用从 导入的 push,请将此插件添加到 这将使该错误消失(感谢 main.ts``vite.config.ts@SuspiciousLookingOwl)。

export default defineConfig({
   plugins: [
      // ...
      {
         name: 'SingleHMR',
         handleHotUpdate({ modules }) {
            modules.map((m) => {
               m.importers = new Set()
            })

            return modules
         },
      },
   ],
})

Okay, thank you!