vuejs3vue-componentvue-routerpinia

[Vue warn]: Failed to resolve component: UserBasket


I ran into an issue that had me scratch my head for a few days now. I am doing a application with vuejs3 frontend.

For all the code I provide I removed the most other code and kept what I think is relevant to make it more readable. If you need more information let me know and I update the question with it.

My main js:

import { createApp } from 'vue';
import App from './App.vue';
import router from './router.js';

const app = createApp(App);
app.use(router);
app.mount('#app');

This is my App.vue:

<template>
  <div>
    <!-- if I put <Userbasket /> here it works -->
    <div>
      <router-view v-slot="{ Component }">
        <Transition mode="out-in">
          <component :is="Component"/>
        </Transition>
      </router-view>
    </div>
  </div>
</template>
<script>

export default {
  name: 'App',
}
</script>

Relevant vue router:

import { createRouter, createWebHistory } from 'vue-router';
import HomeView from "@/views/Home.vue";

const routes = [
  {
    name: 'home',
    path: '/home',
    component: HomeView,
  },
  {
    name: 'root',
    path: '/',
    redirect: '/home',
  },
];
const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes: routes
});

export default router;

And my Home.vue:

<template>
  <div class="d-flex p-2">
    <div class="row-12 mb-2">
      <WeekSummary />
    </div>
    <div class="row-12 mb-2">
      <!-- here it doesn't work, thrown warning in console -->
      <UserBasket />
      <!-- OtherComp renders correctly -->
      <OtherComp/>
    </div>
  </div>
</template>

<script>
import WeekSummary from '@/components/WeekSummary.vue'
import UserBasket from '@/components/UserBasket.vue';
import OtherComp from '@/components/OtherComp.vue';

export default {
    name: 'HomeView',
    components: {
      WeekSummary,
      UserBasket,
      OtherComp,
    }
};
</script>

And the component I am trying to render UserBasket.vue:

<template>
  <div>
    ... lots of div and span ...
  </div>
</template>

<script>
// no child component
export default {
  name: 'UserBasket',
}
</script>

And my directory structure:

src
|-components
| |-UserBasket.vue
| |-Popup.vue
| |-WeekSummary.vue
| |-OtherComp.vue // and more
|-views
| |-Home.vue
| |-OtherView.vue // and more
|-App.vue
|-main.js
|-router.js

So what I try is to render the UserBasket component, but I getting the error that in the title. Whats weird that I have 20+ components and this is the only one that do not want to get rendered.

The UserBasket component is actually inside the WeekSummary component but I moved it up into HomeView trying to debug this and the error is still appear so kept it there for simplicity. I also tried moving it to the root component in App.vue and there it renders without a problem, so I don't think there is a typo like other SO question answers suggest. I also copied the import statement from the child component where the error appear to the App.vue to make it sure its not a typo.

During development I use npm run serve to run it so it hotreloads if I change a file. When I save the UserBasket.vue file it hotreloads and it actually can import it and render it correctly whitout a warning, so this is also why I think there is no typo. But if I reload the page the component does not render again.

I tried building the app with npm run build and the built version also have this issue.

I also tried putting an other component next to UserBasket and the other renders correctly. The other component is in the same folder with UserBasket and I used the same path declaring method. "@/components/OtherComp.vue" like "@/components/UserBasket.vue" so I dont thin it is a path issue. I also tried the path "./components/UserBasket.vue" and "./UserBasket.vue" in the WeekSummary.vue.

I want to mention that In WeekSummary I have another component "Popup.vue" that is renders correctly and the "Popup.vue" file is next to UserBasket.vue in the components folder

my vue versions are:

    "vue": "^3.4.31",
    "vue-router": "^4.2.5",

And I also tried downgrading down to 3.3.0 the issue is still there.

UserBasket is used 3 places and none of the work. in the loaded site inspecting the HTML DOM in the browser there is the <userbasket></userbasket> tag where is should be.

The console warning is throw from three different lines for each location where I used UserBasket.

Note that at the second and third one I save data into a pinia store object. At this point I don't know what is relevant or not.

My vue.config.js if it matters:

const { defineConfig } = require('@vue/cli-service');
const packageJson = require('./package.json');


module.exports = defineConfig({
  chainWebpack: (config) => {
    // Set environment variables for Webpack
    config.plugin('define').tap((args) => {
      args[0]['process.env'].VUE_APP_VERSION = JSON.stringify(packageJson.version);
      return args;
    })
  },
  configureWebpack: {
    devServer: {
      historyApiFallback: true
    }
  },
  transpileDependencies: true
});

What I tried from other SO related question:

Thank you for reading my question, let me know if you need more information.

Update

In the browser, no other vue warning displayed only an Feature flag one:

Feature flag __VUE_PROD_HYDRATION_MISMATCH_DETAILS__ is not explicitly defined. You are running the esm-bundler build of Vue, which expects these compile-time feature flags to be globally injected via the bundler config in order to get better tree-shaking in the production bundle.

Trying @yoduh's suggestion(Thank you) to remove code to simplify the UserBasket componet, I removed every use of my pinia store from my component(that where the warnings are thrown) saved the file. No warning displayed in the console, and my component rendered fine. So I guess I the pinia state object is breaks somwhere.

To further investigate I tried removing only my basket store entirely from UserBasket and no warning thrown and the component rendered fine. I found out that simply having the import line in the component will break the reference somehow. I tried to remove every line from the whole projcet where I update the basket value but nothing changed.

I also tried commenting out all getter and action method in the store, but it did not change anything.

In WeekSummary I had a vue watch statement defined for my auth store, removed it and it get rid of one of the warnings that was pointed to the auth.js store file. My guess from this is somewhere I try to update the basket store's value but I am not sure. The only warning(this appears 4 times in a row) left is pointing to the app.use(router) line in my main.js. Another thing to note that the pinia default log 🍍 "basket" store installed 🆕 dont get printed printed in the console for any of my stores. With the vue devtools browser extension, I can see my stores are there with valid values.

Commenting out the use of UserBasket inside WeekSummary reduces the warning count from 4 to 1 and the pinia loglines are logged in console. The only use of UserBasket left is in the Home.vue file for debugg purpses for this issue.

I didn't found any issues on pinia's github page regarding this.

My basket.js if it helps:

import { defineStore } from 'pinia'
import { useAuth } from "@/stores/auth";
import { state as vuestate, socket } from "@/socket.js";
// other nonrelated imports...

export const useBasket = defineStore('basket', {
  state: () => ({basket: {}}),
  getters: {
    // my getters...
  },
  actions: {
    // my actions...
  }
})

Update 2

I successfully created a repro on playcode.io: https://playcode.io/1932830

What I want to note is:

Update 3

The main reason that the solution was hard to find that in my local dev environment the ReferenceError was not shown in my console which made it impossible or at least very hard to find similar SO questions. This was a huge hint. The error was displayed on the repro link which let to solving the issue. Hope others find this usefull.


Solution

  • The error comes from socket.js and UserBasket.vue happens to be the one importing it, via store/basket.js.

    The fix, in your case:

    1. Install setimmediate polyfill:
    npm i setimmediate
    
    1. In socket.js:
    import 'setimmediate'
    
    1. In main.js
    import { socket } from './socket'
    
    ...
    export { socket }
    
    1. in basket.js:
    import { socket } from '../main'
    // not from '../socket' !!!
    

    See it working.