From c98ddbf33a824b48aacdcd649e3b5b676c0df8c1 Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Tue, 28 May 2024 09:58:07 +0200 Subject: [PATCH] refactor: wip hmr --- playground/src/App.vue | 3 +++ playground/src/main.ts | 13 ++--------- playground/src/router.ts | 18 +++++++++++++++ src/core/context.ts | 8 ++++--- src/core/moduleConstants.ts | 14 ++++++++++++ src/core/vite/index.ts | 44 ++++++++++++++++++++++++++++++++----- src/index.ts | 2 ++ src/options.ts | 1 + 8 files changed, 83 insertions(+), 20 deletions(-) create mode 100644 playground/src/router.ts diff --git a/playground/src/App.vue b/playground/src/App.vue index 5e6990139..97d1f6d0d 100644 --- a/playground/src/App.vue +++ b/playground/src/App.vue @@ -7,6 +7,7 @@ import type { RouteLocation, } from 'vue-router/auto' import { ref } from 'vue' +import { routes } from 'vue-router/auto-routes' function test( a: RouteLocationResolved<'/[name]'>, @@ -19,6 +20,8 @@ if (route.name === '/deep/nesting/works/[[files]]+') { route.params.files } +console.log(`We have ${routes.length} routes.`) + const router = useRouter() router.resolve('/:name') diff --git a/playground/src/main.ts b/playground/src/main.ts index 9c8e2a690..4a19524c3 100644 --- a/playground/src/main.ts +++ b/playground/src/main.ts @@ -1,19 +1,10 @@ import { createApp } from 'vue' import App from './App.vue' -import { - createRouter, - createWebHistory, - DataLoaderPlugin, -} from 'vue-router/auto' -import { routes } from 'vue-router/auto-routes' +import { DataLoaderPlugin } from 'vue-router/auto' import { MutationCache, QueryCache, VueQueryPlugin } from '@tanstack/vue-query' import { createPinia } from 'pinia' import { QueryPlugin } from '@pinia/colada' - -const router = createRouter({ - history: createWebHistory(), - routes, -}) +import { router } from './router' const app = createApp(App) diff --git a/playground/src/router.ts b/playground/src/router.ts new file mode 100644 index 000000000..cc13f0a31 --- /dev/null +++ b/playground/src/router.ts @@ -0,0 +1,18 @@ +import { createRouter, createWebHistory } from 'vue-router/auto' +import { routes } from 'vue-router/auto-routes' + +export const router = createRouter({ + history: createWebHistory(), + routes, +}) + +if (import.meta.hot) { + // How to trigger this? tried virtual: /@id/ + import.meta.hot.accept('vue-router/auto-routes', (mod) => { + console.log('✨ got new routes', mod) + }) + import.meta.hot.accept((mod) => { + console.log('🔁 reloading routes from router...', mod) + console.log(mod!.router.getRoutes()) + }) +} diff --git a/src/core/context.ts b/src/core/context.ts index 53432bbcf..0c6139b85 100644 --- a/src/core/context.ts +++ b/src/core/context.ts @@ -178,6 +178,7 @@ export function createRoutesContext(options: ResolvedOptions) { options, importsMap )}` + // TODO: should we put some HMR code for routes here or should it be at the router creation level (that would be easier to replace the routes) // generate the list of imports let imports = `${importsMap}` @@ -225,9 +226,10 @@ export function createRoutesContext(options: ResolvedOptions) { lastDTS = content // update the files - server?.invalidate(MODULE_ROUTES_PATH) - server?.invalidate(MODULE_VUE_ROUTER) - server?.reload() + server && logger.log(`⚙️ Invalidating server "${MODULE_ROUTES_PATH}"`) + // server?.invalidate(MODULE_ROUTES_PATH) + server?.updateRoutes() + // server?.reload() } } logger.timeEnd('writeConfigFiles') diff --git a/src/core/moduleConstants.ts b/src/core/moduleConstants.ts index 9fa36aca6..f23d75bec 100644 --- a/src/core/moduleConstants.ts +++ b/src/core/moduleConstants.ts @@ -2,6 +2,20 @@ export const MODULE_VUE_ROUTER = 'vue-router/auto' // vue-router/auto/routes was more natural but didn't work well with TS export const MODULE_ROUTES_PATH = `${MODULE_VUE_ROUTER}-routes` +// NOTE: not sure if needed. Used for HMR the virtual routes +let time = Date.now() +/** + * Last time the routes were loaded from MODULE_ROUTES_PATH + */ +export const ROUTES_LAST_LOAD_TIME = { + get value() { + return time + }, + update(when = Date.now()) { + time = when + }, +} + export const VIRTUAL_PREFIX = 'virtual:' // allows removing the route block from the code diff --git a/src/core/vite/index.ts b/src/core/vite/index.ts index 6ece0d43b..84b96f3b0 100644 --- a/src/core/vite/index.ts +++ b/src/core/vite/index.ts @@ -1,6 +1,6 @@ import { type ViteDevServer } from 'vite' import { ServerContext } from '../../options' -import { asVirtualId } from '../moduleConstants' +import { MODULE_ROUTES_PATH, asVirtualId } from '../moduleConstants' export function createViteContext(server: ViteDevServer): ServerContext { function invalidate(path: string) { @@ -13,16 +13,48 @@ export function createViteContext(server: ViteDevServer): ServerContext { } function reload() { - if (server.ws) { - server.ws.send({ - type: 'full-reload', - path: '*', - }) + server.hot.send({ + type: 'full-reload', + path: '*', + }) + } + + // NOTE: still not working + // based on https://github.com/vuejs/vitepress/blob/1188951785fd2a72f9242d46dc55abb1effd212a/src/node/plugins/localSearchPlugin.ts#L90 + // https://github.com/unocss/unocss/blob/f375524d9bca3f2f8b445b322ec0fc3eb124ec3c/packages/vite/src/modes/global/dev.ts#L47-L66 + + async function updateRoutes() { + const modId = asVirtualId(MODULE_ROUTES_PATH) + server.moduleGraph.onFileChange(modId) + const mod = server.moduleGraph.getModuleById(modId) + if (!mod) { + return } + // server.moduleGraph.invalidateModule(mod) + // await new Promise((r) => setTimeout(r, 10)) + // console.log( + // `${mod.url}\n${modId}\n`, + // mod.lastInvalidationTimestamp, + // ROUTES_LAST_LOAD_TIME.value + // ) + server.hot.send({ + type: 'update', + updates: [ + { + acceptedPath: mod.url, + path: mod.url, + // NOTE: this was in the + // timestamp: ROUTES_LAST_LOAD_TIME.value, + timestamp: Date.now(), + type: 'js-update', + }, + ], + }) } return { invalidate, + updateRoutes, reload, } } diff --git a/src/index.ts b/src/index.ts index c768ba546..4f38bf608 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,6 +7,7 @@ import { asVirtualId as _asVirtualId, routeBlockQueryRE, ROUTE_BLOCK_ID, + ROUTES_LAST_LOAD_TIME, } from './core/moduleConstants' // TODO: export standalone createRoutesContext that resolves partial options import { @@ -123,6 +124,7 @@ export default createUnplugin((opt = {}, _meta) => { // vue-router/auto-routes if (resolvedId === MODULE_ROUTES_PATH) { + ROUTES_LAST_LOAD_TIME.update() return ctx.generateRoutes() } diff --git a/src/options.ts b/src/options.ts index 36982af90..942891266 100644 --- a/src/options.ts +++ b/src/options.ts @@ -231,6 +231,7 @@ export const DEFAULT_OPTIONS = { export interface ServerContext { invalidate: (module: string) => void + updateRoutes: () => void reload: () => void }