antfu / vue-starport

🛰 Shared component across routes with animations
https://vue-starport.netlify.app/
MIT License
1.87k stars 96 forks source link

Auto import of Starport and StarportCarrier with Vitesse #36

Closed Youdaman closed 2 years ago

Youdaman commented 2 years ago

Hi,

I can get Starport to work with Vitesse if I do a manual import of Startport in each page and StarportCarrier in App.vue, however I'd like to use the unplugin-auto-import way, and I tried adding the following to AutoImport in vite.config.ts like so:

{
          'vue-starport': [
            'Starport',
            'StarportCarrier',
          ],
        },

But that didn't seem to work, so I tried the global way in main.ts like so:

import StarportPlugin from 'vue-starport'
app.use(StarportPlugin({ keepAlive: true }))

But again that didn't work.

And I noticed that in the Starport playground demo it just has the following in main.ts:

import Starport from 'vue-starport'
...
app.use(Starport({ keepAlive: true }))

And I tried this using this in ViteSSG like so:

import StarportPlugin from 'vue-starport'
...
(ctx) => {
    ctx.app.use(StarportPlugin({ keepAlive: true }))
...

But that also didn't seem to work.

Am I missing a step with the auto import configuration somewhere? I wold rather auto import than manually do so in each page/App.

antfu commented 2 years ago

With the app.use plugin, they we will be available globally. THere is no need to auto import.

Youdaman commented 2 years ago

Added StarportPlugin like so:

import { ViteSSG } from 'vite-ssg'
import { setupLayouts } from 'virtual:generated-layouts'
import StarportPlugin from 'vue-starport'
import App from './App.vue'
import generatedRoutes from '~pages'

import '@unocss/reset/tailwind.css'
import './styles/main.css'
import 'uno.css'

const routes = setupLayouts(generatedRoutes)

// https://github.com/antfu/vite-ssg
export const createApp = ViteSSG(
  App,
  { routes, base: import.meta.env.BASE_URL },
  (ctx) => {
    ctx.app.use(StarportPlugin({ keepAlive: true }))
    // install all modules under `modules/`
    Object.values(import.meta.globEager('./modules/*.ts')).forEach(i => i.install?.(ctx))
  },
)

And got the following error in the console:

Uncaught (in promise) Error: [Vue Starport] Failed to find <StarportCarrier>, have you initalized it?
    at setup (index.mjs:428:13)
    at callWithErrorHandling (runtime-core.esm-bundler.js:155:22)
    at setupStatefulComponent (runtime-core.esm-bundler.js:7109:29)
    at setupComponent (runtime-core.esm-bundler.js:7064:11)
    at mountComponent (runtime-core.esm-bundler.js:4951:13)
    at processComponent (runtime-core.esm-bundler.js:4926:17)
    at patch (runtime-core.esm-bundler.js:4518:21)
    at mountChildren (runtime-core.esm-bundler.js:4714:13)
    at mountElement (runtime-core.esm-bundler.js:4623:17)
    at processElement (runtime-core.esm-bundler.js:4595:13)
Youdaman commented 2 years ago

I found that I can add StarportCarrier to App.vue without any error:

<template>
  <RouterView />
  <StarportCarrier />
</template>

But as soon as I add Starport to a page like index.vue the above error occurs, so as it suggests, the Starport cannot find its Carrier:

<template>
  <div>
    <Starport port="test" bg-sky w-20 h-20>
      Hello
    </Starport>
    ...
Youdaman commented 2 years ago

If I comment-out the Starport component and refresh my browser there is no error, and I can then uncomment Starport and it appears on the page -- but if I refresh again I get the above error.

So the Vite HMU seems to be setting up StarportCarrier so Starport finds it, but then a refresh somehow loses it or at least it's not being loaded before the Starport needs it?

Youdaman commented 2 years ago

I found that if I just remove the StarportPlugin from main.ts and instead update the AutoImport section of my vite.config.ts to be:

    AutoImport({
      imports: [
        'vue',
        'vue-router',
        'vue-i18n',
        'vue/macros',
        '@vueuse/head',
        '@vueuse/core',
        {
          'vue-starport': [
            'Starport',
            'StarportCarrier',
          ],
        },
      ],
      dts: 'src/auto-imports.d.ts',
    }),

Things work and there is no error.

So I'm wondering whether there is an issue with StarportPlugin? Perhaps specific to using it with ViteSSG? i.e. the StarportCarrier is not being setup before the Starport tries to find it?

tangdaoyuan commented 2 years ago

helper for reproduction

I am also confused why Starport setup always run before StarportCarrier when I work with vite-ssg

tangdaoyuan commented 2 years ago

helper for reproduction

I am also confused why Starport setup always run before StarportCarrier when I work with vite-ssg

It turns out that this bug due to vite-ssg client waiting on router ready

  const { app, router } = await createApp(true)
   // wait until page component is fetched before mounting
  await router.isReady().  // <-- this line
  app.mount(rootContainer, true)

Vue-router official docs points out about router.isReady

Returns a Promise that resolves when the router has completed the initial navigation, which means it has resolved all async enter hooks and async components that are associated with the initial route. .....

This causes the following code to always execute sequentially (createVNode sequentially),

<RouterView v-slot="{ Component }">
   <transition name="page-fade">
     <component
        :is="Component"
        absolute left-0 right-0 top-25
      />
  </transition>
</RouterView>
<StarportCarrier />

eventually lead to error.

the easiest way to temporary fix @Youdaman :

<StarportCarrier /> <!-- keep location before RouterView -->
<RouterView>
<!-- other component -->
</RouterView>

ps: we can also validate by skipping router.isReady in vite-ssg

Youdaman commented 2 years ago

Thanks @tangdaoyuan, your explanation makes sense.

That said, I've since encountered an issue where the markup on the site still says <starportcarrier></starportcarrier> instead of being translated into a div, i.e. the component is not actually loading properly, however there are no errors.

So as a test I added import StarportCarrier from 'vue-starport' (and likewise for Starport in the pages) and now I get no component rendering at all. It completely disappears from the final markup that's generated.

I think I will explore using Nuxt or something other than Vitesse for now until this issue is resolved as I really want to use Starport but not if there's conflicts with other modules that are still works in progress that prevent it working.

Thank you for also investigating this problem, it makes me feel like I'm not going crazy! :)