我正在使用ViteSse模板构建Vue.js3项目,我想在安装组件之外使用我的一个名为notificationStore的Pinia存储,但在运行dev命令时收到getActivePinia was called with no active Pinia. Did you forget to install pinia
错误。它的行为非常奇怪,因为它如果我在加载开发服务器后添加useNotificationStore,则不会发生错误,它运行良好,但当useNotificationStore存在于我的ts文件中并运行开发命令时,它会引发错误错误。
下面是我设置:
main.ts
import { ViteSSG } from 'vite-ssg'
import { setupLayouts } from 'virtual:generated-layouts'
import { useAuth, useOidcStore } from 'vue3-oidc'
import type { UserModule } from './types'
import App from './app.vue'
import generatedRoutes from '~pages'
import './assets/styles/style.scss'
import '@/config/oidc'
const routes = setupLayouts(generatedRoutes)
const { autoAuthenticate } = useAuth()
const { state } = useOidcStore()
const isMocking = import.meta.env.VITE_API_MOCKING_ENABLED
if (isMocking === 'true') {
const browser = await import('~/mocks/browser') as any
browser.worker.start({ onUnhandledRequest: 'bypass' })
}
export const createApp = ViteSSG(
App,
{ routes, base: import.meta.env.BASE_URL },
async (ctx) => {
Object.values(import.meta.glob<{ install: UserModule }>('./modules/*.ts', { eager: true }))
.forEach(i => {
i.install?.(ctx)
})
const DEFAULT_TITLE = 'Dashboard'
ctx.router.beforeEach((to) => {
if (!state.value.user) {
autoAuthenticate()
}
let title = DEFAULT_TITLE
if (to.meta.title)
title = `${to.meta.title} - ${title}`
document.title = title
})
},
)
notification.store.ts
import { acceptHMRUpdate, defineStore } from 'pinia'
interface NotificationState {
messages: Array<Notification>
}
export interface Notification {
type?: 'error' | 'info' | 'success' | 'warning'
timeout?: number
permanent?: boolean
message: string
hideAfterRouting?: boolean
validationErrors?: Array<string>
shown?: boolean
}
export const useNotificationsStore = defineStore('notification', {
state: (): NotificationState => ({
messages: [],
}),
actions: {
addNotification(message: Notification) {
if (isDuplicatedMessage(this.messages, message))
return
message.timeout = message.timeout || 3000
message.shown = true
this.messages.push(message)
},
remove(index: number) {
this.messages.splice(index, 1)
},
clearAfterRoute() {
const visibleNotification = this.messages.filter(
item => item.hideAfterRouting === false,
)
this.messages = visibleNotification
},
},
})
function isDuplicatedMessage(messages: Notification[], message: Notification): boolean {
if (!messages.length)
return false
return (messages[messages.length - 1].message === message.message)
}
if (import.meta.hot)
import.meta.hot.accept(acceptHMRUpdate(useNotificationsStore, import.meta.hot))
http-client.ts
import type { AxiosInstance, AxiosRequestConfig } from 'axios'
import axios from 'axios'
import tokenService from './token.service'
import { useNotificationsStore } from '~/store/notification.store'
const notification = useNotificationsStore()
const httpClient: AxiosInstance
= axios.create({
baseURL: `${import.meta.env.VITE_APP_API_URL}/`,
headers: {
'Content-Type': 'application/json',
},
})
httpClient.interceptors.request.use(
(config: AxiosRequestConfig) => {
const token = tokenService.getLocalAccessToken()
if (token && config.headers)
config.headers.Authorization = `Bearer ${token}`
return config
},
(error) => {
return Promise.reject(error)
},
)
httpClient.interceptors.response.use(
(response) => {
if (response.config.method !== 'get') {
const successMsg = 'operation successfully completed'
notification.addNotification({ type: 'success', message: successMsg })
}
return response
},
(error) => {
if (error.message === 'Network Error') {
notification.addNotification({ type: 'error', message: 'Network Error' })
return Promise.reject(error)
}
let errorMessage = ''
const validationErrors = getValidationErrors(error)
errorMessage = getErrorMessage(error)
notification.addNotification({ type: 'error', message: errorMessage, validationErrors, hideAfterRouting: false })
}
)
Vite.config.ts
// Plugins
// Utilities
import path from 'path'
import { URL, fileURLToPath } from 'node:url'
import { defineConfig } from 'vite'
import vuetify from 'vite-plugin-vuetify'
import Vue from '@vitejs/plugin-vue'
import Pages from 'vite-plugin-pages'
import Layouts from 'vite-plugin-vue-layouts'
import Components from 'unplugin-vue-components/vite'
import AutoImport from 'unplugin-auto-import/vite'
import { VitePWA } from 'vite-plugin-pwa'
import VueI18n from '@intlify/vite-plugin-vue-i18n'
import Inspect from 'vite-plugin-inspect'
// https://vitejs.dev/config/
export default defineConfig({
server: {
port: 9080,
host: true,
hmr: {
host: 'localhost',
},
},
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
'~': fileURLToPath(new URL('./src', import.meta.url)),
},
extensions: [
'.js',
'.json',
'.jsx',
'.mjs',
'.ts',
'.tsx',
'.vue',
],
},
plugins: [
Vue({
include: [/\.vue$/],
reactivityTransform: true,
}),
vuetify({
autoImport: true,
}),
// https://github.com/hannoeru/vite-plugin-pages
Pages({
extensions: ['vue'],
dirs: [
{ dir: 'src/router/views', baseRoute: '' },
],
extendRoute: (route) => {
if (route.path === '/')
return { ...route, redirect: '/Dashboard' }
return route
},
}),
// https://github.com/JohnCampionJr/vite-plugin-vue-layouts
Layouts({
layoutsDirs: ['src/router/layouts'],
}),
// https://github.com/antfu/unplugin-auto-import
AutoImport({
imports: [
'vue',
'vue-router',
'vue-i18n',
'vue/macros',
'@vueuse/head',
'@vueuse/core',
],
dts: 'src/auto-imports.d.ts',
dirs: [
'src/composable',
'src/store',
],
vueTemplate: true,
}),
// https://github.com/antfu/unplugin-vue-components
Components({
extensions: ['vue'],
include: [/\.vue$/, /\.vue\?vue/],
dts: 'src/components.d.ts',
deep: true,
}),
// https://github.com/intlify/bundle-tools/tree/main/packages/vite-plugin-vue-i18n
VueI18n({
runtimeOnly: true,
compositionOnly: true,
include: [path.resolve(__dirname, 'locales/**')],
}),
// https://github.com/antfu/vite-plugin-inspect
// Visit http://localhost:3333/__inspect/ to see the inspector
Inspect(),
],
// https://github.com/vitest-dev/vitest
// test: {
// include: ['test/**/*.test.ts'],
// environment: 'jsdom',
// deps: {
// inline: ['@vue', '@vueuse', 'vue-demi'],
// },
// },
// https://github.com/antfu/vite-ssg
ssgOptions: {
script: 'sync',
formatting: 'minify',
// onFinished() { generateSitemap() },
},
ssr: {
// TODO: workaround until they support native ESM
noExternal: ['workbox-window', /vue-i18n/],
},
define: { 'process.env': {} },
})
我已经跟踪了一些日志记录的问题,发现它发生在createApp开始执行之前,初始化pinia,并且当时没有活动的pinia。我预计main.ts中的createApp已经在所有之前执行
先谢了
2条答案
按热度按时间j13ufse21#
这发生因为你还没有注册pinia与这应用程序
请删除顶层的useOidcStore()
lmyy7pcs2#
我通过仔细阅读文档设法解决了这个问题:
确保这一点始终适用的最简单方法是延迟调用useStore(),方法是将它们放在安装pinia后始终运行的函数中。
我只是通过从文件顶部删除useNotificationStore()来更新http-client,在需要notificaitonStore示例的地方使用useNotificationStore().addNotification(...)