Closed xiangnanscu closed 5 months ago
Do you have a reproduction without the vite-plugin-oss and ant?
@posva click here, click Test and modify src/views/Test.vue
's template.
The link seems private
@posva sorry, plz refer this https://github.com/xiangnanscu/v
When using sync
mode there seems to be (I think) a circular dependency somewhere creating the error you see when also using useRoute()
with auto import (from vue-router/auto
). Similar to issues reported at https://github.com/vitejs/vite/issues/3033
Using async
(the default) doesn't show this problem. Note that in your repro you are also importing the routes and calling vue-router createRouter()
but you should do this instead (as shown in docs):
import { createRouter, createWebHashHistory } from 'vue-router/auto'
const router = createRouter({
history: createWebHashHistory(import.meta.env.BASE_URL),
extendRoutes(routes) {
return routes
}
})
export default router
Unfortunately, this doesn't fix the problem. I recommend you to use async
mode in the meantime or to toggle it for dev builds with importMode: process.env.NODE_ENV === 'production' ? 'sync' : 'async'
or similar.
Contribution welcome!
@posva Any possibility we could fix this soon? Since 0.8 this has become a bigger problem for us since we are now forced to import from 'vue-router/auto' to get typing on useRoute. This forces us to use 'async' in development, leading to inconsistent application behavior between dev and production.
I'd be happy to make another PR, but I need to know which path to take.
Here are some different ways to solve it:
@xenolithviktor I need to investigate more. For the moment, I recommend you to use any of the versions with pnpm patch or patch-package.
I will focus on fixing this and #5 at some point, but I need to focus on other features and bugs now.
@posva I understand. When you do get the time, I'll be happy to assist in any way I can.
Previously, the typed-routes.d.ts would declare typings for the 'vue-router' module which made it possible to import from there as a workaround. Would it be possible to get that back somehow with an extra d.ts file? If so, what would we put in it? I tried copying the declaration from a previous version of unplugin-vue-router but it does not seem to work..
Patching should be a last resort 😅
@posva Any updates regarding this? @xenolithviktor has put forward he is happy to help with a solution and just need your blessing on which way to move forward with a PR.
You don't need my blessing in any way 😅 This is open source, feel free to work on it and submit a PR. I'm busy with other matters that affect more users, so using async mode or a local patch is the preferred way until a proper fix is found
Here is a little workaround that patches the routes array to be a function using a Vite-plugin. (Add to vite config plugins)
{
// Hacky workaround until HMR in sync mode is fixed, see: https://github.com/posva/unplugin-vue-router/issues/132
name: 'unplugin-vue-router-hmr-workaround',
apply: 'serve',
transform(code, id) {
if (id === 'virtual:vue-router/auto') {
return {
code: code.replace('extendRoutes(routes) : routes', 'extendRoutes(routes()) : routes()')
}
}
if (id === 'virtual:vue-router/auto-routes') {
return {
code: code.replace('export const routes = [', 'export const routes = () => [')
}
}
}
}
This only runs on serve and makes HMR happy by using a function instead of defining the routes array directly in the module, which removes the cyclic dependency error in Vite.
Note that this will only work when using createRouter from vue-router/auto, and not if importing the routes directly from vue-router/auto-routes.
In the future, in my opinion, it would probably be best to remove the custom createRouter (and the import of vue-router/auto-routes) from vue-router/auto completely, and instead have the users import the routes manually when they set up the router. We don't want vue-router/auto-routes to be imported on every page that uses things like useRouter() or useRoute() as this is what introduces the cyclic problem.
@xenolithviktor Rollup's still report CIRCULAR_DEPENDENCY warnings, both with your PR and with your plugin workaround (HMR is working fine for me, it's just production where I'm having issues), so none of them are the real solution to this issue.
I've been investigating further and I'm also onboard that the best solution (albeit it's a minor inconvinient, but just for the first-time setup) is to force users to import the routes manually, like in the layout example in README.
The more I think about this, the more I think routes shouldn't be automatically added. Making the import of routes
explicit would remove the circular dependency issue
Not sure about others, but on 0.9.1 nothing changed about circular imports. @posva Let me know if you want another issue opened for this or "recycling" this one is good
In a quick glance, I think the issue is when a page/component inside a page imports a JS/TS module that imports the global instance of Vue Router:
// router.ts
export const router = createRouter(...)
// external.ts
import { router } from '@/router.ts'
...
// module contents
...
// This module is imported by a Vue Component/Page
You’re creating a cyclic import. Use useRouter
@posva But then how I can use the router outside the Vue application? I understand that, if external.ts
were consumed just by Vue components, it would work right, but that's not the case (it's also imported by other external modules). How we should do it in those situations?
If I do the following:
// @/plugins/router/index.ts
import {
createRouter,
createWebHashHistory,
createWebHistory
} from 'vue-router';
import type { RouteNamedMap, _RouterTyped } from 'unplugin-vue-router/types';
export const router = createRouter({
history: createWebHashHistory(),
routes: [],
}) as _RouterTyped<RouteNamedMap>;
And somewhere else:
// main.ts
import { routes } from 'vue-router/auto-routes';
for (const route of routes) {
router.addRoute(route);
}
There are no issues, but of course this is not ideal given the need for the casting, it's just a workaround.
vite-plugin-pages
does not have the issue either. I believe the only real solution to these kind of circular imports in all use cases is to get rid of the main virtual module (vue-router/auto
) and use vue-router itself.
When you modify template, the hmr doesn't work with error:
ReferenceError: Cannot access '_page_0' before initialization
. you must press F5 to refresh the page.But if you manually import useRoute, this problem doesn't exist
router.ts
vite.config.ts