From 41c20db4b2e292a1105d260c12557011ec3cc635 Mon Sep 17 00:00:00 2001 From: yoho Date: Mon, 13 Jun 2022 00:53:16 +0800 Subject: [PATCH 01/15] chore: update --- test/vite-node/package.json | 13 +++++++++++++ test/vite-node/src/main.ts | 6 ++++++ test/vite-node/src/testMod.ts | 4 ++++ 3 files changed, 23 insertions(+) create mode 100644 test/vite-node/package.json create mode 100644 test/vite-node/src/main.ts create mode 100644 test/vite-node/src/testMod.ts diff --git a/test/vite-node/package.json b/test/vite-node/package.json new file mode 100644 index 000000000000..5db30c71ad17 --- /dev/null +++ b/test/vite-node/package.json @@ -0,0 +1,13 @@ +{ + "name": "vite-node-test", + "private": true, + "main": "index.js", + "license": "MIT", + "type": "module", + "scripts": { + "dev": "vite-node --watch ./src/*" + }, + "devDependencies": { + "vite-node": "workspace:*" + } +} diff --git a/test/vite-node/src/main.ts b/test/vite-node/src/main.ts new file mode 100644 index 000000000000..2bec6ed94a6f --- /dev/null +++ b/test/vite-node/src/main.ts @@ -0,0 +1,6 @@ +/* eslint-disable no-console */ +import { a } from './testMod' + +console.log('[index.js] load!') +console.log('hello world') +console.log(a) diff --git a/test/vite-node/src/testMod.ts b/test/vite-node/src/testMod.ts new file mode 100644 index 000000000000..873f02f6ae3a --- /dev/null +++ b/test/vite-node/src/testMod.ts @@ -0,0 +1,4 @@ +export const a = 'hello testModule' + +// eslint-disable-next-line no-console +console.log('[testModule.js] load!') From 54ef5b8a9d913187d22f1614791c89d9c626d0f4 Mon Sep 17 00:00:00 2001 From: yoho Date: Mon, 20 Jun 2022 22:44:44 +0800 Subject: [PATCH 02/15] feat: vite-node hmr --- packages/vite-node/src/cli.ts | 23 ++- packages/vite-node/src/client.ts | 5 +- packages/vite-node/src/hmr/emitter.ts | 42 ++++++ packages/vite-node/src/hmr/hmr.ts | 169 +++++++++++++++++++++++ packages/vite-node/src/hmr/hotContext.ts | 140 +++++++++++++++++++ packages/vite-node/src/hmr/index.ts | 3 + packages/vite-node/src/types.ts | 8 +- test/vite-node/package.json | 4 +- test/vite-node/src/deps.ts | 9 ++ test/vite-node/src/testMod.ts | 2 + 10 files changed, 389 insertions(+), 16 deletions(-) create mode 100644 packages/vite-node/src/hmr/emitter.ts create mode 100644 packages/vite-node/src/hmr/hmr.ts create mode 100644 packages/vite-node/src/hmr/hotContext.ts create mode 100644 packages/vite-node/src/hmr/index.ts create mode 100644 test/vite-node/src/deps.ts diff --git a/packages/vite-node/src/cli.ts b/packages/vite-node/src/cli.ts index ad3daeb585f8..eb76d5f4f9c8 100644 --- a/packages/vite-node/src/cli.ts +++ b/packages/vite-node/src/cli.ts @@ -1,11 +1,12 @@ import cac from 'cac' -import { cyan, dim, red } from 'kolorist' +import { red } from 'kolorist' import { createServer } from 'vite' import { version } from '../package.json' import { ViteNodeServer } from './server' import { ViteNodeRunner } from './client' import type { ViteNodeServerOptions } from './types' import { toArray } from './utils' +import { createHotContext, handleMessage, viteNodeHmrPlugin } from './hmr' const cli = cac('vite-node') @@ -49,6 +50,9 @@ async function run(files: string[], options: CliOptions = {}) { logLevel: 'error', configFile: options.config, root: options.root, + plugins: [ + viteNodeHmrPlugin(), + ], }) await server.pluginContainer.buildStart({}) @@ -63,6 +67,9 @@ async function run(files: string[], options: CliOptions = {}) { resolveId(id, importer) { return node.resolveId(id, importer) }, + createHotContext(runner, url) { + return createHotContext(runner, server.emitter, files, url) + }, }) // provide the vite define variable in this context @@ -74,18 +81,8 @@ async function run(files: string[], options: CliOptions = {}) { if (!options.watch) await server.close() - server.watcher.on('change', async (path) => { - console.log(`${cyan('[vite-node]')} File change detected. ${dim(path)}`) - - // invalidate module cache but not node_modules - Array.from(runner.moduleCache.keys()) - .forEach((i) => { - if (!i.includes('node_modules')) - runner.moduleCache.delete(i) - }) - - for (const file of files) - await runner.executeFile(file) + server.emitter.on('message', (payload) => { + handleMessage(runner, server.emitter, files, payload) }) } diff --git a/packages/vite-node/src/client.ts b/packages/vite-node/src/client.ts index 706286fb1401..865e0b77ac53 100644 --- a/packages/vite-node/src/client.ts +++ b/packages/vite-node/src/client.ts @@ -187,7 +187,10 @@ export class ViteNodeRunner { __vite_ssr_dynamic_import__: request, __vite_ssr_exports__: exports, __vite_ssr_exportAll__: (obj: any) => exportAll(exports, obj), - __vite_ssr_import_meta__: { url }, + __vite_ssr_import_meta__: { + url, + hot: this.options.createHotContext?.(this, `/@fs/${fsPath}`), + }, __vitest_resolve_id__: resolveId, diff --git a/packages/vite-node/src/hmr/emitter.ts b/packages/vite-node/src/hmr/emitter.ts new file mode 100644 index 000000000000..02904391e25d --- /dev/null +++ b/packages/vite-node/src/hmr/emitter.ts @@ -0,0 +1,42 @@ +import { EventEmitter } from 'events' +import type { HMRPayload, Plugin } from 'vite' + +export type EventType = string | symbol +export type Handler = (event: T) => void +export interface Emitter> { + on(type: Key, handler: Handler): void + off(type: Key, handler?: Handler): void + emit(type: Key, event: Events[Key]): void + emit(type: undefined extends Events[Key] ? Key : never): void +} + +export type HMREmitter = Emitter<{ + 'message': HMRPayload +}> & EventEmitter + +declare module 'vite' { + interface ViteDevServer { + emitter: HMREmitter + } +} + +export function createHmrEmitter(): HMREmitter { + const emitter = new EventEmitter() + return emitter +} + +export function viteNodeHmrPlugin(): Plugin { + const emitter = createHmrEmitter() + return { + name: 'vite-node:hmr', + + configureServer(server) { + const _send = server.ws.send + server.emitter = emitter + server.ws.send = function (payload: HMRPayload) { + _send(payload) + emitter.emit('message', payload) + } + }, + } +} diff --git a/packages/vite-node/src/hmr/hmr.ts b/packages/vite-node/src/hmr/hmr.ts new file mode 100644 index 000000000000..7f35c3a5064a --- /dev/null +++ b/packages/vite-node/src/hmr/hmr.ts @@ -0,0 +1,169 @@ +/* eslint-disable no-console */ +import type { ErrorPayload, FullReloadPayload, HMRPayload, PrunePayload, Update, UpdatePayload } from 'vite/types/hmrPayload' +import { cyan } from 'kolorist' +import type { ViteNodeRunner } from '../client' +import { getCache } from './hotContext' +import type { HMREmitter } from './emitter' + +export interface CustomEventMap { + 'vite:beforeUpdate': UpdatePayload + 'vite:beforePrune': PrunePayload + 'vite:beforeFullReload': FullReloadPayload + 'vite:error': ErrorPayload +} + +export type InferCustomEventPayload = + T extends keyof CustomEventMap ? CustomEventMap[T] : any + +export function sendMessageBuffer(runner: ViteNodeRunner, emitter: HMREmitter) { + const maps = getCache(runner) + maps.messageBuffer.forEach(msg => emitter.emit('custom', msg)) + maps.messageBuffer.length = 0 +} + +export async function reload(runner: ViteNodeRunner, files: string[]) { + // invalidate module cache but not node_modules + Array.from(runner.moduleCache.keys()) + .forEach((i) => { + if (!i.includes('node_modules')) + runner.moduleCache.delete(i) + }) + + return Promise.all(files.map(file => runner.executeId(file))) +} + +function notifyListeners( + runner: ViteNodeRunner, + event: T, + data: InferCustomEventPayload, +): void +function notifyListeners(runner: ViteNodeRunner, event: string, data: any): void { + const maps = getCache(runner) + const cbs = maps.customListenersMap.get(event) + if (cbs) + cbs.forEach(cb => cb(data)) +} + +async function queueUpdate(runner: ViteNodeRunner, p: Promise<(() => void) | undefined>) { + const maps = getCache(runner) + maps.queued.push(p) + if (!maps.pending) { + maps.pending = true + await Promise.resolve() + maps.pending = false + const loading = [...maps.queued] + maps.queued = [] + ;(await Promise.all(loading)).forEach(fn => fn && fn()) + } +} + +async function fetchUpdate(runner: ViteNodeRunner, { path, acceptedPath }: Update) { + const maps = getCache(runner) + const mod = maps.hotModulesMap.get(path) + + if (!mod) { + // In a code-splitting project, + // it is common that the hot-updating module is not loaded yet. + // https://github.com/vitejs/vite/issues/721 + return + } + + const moduleMap = new Map() + const isSelfUpdate = path === acceptedPath + + // make sure we only import each dep once + const modulesToUpdate = new Set() + if (isSelfUpdate) { + // self update - only update self + modulesToUpdate.add(path) + } + else { + // dep update + for (const { deps } of mod.callbacks) { + deps.forEach((dep) => { + if (acceptedPath === dep) + modulesToUpdate.add(dep) + }) + } + } + + // determine the qualified callbacks before we re-import the modules + const qualifiedCallbacks = mod.callbacks.filter(({ deps }) => { + return deps.some(dep => modulesToUpdate.has(dep)) + }) + + await Promise.all( + Array.from(modulesToUpdate).map(async (dep) => { + const disposer = maps.disposeMap.get(dep) + if (disposer) + await disposer(maps.dataMap.get(dep)) + try { + const newMod = await reload(runner, [dep]) + moduleMap.set(dep, newMod) + } + catch (e: any) { + warnFailedFetch(e, dep) + } + }), + ) + + return () => { + for (const { deps, fn } of qualifiedCallbacks) + fn(deps.map(dep => moduleMap.get(dep))) + + const loggedPath = isSelfUpdate ? path : `${acceptedPath} via ${path}` + console.log(`${cyan('[vite-node]')} hot updated: ${loggedPath}`) + } +} + +function warnFailedFetch(err: Error, path: string | string[]) { + if (!err.message.match('fetch')) + console.error(err) + + console.error( + `[hmr] Failed to reload ${path}. ` + + 'This could be due to syntax errors or importing non-existent ' + + 'modules. (see errors above)', + ) +} + +export async function handleMessage(runner: ViteNodeRunner, emitter: HMREmitter, files: string[], payload: HMRPayload) { + const maps = getCache(runner) + switch (payload.type) { + case 'connected': + sendMessageBuffer(runner, emitter) + break + case 'update': + notifyListeners(runner, 'vite:beforeUpdate', payload) + if (maps.isFirstUpdate) { + reload(runner, files) + maps.isFirstUpdate = true + } + payload.updates.forEach((update) => { + if (update.type === 'js-update') { + queueUpdate(runner, fetchUpdate(runner, update)) + } + else { + // css-update + console.error(`${cyan('[vite-node]')} no support css hmr.}`) + } + }) + break + case 'full-reload': + reload(runner, files) + break + case 'prune': + payload.paths.forEach((path) => { + const fn = maps.pruneMap.get(path) + if (fn) + fn(maps.dataMap.get(path)) + }) + break + case 'error': { + notifyListeners(runner, 'vite:error', payload) + const err = payload.err + console.error(`${cyan('[vite-node]')} Internal Server Error\n${err.message}\n${err.stack}`) + break + } + } +} diff --git a/packages/vite-node/src/hmr/hotContext.ts b/packages/vite-node/src/hmr/hotContext.ts new file mode 100644 index 000000000000..e1efca35a57a --- /dev/null +++ b/packages/vite-node/src/hmr/hotContext.ts @@ -0,0 +1,140 @@ +import type { InferCustomEventPayload } from 'vite' +import type { ViteNodeRunner } from '../client' +import type { HotContext } from '../types' +import { reload, sendMessageBuffer } from './hmr' +import type { HMREmitter } from './emitter' + +export interface HotModule { + id: string + callbacks: HotCallback[] +} + +export interface HotCallback { + // the dependencies must be fetchable paths + deps: string[] + fn: (modules: object[]) => void +} + +interface CacheData { + hotModulesMap: Map + dataMap: Map + disposeMap: Map void | Promise> + pruneMap: Map void | Promise> + customListenersMap: Map void)[]> + ctxToListenersMap: Map< + string, + Map void)[]> + > + messageBuffer: string[] + isFirstUpdate: boolean + pending: boolean + queued: Promise<(() => void) | undefined>[] +} + +const cache: WeakMap = new WeakMap() + +export function getCache(runner: ViteNodeRunner): CacheData { + if (!cache.has(runner)) { + cache.set(runner, { + hotModulesMap: new Map(), + dataMap: new Map(), + disposeMap: new Map(), + pruneMap: new Map(), + customListenersMap: new Map(), + ctxToListenersMap: new Map(), + messageBuffer: [], + isFirstUpdate: false, + pending: false, + queued: [], + }) + } + return cache.get(runner) as CacheData +} + +export function createHotContext( + runner: ViteNodeRunner, + emitter: HMREmitter, + files: string[], + ownerPath: string, +): HotContext { + const maps = getCache(runner) + if (!maps.dataMap.has(ownerPath)) + maps.dataMap.set(ownerPath, {}) + + // when a file is hot updated, a new context is created + // clear its stale callbacks + const mod = maps.hotModulesMap.get(ownerPath) + if (mod) + mod.callbacks = [] + + const newListeners = new Map() + maps.ctxToListenersMap.set(ownerPath, newListeners) + + function acceptDeps(deps: string[], callback: HotCallback['fn'] = () => {}) { + const mod: HotModule = maps.hotModulesMap.get(ownerPath) || { + id: ownerPath, + callbacks: [], + } + mod.callbacks.push({ + deps, + fn: callback, + }) + maps.hotModulesMap.set(ownerPath, mod) + } + + const hot: HotContext = { + get data() { + return maps.dataMap.get(ownerPath) + }, + + accept(deps?: any, callback?: any) { + if (typeof deps === 'function' || !deps) { + // self-accept: hot.accept(() => {}) + acceptDeps([ownerPath], ([mod]) => deps && deps(mod)) + } + else if (typeof deps === 'string') { + // explicit deps + acceptDeps([deps], ([mod]) => callback && callback(mod)) + } + else if (Array.isArray(deps)) { + acceptDeps(deps, callback) + } + else { + throw new TypeError('invalid hot.accept() usage.') + } + }, + + dispose(cb) { + maps.disposeMap.set(ownerPath, cb) + }, + + // @ts-expect-error untyped + prune(cb: (data: any) => void) { + maps.pruneMap.set(ownerPath, cb) + }, + + invalidate() { + return reload(runner, files) + }, + + on( + event: T, + cb: (payload: InferCustomEventPayload) => void, + ): void { + const addToMap = (map: Map) => { + const existing = map.get(event) || [] + existing.push(cb) + map.set(event, existing) + } + addToMap(maps.customListenersMap) + addToMap(newListeners) + }, + + send(event: T, data?: InferCustomEventPayload): void { + maps.messageBuffer.push(JSON.stringify({ type: 'custom', event, data })) + sendMessageBuffer(runner, emitter) + }, + } + + return hot +} diff --git a/packages/vite-node/src/hmr/index.ts b/packages/vite-node/src/hmr/index.ts new file mode 100644 index 000000000000..0255738ea54c --- /dev/null +++ b/packages/vite-node/src/hmr/index.ts @@ -0,0 +1,3 @@ +export * from './emitter' +export * from './hotContext' +export * from './hmr' diff --git a/packages/vite-node/src/types.ts b/packages/vite-node/src/types.ts index ab84483655cb..f0e594e67fd0 100644 --- a/packages/vite-node/src/types.ts +++ b/packages/vite-node/src/types.ts @@ -1,4 +1,5 @@ -import type { ModuleCacheMap } from './client' +import type { ViteHotContext } from 'vite/types/hot' +import type { ModuleCacheMap, ViteNodeRunner } from './client' export type Nullable = T | null | undefined export type Arrayable = T | Array @@ -32,10 +33,14 @@ export interface FetchResult { map?: RawSourceMap } +export type HotContext = Omit + export type FetchFunction = (id: string) => Promise export type ResolveIdFunction = (id: string, importer?: string) => Promise +export type CreateHotContextFunction = (runner: ViteNodeRunner, url: string) => HotContext + export interface ModuleCache { promise?: Promise exports?: any @@ -46,6 +51,7 @@ export interface ViteNodeRunnerOptions { root: string fetchModule: FetchFunction resolveId?: ResolveIdFunction + createHotContext?: CreateHotContextFunction base?: string moduleCache?: ModuleCacheMap interopDefault?: boolean diff --git a/test/vite-node/package.json b/test/vite-node/package.json index 5db30c71ad17..b01e47689c59 100644 --- a/test/vite-node/package.json +++ b/test/vite-node/package.json @@ -5,7 +5,9 @@ "license": "MIT", "type": "module", "scripts": { - "dev": "vite-node --watch ./src/*" + "dev": "vite-node --watch ./src/*", + "debug:dev": "node --inspect-brk ../../packages/vite-node/dist/cli.cjs --watch ./src/*", + "debug": "node --inspect-brk ../../packages/vite-node/dist/cli.cjs" }, "devDependencies": { "vite-node": "workspace:*" diff --git a/test/vite-node/src/deps.ts b/test/vite-node/src/deps.ts new file mode 100644 index 000000000000..148cb5dc41a2 --- /dev/null +++ b/test/vite-node/src/deps.ts @@ -0,0 +1,9 @@ +// eslint-disable-next-line no-console +console.log('deps') + +export {} + +import.meta.hot && import.meta.hot.accept(() => { + // eslint-disable-next-line no-console + console.log('[deps.ts] hot reload!') +}) diff --git a/test/vite-node/src/testMod.ts b/test/vite-node/src/testMod.ts index 873f02f6ae3a..2e6630f2fbf4 100644 --- a/test/vite-node/src/testMod.ts +++ b/test/vite-node/src/testMod.ts @@ -2,3 +2,5 @@ export const a = 'hello testModule' // eslint-disable-next-line no-console console.log('[testModule.js] load!') + +import('./deps') From 70f61847459ea20e6dc1583ab33dd2bc3e631514 Mon Sep 17 00:00:00 2001 From: yoho Date: Mon, 20 Jun 2022 23:03:28 +0800 Subject: [PATCH 03/15] chore: lock.yaml --- pnpm-lock.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 26e57f842866..e3120fbc7a0a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -874,6 +874,12 @@ importers: pathe: 0.2.0 vitest: link:../../packages/vitest + test/vite-node: + specifiers: + vite-node: workspace:* + devDependencies: + vite-node: link:../../packages/vite-node + test/web-worker: specifiers: '@vitest/web-worker': workspace:* From b3b081dab32c8a4ca61f053f5b643650ca77d5d1 Mon Sep 17 00:00:00 2001 From: yoho Date: Mon, 20 Jun 2022 23:12:39 +0800 Subject: [PATCH 04/15] chore: update --- test/vite-node/package.json | 2 -- test/vite-node/src/deps.ts | 10 ++++++---- test/vite-node/src/main.ts | 12 +++++++++--- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/test/vite-node/package.json b/test/vite-node/package.json index b01e47689c59..67a1c054050f 100644 --- a/test/vite-node/package.json +++ b/test/vite-node/package.json @@ -1,8 +1,6 @@ { "name": "vite-node-test", "private": true, - "main": "index.js", - "license": "MIT", "type": "module", "scripts": { "dev": "vite-node --watch ./src/*", diff --git a/test/vite-node/src/deps.ts b/test/vite-node/src/deps.ts index 148cb5dc41a2..285eb842f8ad 100644 --- a/test/vite-node/src/deps.ts +++ b/test/vite-node/src/deps.ts @@ -3,7 +3,9 @@ console.log('deps') export {} -import.meta.hot && import.meta.hot.accept(() => { - // eslint-disable-next-line no-console - console.log('[deps.ts] hot reload!') -}) +if (import.meta.hot) { + import.meta.hot.accept(() => { + // eslint-disable-next-line no-console + console.log('[deps.ts] hot reload!') + }) +} diff --git a/test/vite-node/src/main.ts b/test/vite-node/src/main.ts index 2bec6ed94a6f..601823a63f0e 100644 --- a/test/vite-node/src/main.ts +++ b/test/vite-node/src/main.ts @@ -1,6 +1,12 @@ /* eslint-disable no-console */ import { a } from './testMod' -console.log('[index.js] load!') -console.log('hello world') -console.log(a) +console.log('[main.js] load!') +console.log('[main.js] hello world') +console.log('[main.js]', a) + +if (import.meta.hot) { + import.meta.hot.accept(() => { + console.log('[main.ts] hot reload!') + }) +} From 6e7cc1d0b36e896346ec1df24990d895691cf284 Mon Sep 17 00:00:00 2001 From: yoho Date: Mon, 20 Jun 2022 23:20:46 +0800 Subject: [PATCH 05/15] chore: update --- test/vite-node/package.json | 1 - test/vite-node/vite.config.ts | 5 +++++ 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 test/vite-node/vite.config.ts diff --git a/test/vite-node/package.json b/test/vite-node/package.json index 67a1c054050f..50aa298c032c 100644 --- a/test/vite-node/package.json +++ b/test/vite-node/package.json @@ -1,7 +1,6 @@ { "name": "vite-node-test", "private": true, - "type": "module", "scripts": { "dev": "vite-node --watch ./src/*", "debug:dev": "node --inspect-brk ../../packages/vite-node/dist/cli.cjs --watch ./src/*", diff --git a/test/vite-node/vite.config.ts b/test/vite-node/vite.config.ts new file mode 100644 index 000000000000..6d1069aeb9dd --- /dev/null +++ b/test/vite-node/vite.config.ts @@ -0,0 +1,5 @@ +import { defineConfig } from 'vite' + +export default defineConfig({ + +}) From 75c033b47d43a70b087b57e4a730b7017a39a916 Mon Sep 17 00:00:00 2001 From: yoho Date: Mon, 20 Jun 2022 23:23:11 +0800 Subject: [PATCH 06/15] chore: update --- packages/vite-node/src/hmr/hmr.ts | 137 +++++++++++++++++++++- packages/vite-node/src/hmr/hotContext.ts | 140 ----------------------- packages/vite-node/src/hmr/index.ts | 1 - 3 files changed, 136 insertions(+), 142 deletions(-) delete mode 100644 packages/vite-node/src/hmr/hotContext.ts diff --git a/packages/vite-node/src/hmr/hmr.ts b/packages/vite-node/src/hmr/hmr.ts index 7f35c3a5064a..77e12176ef5a 100644 --- a/packages/vite-node/src/hmr/hmr.ts +++ b/packages/vite-node/src/hmr/hmr.ts @@ -2,7 +2,7 @@ import type { ErrorPayload, FullReloadPayload, HMRPayload, PrunePayload, Update, UpdatePayload } from 'vite/types/hmrPayload' import { cyan } from 'kolorist' import type { ViteNodeRunner } from '../client' -import { getCache } from './hotContext' +import type { HotContext } from '../types' import type { HMREmitter } from './emitter' export interface CustomEventMap { @@ -15,6 +15,53 @@ export interface CustomEventMap { export type InferCustomEventPayload = T extends keyof CustomEventMap ? CustomEventMap[T] : any +export interface HotModule { + id: string + callbacks: HotCallback[] +} + +export interface HotCallback { + // the dependencies must be fetchable paths + deps: string[] + fn: (modules: object[]) => void +} + +interface CacheData { + hotModulesMap: Map + dataMap: Map + disposeMap: Map void | Promise> + pruneMap: Map void | Promise> + customListenersMap: Map void)[]> + ctxToListenersMap: Map< + string, + Map void)[]> + > + messageBuffer: string[] + isFirstUpdate: boolean + pending: boolean + queued: Promise<(() => void) | undefined>[] +} + +const cache: WeakMap = new WeakMap() + +export function getCache(runner: ViteNodeRunner): CacheData { + if (!cache.has(runner)) { + cache.set(runner, { + hotModulesMap: new Map(), + dataMap: new Map(), + disposeMap: new Map(), + pruneMap: new Map(), + customListenersMap: new Map(), + ctxToListenersMap: new Map(), + messageBuffer: [], + isFirstUpdate: false, + pending: false, + queued: [], + }) + } + return cache.get(runner) as CacheData +} + export function sendMessageBuffer(runner: ViteNodeRunner, emitter: HMREmitter) { const maps = getCache(runner) maps.messageBuffer.forEach(msg => emitter.emit('custom', msg)) @@ -167,3 +214,91 @@ export async function handleMessage(runner: ViteNodeRunner, emitter: HMREmitter, } } } + +export function createHotContext( + runner: ViteNodeRunner, + emitter: HMREmitter, + files: string[], + ownerPath: string, +): HotContext { + const maps = getCache(runner) + if (!maps.dataMap.has(ownerPath)) + maps.dataMap.set(ownerPath, {}) + + // when a file is hot updated, a new context is created + // clear its stale callbacks + const mod = maps.hotModulesMap.get(ownerPath) + if (mod) + mod.callbacks = [] + + const newListeners = new Map() + maps.ctxToListenersMap.set(ownerPath, newListeners) + + function acceptDeps(deps: string[], callback: HotCallback['fn'] = () => {}) { + const mod: HotModule = maps.hotModulesMap.get(ownerPath) || { + id: ownerPath, + callbacks: [], + } + mod.callbacks.push({ + deps, + fn: callback, + }) + maps.hotModulesMap.set(ownerPath, mod) + } + + const hot: HotContext = { + get data() { + return maps.dataMap.get(ownerPath) + }, + + accept(deps?: any, callback?: any) { + if (typeof deps === 'function' || !deps) { + // self-accept: hot.accept(() => {}) + acceptDeps([ownerPath], ([mod]) => deps && deps(mod)) + } + else if (typeof deps === 'string') { + // explicit deps + acceptDeps([deps], ([mod]) => callback && callback(mod)) + } + else if (Array.isArray(deps)) { + acceptDeps(deps, callback) + } + else { + throw new TypeError('invalid hot.accept() usage.') + } + }, + + dispose(cb) { + maps.disposeMap.set(ownerPath, cb) + }, + + // @ts-expect-error untyped + prune(cb: (data: any) => void) { + maps.pruneMap.set(ownerPath, cb) + }, + + invalidate() { + return reload(runner, files) + }, + + on( + event: T, + cb: (payload: InferCustomEventPayload) => void, + ): void { + const addToMap = (map: Map) => { + const existing = map.get(event) || [] + existing.push(cb) + map.set(event, existing) + } + addToMap(maps.customListenersMap) + addToMap(newListeners) + }, + + send(event: T, data?: InferCustomEventPayload): void { + maps.messageBuffer.push(JSON.stringify({ type: 'custom', event, data })) + sendMessageBuffer(runner, emitter) + }, + } + + return hot +} diff --git a/packages/vite-node/src/hmr/hotContext.ts b/packages/vite-node/src/hmr/hotContext.ts deleted file mode 100644 index e1efca35a57a..000000000000 --- a/packages/vite-node/src/hmr/hotContext.ts +++ /dev/null @@ -1,140 +0,0 @@ -import type { InferCustomEventPayload } from 'vite' -import type { ViteNodeRunner } from '../client' -import type { HotContext } from '../types' -import { reload, sendMessageBuffer } from './hmr' -import type { HMREmitter } from './emitter' - -export interface HotModule { - id: string - callbacks: HotCallback[] -} - -export interface HotCallback { - // the dependencies must be fetchable paths - deps: string[] - fn: (modules: object[]) => void -} - -interface CacheData { - hotModulesMap: Map - dataMap: Map - disposeMap: Map void | Promise> - pruneMap: Map void | Promise> - customListenersMap: Map void)[]> - ctxToListenersMap: Map< - string, - Map void)[]> - > - messageBuffer: string[] - isFirstUpdate: boolean - pending: boolean - queued: Promise<(() => void) | undefined>[] -} - -const cache: WeakMap = new WeakMap() - -export function getCache(runner: ViteNodeRunner): CacheData { - if (!cache.has(runner)) { - cache.set(runner, { - hotModulesMap: new Map(), - dataMap: new Map(), - disposeMap: new Map(), - pruneMap: new Map(), - customListenersMap: new Map(), - ctxToListenersMap: new Map(), - messageBuffer: [], - isFirstUpdate: false, - pending: false, - queued: [], - }) - } - return cache.get(runner) as CacheData -} - -export function createHotContext( - runner: ViteNodeRunner, - emitter: HMREmitter, - files: string[], - ownerPath: string, -): HotContext { - const maps = getCache(runner) - if (!maps.dataMap.has(ownerPath)) - maps.dataMap.set(ownerPath, {}) - - // when a file is hot updated, a new context is created - // clear its stale callbacks - const mod = maps.hotModulesMap.get(ownerPath) - if (mod) - mod.callbacks = [] - - const newListeners = new Map() - maps.ctxToListenersMap.set(ownerPath, newListeners) - - function acceptDeps(deps: string[], callback: HotCallback['fn'] = () => {}) { - const mod: HotModule = maps.hotModulesMap.get(ownerPath) || { - id: ownerPath, - callbacks: [], - } - mod.callbacks.push({ - deps, - fn: callback, - }) - maps.hotModulesMap.set(ownerPath, mod) - } - - const hot: HotContext = { - get data() { - return maps.dataMap.get(ownerPath) - }, - - accept(deps?: any, callback?: any) { - if (typeof deps === 'function' || !deps) { - // self-accept: hot.accept(() => {}) - acceptDeps([ownerPath], ([mod]) => deps && deps(mod)) - } - else if (typeof deps === 'string') { - // explicit deps - acceptDeps([deps], ([mod]) => callback && callback(mod)) - } - else if (Array.isArray(deps)) { - acceptDeps(deps, callback) - } - else { - throw new TypeError('invalid hot.accept() usage.') - } - }, - - dispose(cb) { - maps.disposeMap.set(ownerPath, cb) - }, - - // @ts-expect-error untyped - prune(cb: (data: any) => void) { - maps.pruneMap.set(ownerPath, cb) - }, - - invalidate() { - return reload(runner, files) - }, - - on( - event: T, - cb: (payload: InferCustomEventPayload) => void, - ): void { - const addToMap = (map: Map) => { - const existing = map.get(event) || [] - existing.push(cb) - map.set(event, existing) - } - addToMap(maps.customListenersMap) - addToMap(newListeners) - }, - - send(event: T, data?: InferCustomEventPayload): void { - maps.messageBuffer.push(JSON.stringify({ type: 'custom', event, data })) - sendMessageBuffer(runner, emitter) - }, - } - - return hot -} diff --git a/packages/vite-node/src/hmr/index.ts b/packages/vite-node/src/hmr/index.ts index 0255738ea54c..1862f7e41ddb 100644 --- a/packages/vite-node/src/hmr/index.ts +++ b/packages/vite-node/src/hmr/index.ts @@ -1,3 +1,2 @@ export * from './emitter' -export * from './hotContext' export * from './hmr' From cc18d0cb7c0bf2cf845f3391723e763928049ec4 Mon Sep 17 00:00:00 2001 From: yoho Date: Tue, 21 Jun 2022 11:28:08 +0800 Subject: [PATCH 07/15] feat: hmr module --- packages/vite-node/rollup.config.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/vite-node/rollup.config.js b/packages/vite-node/rollup.config.js index ab44d5e95134..c24b4b11364e 100644 --- a/packages/vite-node/rollup.config.js +++ b/packages/vite-node/rollup.config.js @@ -14,6 +14,7 @@ const entries = { client: 'src/client.ts', utils: 'src/utils.ts', cli: 'src/cli.ts', + hmr: 'src/hmr/index.ts', } const external = [ @@ -23,6 +24,7 @@ const external = [ 'birpc', 'vite', 'url', + 'events', ] const plugins = [ From 56feaabeb6da0f2fa6f27cbb302920f35972c2b5 Mon Sep 17 00:00:00 2001 From: yoho Date: Tue, 21 Jun 2022 11:28:36 +0800 Subject: [PATCH 08/15] chore: package.json --- packages/vite-node/package.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/vite-node/package.json b/packages/vite-node/package.json index 0704322993f2..41ad84d8afd4 100644 --- a/packages/vite-node/package.json +++ b/packages/vite-node/package.json @@ -34,6 +34,11 @@ "types": "./dist/utils.d.ts", "require": "./dist/utils.cjs", "import": "./dist/utils.mjs" + }, + "./hmr": { + "types": "./dist/hmr.d.ts", + "require": "./dist/hmr.cjs", + "import": "./dist/hmr.mjs" } }, "main": "./dist/index.mjs", From c46bc22d9d00fc49f5c5966ab176729bdd178995 Mon Sep 17 00:00:00 2001 From: yoho Date: Tue, 21 Jun 2022 21:12:38 +0800 Subject: [PATCH 09/15] perf: create ctx only had `__vite_ssr_import_meta__.hot` --- packages/vite-node/src/client.ts | 4 +++- packages/vite-node/src/hmr/hmr.ts | 4 ++++ test/vite-node/package.json | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/vite-node/src/client.ts b/packages/vite-node/src/client.ts index 865e0b77ac53..0c7fe0ea427a 100644 --- a/packages/vite-node/src/client.ts +++ b/packages/vite-node/src/client.ts @@ -177,6 +177,8 @@ export class ViteNodeRunner { }, } + const isNeedHmr = transformed.includes('__vite_ssr_import_meta__.hot') + // Be careful when changing this // changing context will change amount of code added on line :114 (vm.runInThisContext) // this messes up sourcemaps for coverage @@ -189,7 +191,7 @@ export class ViteNodeRunner { __vite_ssr_exportAll__: (obj: any) => exportAll(exports, obj), __vite_ssr_import_meta__: { url, - hot: this.options.createHotContext?.(this, `/@fs/${fsPath}`), + hot: isNeedHmr ? this.options.createHotContext?.(this, `/@fs/${fsPath}`) : undefined, }, __vitest_resolve_id__: resolveId, diff --git a/packages/vite-node/src/hmr/hmr.ts b/packages/vite-node/src/hmr/hmr.ts index 77e12176ef5a..347206f0923e 100644 --- a/packages/vite-node/src/hmr/hmr.ts +++ b/packages/vite-node/src/hmr/hmr.ts @@ -1,10 +1,13 @@ /* eslint-disable no-console */ import type { ErrorPayload, FullReloadPayload, HMRPayload, PrunePayload, Update, UpdatePayload } from 'vite/types/hmrPayload' import { cyan } from 'kolorist' +import createDebug from 'debug' import type { ViteNodeRunner } from '../client' import type { HotContext } from '../types' import type { HMREmitter } from './emitter' +const debugHmr = createDebug('vite-node:hmr') + export interface CustomEventMap { 'vite:beforeUpdate': UpdatePayload 'vite:beforePrune': PrunePayload @@ -221,6 +224,7 @@ export function createHotContext( files: string[], ownerPath: string, ): HotContext { + debugHmr('createHotContext', ownerPath) const maps = getCache(runner) if (!maps.dataMap.has(ownerPath)) maps.dataMap.set(ownerPath, {}) diff --git a/test/vite-node/package.json b/test/vite-node/package.json index 50aa298c032c..a872fda25a87 100644 --- a/test/vite-node/package.json +++ b/test/vite-node/package.json @@ -3,7 +3,7 @@ "private": true, "scripts": { "dev": "vite-node --watch ./src/*", - "debug:dev": "node --inspect-brk ../../packages/vite-node/dist/cli.cjs --watch ./src/*", + "debug:dev": "cross-env DEBUG=vite-node:hmr node --inspect-brk ../../packages/vite-node/dist/cli.cjs --watch ./src/*", "debug": "node --inspect-brk ../../packages/vite-node/dist/cli.cjs" }, "devDependencies": { From b43f28d6dc74c0f3f7d76a905b7bef1d64ba2472 Mon Sep 17 00:00:00 2001 From: yoho Date: Tue, 21 Jun 2022 21:17:01 +0800 Subject: [PATCH 10/15] chore: update --- test/vite-node/vite.config.ts | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 test/vite-node/vite.config.ts diff --git a/test/vite-node/vite.config.ts b/test/vite-node/vite.config.ts deleted file mode 100644 index 6d1069aeb9dd..000000000000 --- a/test/vite-node/vite.config.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { defineConfig } from 'vite' - -export default defineConfig({ - -}) From 37aa4d00823d01cb9ba47b705168b7eb5bdda5c9 Mon Sep 17 00:00:00 2001 From: yoho Date: Tue, 21 Jun 2022 21:52:22 +0800 Subject: [PATCH 11/15] chore: update --- test/vite-node/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/vite-node/package.json b/test/vite-node/package.json index b0b26e395e32..84e9afb07e23 100644 --- a/test/vite-node/package.json +++ b/test/vite-node/package.json @@ -5,7 +5,7 @@ "test": "vitest", "coverage": "vitest run --coverage", "dev": "vite-node --watch ./src/*", - "debug:dev": "cross-env DEBUG=vite-node:hmr node --inspect-brk ../../packages/vite-node/dist/cli.cjs --watch ./src/*", + "debug:dev": "cross-env DEBUG=vite-node:* node --inspect-brk ../../packages/vite-node/dist/cli.cjs --watch ./src/*", "debug": "node --inspect-brk ../../packages/vite-node/dist/cli.cjs" }, "devDependencies": { From ec0ab18270b37774053721de106246bbc13777f7 Mon Sep 17 00:00:00 2001 From: yoho Date: Tue, 21 Jun 2022 21:59:43 +0800 Subject: [PATCH 12/15] chore: update --- pnpm-lock.yaml | 2 -- test/vite-node/package.json | 1 - 2 files changed, 3 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8de30507a22a..91fd7db6a604 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -879,11 +879,9 @@ importers: test/vite-node: specifiers: - vite: ^2.9.10 vite-node: workspace:* vitest: workspace:* devDependencies: - vite: 2.9.10 vite-node: link:../../packages/vite-node vitest: link:../../packages/vitest diff --git a/test/vite-node/package.json b/test/vite-node/package.json index 84e9afb07e23..847c24e5adb3 100644 --- a/test/vite-node/package.json +++ b/test/vite-node/package.json @@ -9,7 +9,6 @@ "debug": "node --inspect-brk ../../packages/vite-node/dist/cli.cjs" }, "devDependencies": { - "vite": "^2.9.10", "vite-node": "workspace:*", "vitest": "workspace:*" } From d9303c2fb10b8648e9919f2dd6950d7372265e3b Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Fri, 1 Jul 2022 17:15:33 +0800 Subject: [PATCH 13/15] chore: update --- packages/vite-node/src/client.ts | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/packages/vite-node/src/client.ts b/packages/vite-node/src/client.ts index 0c7fe0ea427a..6cd38a905409 100644 --- a/packages/vite-node/src/client.ts +++ b/packages/vite-node/src/client.ts @@ -5,7 +5,7 @@ import { dirname, extname, isAbsolute, resolve } from 'pathe' import { isNodeBuiltin } from 'mlly' import createDebug from 'debug' import { isPrimitive, mergeSlashes, normalizeModuleId, normalizeRequestId, slash, toFilePath } from './utils' -import type { ModuleCache, ViteNodeRunnerOptions } from './types' +import type { HotContext, ModuleCache, ViteNodeRunnerOptions } from './types' const debugExecute = createDebug('vite-node:client:execute') const debugNative = createDebug('vite-node:client:native') @@ -161,6 +161,7 @@ export class ViteNodeRunner { // disambiguate the `:/` on windows: see nodejs/node#31710 const url = pathToFileURL(fsPath).href + const meta = { url } const exports: any = Object.create(null) exports[Symbol.toStringTag] = 'Module' @@ -177,7 +178,17 @@ export class ViteNodeRunner { }, } - const isNeedHmr = transformed.includes('__vite_ssr_import_meta__.hot') + // Vite hot context + let hotContext: HotContext | undefined + if (this.options.createHotContext) { + Object.defineProperty(meta, 'hot', { + enumerable: true, + get: () => { + hotContext ||= this.options.createHotContext?.(this, `/@fs/${fsPath}`) + return hotContext + }, + }) + } // Be careful when changing this // changing context will change amount of code added on line :114 (vm.runInThisContext) @@ -189,11 +200,7 @@ export class ViteNodeRunner { __vite_ssr_dynamic_import__: request, __vite_ssr_exports__: exports, __vite_ssr_exportAll__: (obj: any) => exportAll(exports, obj), - __vite_ssr_import_meta__: { - url, - hot: isNeedHmr ? this.options.createHotContext?.(this, `/@fs/${fsPath}`) : undefined, - }, - + __vite_ssr_import_meta__: meta, __vitest_resolve_id__: resolveId, // cjs compact From 09cd8f0200193fa3d84023b327d40f16e265e5cd Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Fri, 1 Jul 2022 17:20:26 +0800 Subject: [PATCH 14/15] perf: only install hmr plugin on watch mode --- packages/vite-node/src/cli.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/vite-node/src/cli.ts b/packages/vite-node/src/cli.ts index eb76d5f4f9c8..7cce96604c01 100644 --- a/packages/vite-node/src/cli.ts +++ b/packages/vite-node/src/cli.ts @@ -51,7 +51,7 @@ async function run(files: string[], options: CliOptions = {}) { configFile: options.config, root: options.root, plugins: [ - viteNodeHmrPlugin(), + options.watch && viteNodeHmrPlugin(), ], }) await server.pluginContainer.buildStart({}) @@ -81,7 +81,7 @@ async function run(files: string[], options: CliOptions = {}) { if (!options.watch) await server.close() - server.emitter.on('message', (payload) => { + server.emitter?.on('message', (payload) => { handleMessage(runner, server.emitter, files, payload) }) } From 2465d7b3a89dcbc8d01e2db46ca9fb8b961fe0a4 Mon Sep 17 00:00:00 2001 From: Anthony Fu Date: Fri, 1 Jul 2022 17:26:37 +0800 Subject: [PATCH 15/15] chore: update lock --- pnpm-lock.yaml | 271 ++++++++++++------------------------------------- 1 file changed, 66 insertions(+), 205 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e2808f242d48..1b8be110ebb6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -163,7 +163,7 @@ importers: lit: 2.2.5 devDependencies: '@vitest/ui': link:../../packages/ui - happy-dom: 5.3.1 + happy-dom: 6.0.0 vite: 2.9.12 vitest: link:../../packages/vitest @@ -295,7 +295,7 @@ importers: dependencies: '@emotion/react': 11.9.0_3dj5wppwohj5ocihzt4m54mr2a '@emotion/styled': 11.8.1_3zgpe2oef7sbs566rsy6a7qm7i - '@mui/lab': 5.0.0-alpha.84_xjii3a7ufdwggkrf6imrcribfm + '@mui/lab': 5.0.0-alpha.88_xjii3a7ufdwggkrf6imrcribfm '@mui/material': 5.8.3_rikzftoujo3cmwul4lespwcm6i history: 5.3.0 notistack: 2.0.5_ozyq7dscrvuimqma7xstouyo4e @@ -351,10 +351,10 @@ importers: '@storybook/addon-actions': 6.5.5_sfoxds7t5ydpegc3knd667wn6m '@storybook/addon-essentials': 6.5.5_hsrlj427md5pp3pvjdg47ksxsm '@storybook/addon-links': 6.5.5_sfoxds7t5ydpegc3knd667wn6m - '@storybook/builder-vite': 0.1.35_pnlipthttc4nbyqborp4alalnm + '@storybook/builder-vite': 0.1.35_7xrp3utzqsruae7fycgzt5z3ri '@storybook/react': 6.5.8_oocfzwtuyqxgsjuquyuluqp3ji '@storybook/testing-library': 0.0.11_sfoxds7t5ydpegc3knd667wn6m - '@storybook/testing-react': 1.3.0_zosetbroh6lpsz2fq5auzg6cxe + '@storybook/testing-react': 1.3.0_arewo4uagrgfv3hckbnzjw6rsy '@testing-library/jest-dom': 5.16.4 '@testing-library/react': 12.1.5_sfoxds7t5ydpegc3knd667wn6m '@types/react': 17.0.45 @@ -3711,8 +3711,8 @@ packages: - supports-color dev: true - /@mui/base/5.0.0-alpha.83_sfoxds7t5ydpegc3knd667wn6m: - resolution: {integrity: sha512-/bFcjiI36R2Epf2Y3BkZOIdxrz5uMLqOU4cRai4igJ8DHTRMZDeKbOff0SdvwJNwg8r6oPUyoeOpsWkaOOX9/g==} + /@mui/base/5.0.0-alpha.84_sfoxds7t5ydpegc3knd667wn6m: + resolution: {integrity: sha512-uDx+wGVytS+ZHiWHyzUyijY83GSIXJpzSJ0PGc/8/s+8nBzeHvaPKrAyJz15ASLr52hYRA6PQGqn0eRAsB7syQ==} engines: {node: '>=12.0.0'} peerDependencies: '@types/react': ^17.0.0 || ^18.0.0 @@ -3724,8 +3724,8 @@ packages: dependencies: '@babel/runtime': 7.17.9 '@emotion/is-prop-valid': 1.1.2 - '@mui/types': 7.1.3 - '@mui/utils': 5.8.0_react@17.0.2 + '@mui/types': 7.1.4 + '@mui/utils': 5.8.6_react@17.0.2 '@popperjs/core': 2.11.5 clsx: 1.1.1 prop-types: 15.8.1 @@ -3734,8 +3734,8 @@ packages: react-is: 17.0.2 dev: false - /@mui/base/5.0.0-alpha.84_sfoxds7t5ydpegc3knd667wn6m: - resolution: {integrity: sha512-uDx+wGVytS+ZHiWHyzUyijY83GSIXJpzSJ0PGc/8/s+8nBzeHvaPKrAyJz15ASLr52hYRA6PQGqn0eRAsB7syQ==} + /@mui/base/5.0.0-alpha.87_sfoxds7t5ydpegc3knd667wn6m: + resolution: {integrity: sha512-PuxRYrvG63Yj/UTwf4hSwZ5ClMv88iXHK+5hUV1CrG3kNPo6FFQiIFNRaNpRt/3nsXj6+xygJByNFA8m4Leetg==} engines: {node: '>=12.0.0'} peerDependencies: '@types/react': ^17.0.0 || ^18.0.0 @@ -3747,8 +3747,8 @@ packages: dependencies: '@babel/runtime': 7.17.9 '@emotion/is-prop-valid': 1.1.2 - '@mui/types': 7.1.3 - '@mui/utils': 5.8.0_react@17.0.2 + '@mui/types': 7.1.4 + '@mui/utils': 5.8.6_react@17.0.2 '@popperjs/core': 2.11.5 clsx: 1.1.1 prop-types: 15.8.1 @@ -3757,8 +3757,8 @@ packages: react-is: 17.0.2 dev: false - /@mui/lab/5.0.0-alpha.84_xjii3a7ufdwggkrf6imrcribfm: - resolution: {integrity: sha512-HLYD6E3PAlzKMGZkkpiPI7trHP3WYDvrjQstEsFwdaGy9AMWPmyTxhwUyfB4VVHOx3zcj4p/a36kECDtEOAJ+g==} + /@mui/lab/5.0.0-alpha.88_xjii3a7ufdwggkrf6imrcribfm: + resolution: {integrity: sha512-YS2NPw0D0CHG9z9Y6Wjocl3g2LNzdXdkvORPoyc05ea9Xm+m8buddvMeTuL/r/e3S7yLK8HOMN2uHE0rwD/oVQ==} engines: {node: '>=12.0.0'} peerDependencies: '@emotion/react': ^11.5.0 @@ -3790,11 +3790,11 @@ packages: '@babel/runtime': 7.17.9 '@emotion/react': 11.9.0_3dj5wppwohj5ocihzt4m54mr2a '@emotion/styled': 11.8.1_3zgpe2oef7sbs566rsy6a7qm7i - '@mui/base': 5.0.0-alpha.83_sfoxds7t5ydpegc3knd667wn6m + '@mui/base': 5.0.0-alpha.87_sfoxds7t5ydpegc3knd667wn6m '@mui/material': 5.8.3_rikzftoujo3cmwul4lespwcm6i - '@mui/system': 5.8.2_bgqmsvm4hz6izcmpcwescmz73y - '@mui/utils': 5.8.0_react@17.0.2 - '@mui/x-date-pickers': 5.0.0-alpha.1_oapnwsljl22olbjazwqgrmnl5y + '@mui/system': 5.8.6_bgqmsvm4hz6izcmpcwescmz73y + '@mui/utils': 5.8.6_react@17.0.2 + '@mui/x-date-pickers': 5.0.0-alpha.1_a27cws6df4ygyi4adk5k5wbyme clsx: 1.1.1 date-fns: 2.28.0 prop-types: 15.8.1 @@ -3840,8 +3840,8 @@ packages: react-transition-group: 4.4.2_sfoxds7t5ydpegc3knd667wn6m dev: false - /@mui/private-theming/5.8.0_react@17.0.2: - resolution: {integrity: sha512-MjRAneTmCKLR9u2S4jtjLUe6gpHxlbb4g2bqpDJ2PdwlvwsWIUzbc/gVB4dvccljXeWxr5G2M/Co2blXisvFIw==} + /@mui/private-theming/5.8.6_react@17.0.2: + resolution: {integrity: sha512-yHsJk1qU9r/q0DlnxGRJPHyM0Y/nUv8FTNgDTiI9I58GWuVuZqeTUr7JRvPh6ybeP/FLtW5eXEavRK9wxVk4uQ==} engines: {node: '>=12.0.0'} peerDependencies: '@types/react': ^17.0.0 || ^18.0.0 @@ -3851,7 +3851,7 @@ packages: optional: true dependencies: '@babel/runtime': 7.17.9 - '@mui/utils': 5.8.0_react@17.0.2 + '@mui/utils': 5.8.6_react@17.0.2 prop-types: 15.8.1 react: 17.0.2 dev: false @@ -3877,8 +3877,8 @@ packages: react: 17.0.2 dev: false - /@mui/system/5.8.2_bgqmsvm4hz6izcmpcwescmz73y: - resolution: {integrity: sha512-N74gDNKM+MnWvKTMmCPvCVLH4f0ZzakP1bcMDaPctrHwcyxNcEmtTGNpIiVk0Iu7vtThZAFL3DjHpINPGF7+cg==} + /@mui/system/5.8.3_bgqmsvm4hz6izcmpcwescmz73y: + resolution: {integrity: sha512-/tyGQcYqZT0nl98qV9XnGiedTO+V7VHc28k4POfhMJNedB1CRrwWRm767DeEdc5f/8CU2See3WD16ikP6pYiOA==} engines: {node: '>=12.0.0'} peerDependencies: '@emotion/react': ^11.5.0 @@ -3896,18 +3896,18 @@ packages: '@babel/runtime': 7.17.9 '@emotion/react': 11.9.0_3dj5wppwohj5ocihzt4m54mr2a '@emotion/styled': 11.8.1_3zgpe2oef7sbs566rsy6a7qm7i - '@mui/private-theming': 5.8.0_react@17.0.2 + '@mui/private-theming': 5.8.6_react@17.0.2 '@mui/styled-engine': 5.8.0_bgqmsvm4hz6izcmpcwescmz73y - '@mui/types': 7.1.3 - '@mui/utils': 5.8.0_react@17.0.2 + '@mui/types': 7.1.4 + '@mui/utils': 5.8.6_react@17.0.2 clsx: 1.1.1 csstype: 3.1.0 prop-types: 15.8.1 react: 17.0.2 dev: false - /@mui/system/5.8.3_bgqmsvm4hz6izcmpcwescmz73y: - resolution: {integrity: sha512-/tyGQcYqZT0nl98qV9XnGiedTO+V7VHc28k4POfhMJNedB1CRrwWRm767DeEdc5f/8CU2See3WD16ikP6pYiOA==} + /@mui/system/5.8.6_bgqmsvm4hz6izcmpcwescmz73y: + resolution: {integrity: sha512-+a+rD58XltKQHDrrjcuCta2cUBqdnLDUDwnphSLCMFigRl8/uk+R+fdQRlMNRXAOgnMb8ioWIgfjxri5pmTH4A==} engines: {node: '>=12.0.0'} peerDependencies: '@emotion/react': ^11.5.0 @@ -3925,10 +3925,10 @@ packages: '@babel/runtime': 7.17.9 '@emotion/react': 11.9.0_3dj5wppwohj5ocihzt4m54mr2a '@emotion/styled': 11.8.1_3zgpe2oef7sbs566rsy6a7qm7i - '@mui/private-theming': 5.8.0_react@17.0.2 + '@mui/private-theming': 5.8.6_react@17.0.2 '@mui/styled-engine': 5.8.0_bgqmsvm4hz6izcmpcwescmz73y - '@mui/types': 7.1.3 - '@mui/utils': 5.8.0_react@17.0.2 + '@mui/types': 7.1.4 + '@mui/utils': 5.8.6_react@17.0.2 clsx: 1.1.1 csstype: 3.1.0 prop-types: 15.8.1 @@ -3944,6 +3944,15 @@ packages: optional: true dev: false + /@mui/types/7.1.4: + resolution: {integrity: sha512-uveM3byMbthO+6tXZ1n2zm0W3uJCQYtwt/v5zV5I77v2v18u0ITkb8xwhsDD2i3V2Kye7SaNR6FFJ6lMuY/WqQ==} + peerDependencies: + '@types/react': '*' + peerDependenciesMeta: + '@types/react': + optional: true + dev: false + /@mui/utils/5.8.0_react@17.0.2: resolution: {integrity: sha512-7LgUtCvz78676iC0wpTH7HizMdCrTphhBmRWimIMFrp5Ph6JbDFVuKS1CwYnWWxRyYKL0QzXrDL0lptAU90EXg==} engines: {node: '>=12.0.0'} @@ -3958,7 +3967,21 @@ packages: react-is: 17.0.2 dev: false - /@mui/x-date-pickers/5.0.0-alpha.1_oapnwsljl22olbjazwqgrmnl5y: + /@mui/utils/5.8.6_react@17.0.2: + resolution: {integrity: sha512-QM2Sd1xZo2jOt2Vz5Rmro+pi2FLJyiv4+OjxkUwXR3oUM65KSMAMLl/KNYU55s3W3DLRFP5MVwE4FhAbHseHAg==} + engines: {node: '>=12.0.0'} + peerDependencies: + react: ^17.0.0 || ^18.0.0 + dependencies: + '@babel/runtime': 7.17.9 + '@types/prop-types': 15.7.5 + '@types/react-is': 17.0.3 + prop-types: 15.8.1 + react: 17.0.2 + react-is: 17.0.2 + dev: false + + /@mui/x-date-pickers/5.0.0-alpha.1_a27cws6df4ygyi4adk5k5wbyme: resolution: {integrity: sha512-dLPkRiIn2Gr0momblxiOnIwrxn4SijVix+8e08mwAGWhiWcmWep1O9XTRDpZsjB0kjHYCf+kZjlRX4dxnj2acg==} engines: {node: '>=12.0.0'} peerDependencies: @@ -3985,8 +4008,8 @@ packages: '@date-io/luxon': 2.13.1 '@date-io/moment': 2.13.1 '@mui/material': 5.8.3_rikzftoujo3cmwul4lespwcm6i - '@mui/system': 5.8.2_bgqmsvm4hz6izcmpcwescmz73y - '@mui/utils': 5.8.0_react@17.0.2 + '@mui/system': 5.8.6_bgqmsvm4hz6izcmpcwescmz73y + '@mui/utils': 5.8.6_react@17.0.2 clsx: 1.1.1 date-fns: 2.28.0 prop-types: 15.8.1 @@ -4742,27 +4765,6 @@ packages: regenerator-runtime: 0.13.9 dev: true - /@storybook/addons/6.5.7_sfoxds7t5ydpegc3knd667wn6m: - resolution: {integrity: sha512-tUZ2c1uegUcwY31ztNQZGU/HUwAEEGIR8fEOvvO8S0TNQGoo6cwFtZmWBh3mTSRGcmzK2SNBjFHZua5Ee9TefA==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - dependencies: - '@storybook/api': 6.5.7_sfoxds7t5ydpegc3knd667wn6m - '@storybook/channels': 6.5.7 - '@storybook/client-logger': 6.5.7 - '@storybook/core-events': 6.5.7 - '@storybook/csf': 0.0.2--canary.4566f4d.1 - '@storybook/router': 6.5.7_sfoxds7t5ydpegc3knd667wn6m - '@storybook/theming': 6.5.7_sfoxds7t5ydpegc3knd667wn6m - '@types/webpack-env': 1.16.4 - core-js: 3.22.2 - global: 4.4.0 - react: 17.0.2 - react-dom: 17.0.2_react@17.0.2 - regenerator-runtime: 0.13.9 - dev: true - /@storybook/addons/6.5.8_sfoxds7t5ydpegc3knd667wn6m: resolution: {integrity: sha512-L3LmbsYP9tDHHvpr/yv8YuEkzym7SXp/jZ0km31tpG3EuZmgGu7MXPrZ2ymEw4PkAhQzztgRr23VTfKobGUojA==} peerDependencies: @@ -4838,33 +4840,6 @@ packages: util-deprecate: 1.0.2 dev: true - /@storybook/api/6.5.7_sfoxds7t5ydpegc3knd667wn6m: - resolution: {integrity: sha512-QCNypz4X+lYuFW7EzvRPXMf8uS3gfSIV8sqXtEe5XoMb0HQXhy6AGU7/4iAeuUimtETqLTxq+kOxaSg4uPowxg==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - dependencies: - '@storybook/channels': 6.5.7 - '@storybook/client-logger': 6.5.7 - '@storybook/core-events': 6.5.7 - '@storybook/csf': 0.0.2--canary.4566f4d.1 - '@storybook/router': 6.5.7_sfoxds7t5ydpegc3knd667wn6m - '@storybook/semver': 7.3.2 - '@storybook/theming': 6.5.7_sfoxds7t5ydpegc3knd667wn6m - core-js: 3.22.2 - fast-deep-equal: 3.1.3 - global: 4.4.0 - lodash: 4.17.21 - memoizerific: 1.11.3 - react: 17.0.2 - react-dom: 17.0.2_react@17.0.2 - regenerator-runtime: 0.13.9 - store2: 2.13.2 - telejson: 6.0.8 - ts-dedent: 2.2.0 - util-deprecate: 1.0.2 - dev: true - /@storybook/api/6.5.8_sfoxds7t5ydpegc3knd667wn6m: resolution: {integrity: sha512-/MueV+wLCvy9gFA3ih4g7QYjDmn14i+D2ydonfaEC7R+agFGXxXwJGPKkz3yBNrRpNkBwcbY9mAmv8lE2AqgqQ==} peerDependencies: @@ -4892,7 +4867,7 @@ packages: util-deprecate: 1.0.2 dev: true - /@storybook/builder-vite/0.1.35_pnlipthttc4nbyqborp4alalnm: + /@storybook/builder-vite/0.1.35_7xrp3utzqsruae7fycgzt5z3ri: resolution: {integrity: sha512-QEVbfEH/wXHSh1i/Nz8Ox+YDn6Y2OOpHrOa+GsuJG/Oej+WErYDVnBxN8HrfNyc02bzksH8NsML8yZDBLQPccA==} peerDependencies: '@storybook/core-common': '>=6.4.3 || >=6.5.0-alpha.0' @@ -4901,9 +4876,9 @@ packages: dependencies: '@joshwooding/vite-plugin-react-docgen-typescript': 0.0.4_eelqgipz77p4uwpsmgyr3mvhpm '@mdx-js/mdx': 1.6.22 - '@storybook/core-common': 6.5.5_k26rfrdk2uh2ao3d3jcmn6wejm + '@storybook/core-common': 6.5.8_k26rfrdk2uh2ao3d3jcmn6wejm '@storybook/csf-tools': 6.4.22 - '@storybook/node-logger': 6.5.5 + '@storybook/node-logger': 6.5.8 '@storybook/source-loader': 6.5.5_sfoxds7t5ydpegc3knd667wn6m '@vitejs/plugin-react': 1.3.2 ast-types: 0.14.2 @@ -5003,18 +4978,6 @@ packages: telejson: 6.0.8 dev: true - /@storybook/channel-postmessage/6.5.7: - resolution: {integrity: sha512-X4UPgm4O0503CsSnqAM1ht/6R9ofnoMcqFZxYRu9PSvHlhaFR9V9AU4VjQhakH7alFzRsAhcAV2PFVTAdWhgtA==} - dependencies: - '@storybook/channels': 6.5.7 - '@storybook/client-logger': 6.5.7 - '@storybook/core-events': 6.5.7 - core-js: 3.22.2 - global: 4.4.0 - qs: 6.10.3 - telejson: 6.0.8 - dev: true - /@storybook/channel-postmessage/6.5.8: resolution: {integrity: sha512-6IkIKk+UMYKk05vN8gWHvvOV/EZNXpQG/5gesGDALjkCyvRmcktHak1a9tHpoihZ3L7/gDwXOZraCZmuy8vBcQ==} dependencies: @@ -5053,14 +5016,6 @@ packages: util-deprecate: 1.0.2 dev: true - /@storybook/channels/6.5.7: - resolution: {integrity: sha512-v880fWBpWgiWrDmZesTIstNfMZhrPfgXAtLNcL5Z89NAPahsHskOSszc0BDxKN3gb+ZeTKUqHxY57dQdp+1rhg==} - dependencies: - core-js: 3.22.2 - ts-dedent: 2.2.0 - util-deprecate: 1.0.2 - dev: true - /@storybook/channels/6.5.8: resolution: {integrity: sha512-fNql1lEIvWlI1NiRtwFMWOOvfW6qxgeSP6xoqiAJ0b+QYegEFG9UxJDuEvVHq++S81FulgQ5U+p+5R9XSV19tQ==} dependencies: @@ -5069,36 +5024,6 @@ packages: util-deprecate: 1.0.2 dev: true - /@storybook/client-api/6.5.7_sfoxds7t5ydpegc3knd667wn6m: - resolution: {integrity: sha512-na8NZhB6GnAGp3jRTV9wwue3WGwSZoi5jfxrKSYMPL/s/2n07/soixHggqueBDXuNBrPoJaXbY/nRHmSjLwxtQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - dependencies: - '@storybook/addons': 6.5.7_sfoxds7t5ydpegc3knd667wn6m - '@storybook/channel-postmessage': 6.5.7 - '@storybook/channels': 6.5.7 - '@storybook/client-logger': 6.5.7 - '@storybook/core-events': 6.5.7 - '@storybook/csf': 0.0.2--canary.4566f4d.1 - '@storybook/store': 6.5.7_sfoxds7t5ydpegc3knd667wn6m - '@types/qs': 6.9.7 - '@types/webpack-env': 1.16.4 - core-js: 3.22.2 - fast-deep-equal: 3.1.3 - global: 4.4.0 - lodash: 4.17.21 - memoizerific: 1.11.3 - qs: 6.10.3 - react: 17.0.2 - react-dom: 17.0.2_react@17.0.2 - regenerator-runtime: 0.13.9 - store2: 2.13.2 - synchronous-promise: 2.0.15 - ts-dedent: 2.2.0 - util-deprecate: 1.0.2 - dev: true - /@storybook/client-api/6.5.8_sfoxds7t5ydpegc3knd667wn6m: resolution: {integrity: sha512-mdU+qQ4+T2OUbEnl+3MWRKxEPju/EOIUg66hMgmif8c5u7YFYBFulUMUYLICMjll8Jlu+37+g+qO3K2eEz6CEw==} peerDependencies: @@ -5143,13 +5068,6 @@ packages: global: 4.4.0 dev: true - /@storybook/client-logger/6.5.7: - resolution: {integrity: sha512-ycDy1kXeXRg3djSTXRGMVxc0kvaWw/UhHDs2VGFmOPScsoeWpdbePHXJMFbsqippxuexpsofqTryBwH2b6BPhw==} - dependencies: - core-js: 3.22.2 - global: 4.4.0 - dev: true - /@storybook/client-logger/6.5.8: resolution: {integrity: sha512-dH6HSaVuOIMHy1+rpsqcD3SJxVZEEbuEtsNpdUGwLJaIuduhUJJpM2xQfUW0siZDyrgwoa+znll+G0YNUbv7sg==} dependencies: @@ -5386,12 +5304,6 @@ packages: core-js: 3.22.2 dev: true - /@storybook/core-events/6.5.7: - resolution: {integrity: sha512-epqYy67Ypry5QdCt7FpN57/X9uuS7R2+DLFORZIpL/SJG1dIdN4POQ1icWOhPzHl+eiSgaV7e2oPaUsN+LPhJQ==} - dependencies: - core-js: 3.22.2 - dev: true - /@storybook/core-events/6.5.8: resolution: {integrity: sha512-lzG4Lg65WFYvjs2k/E3CP4+eyPexEGrDyRMO9Pbj9H9x+eosYptauEbT/wXF83bmUWZKLWWVUAZX7hDcxBO8cw==} dependencies: @@ -5912,19 +5824,6 @@ packages: regenerator-runtime: 0.13.9 dev: true - /@storybook/router/6.5.7_sfoxds7t5ydpegc3knd667wn6m: - resolution: {integrity: sha512-edWEdAb8O0rSgdXoBZDDuNlQg2cOmC/nJ6gXj9zBotzmXqsbxWyjKGooG1dU6dnKshUqE1RmWF7/N1WMluLf0A==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - dependencies: - '@storybook/client-logger': 6.5.7 - core-js: 3.22.2 - react: 17.0.2 - react-dom: 17.0.2_react@17.0.2 - regenerator-runtime: 0.13.9 - dev: true - /@storybook/router/6.5.8_sfoxds7t5ydpegc3knd667wn6m: resolution: {integrity: sha512-tseNJpZ2ZzVYowjekUMpGJVVRMrwOkttieD9mRbHrhh+2n7b+SoMKnuLi3ow0xeOyPL8ZDng2FgRjQzQHXA5Sw==} peerDependencies: @@ -5992,31 +5891,6 @@ packages: util-deprecate: 1.0.2 dev: true - /@storybook/store/6.5.7_sfoxds7t5ydpegc3knd667wn6m: - resolution: {integrity: sha512-d64towcdylC6TXNL2oJklCpwN3XcUGgZzQ9zgoV8BUlOlsj9tNq8eo95uzTURnLg1Q5uHoDDKWuXrrKj03HHxw==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - dependencies: - '@storybook/addons': 6.5.7_sfoxds7t5ydpegc3knd667wn6m - '@storybook/client-logger': 6.5.7 - '@storybook/core-events': 6.5.7 - '@storybook/csf': 0.0.2--canary.4566f4d.1 - core-js: 3.22.2 - fast-deep-equal: 3.1.3 - global: 4.4.0 - lodash: 4.17.21 - memoizerific: 1.11.3 - react: 17.0.2 - react-dom: 17.0.2_react@17.0.2 - regenerator-runtime: 0.13.9 - slash: 3.0.0 - stable: 0.1.8 - synchronous-promise: 2.0.15 - ts-dedent: 2.2.0 - util-deprecate: 1.0.2 - dev: true - /@storybook/store/6.5.8_sfoxds7t5ydpegc3knd667wn6m: resolution: {integrity: sha512-5rhGjN/O0oLebRv947B0vgapq48qBBBYYOgq4krRUYU2ecS6LUgtAHR/kTa324o9aBO8cnIXHH78jZcSvMiJlQ==} peerDependencies: @@ -6082,7 +5956,7 @@ packages: - react-dom dev: true - /@storybook/testing-react/1.3.0_zosetbroh6lpsz2fq5auzg6cxe: + /@storybook/testing-react/1.3.0_arewo4uagrgfv3hckbnzjw6rsy: resolution: {integrity: sha512-TfxzflxwBHSPhetWKuYt239t+1iN8gnnUN8OKo5UGtwwirghKQlApjH23QXW6j8YBqFhmq+yP29Oqf8HgKCFLw==} engines: {node: '>=10'} peerDependencies: @@ -6092,10 +5966,10 @@ packages: '@storybook/react': '>=6.4.0' react: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: - '@storybook/addons': 6.5.5_sfoxds7t5ydpegc3knd667wn6m - '@storybook/client-api': 6.5.7_sfoxds7t5ydpegc3knd667wn6m + '@storybook/addons': 6.5.8_sfoxds7t5ydpegc3knd667wn6m + '@storybook/client-api': 6.5.8_sfoxds7t5ydpegc3knd667wn6m '@storybook/csf': 0.0.2--canary.87bc651.0 - '@storybook/preview-web': 6.5.5_sfoxds7t5ydpegc3knd667wn6m + '@storybook/preview-web': 6.5.8_sfoxds7t5ydpegc3knd667wn6m '@storybook/react': 6.5.8_oocfzwtuyqxgsjuquyuluqp3ji react: 17.0.2 dev: true @@ -6135,19 +6009,6 @@ packages: regenerator-runtime: 0.13.9 dev: true - /@storybook/theming/6.5.7_sfoxds7t5ydpegc3knd667wn6m: - resolution: {integrity: sha512-6zp1V84DSBcS8BtFOCJlF2/nIonjQmr+dILPxaM3lCm/X003i2jAQrBKTfPlmzCeDn07PBhzHaRJ3wJskfmeNw==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - dependencies: - '@storybook/client-logger': 6.5.7 - core-js: 3.22.2 - react: 17.0.2 - react-dom: 17.0.2_react@17.0.2 - regenerator-runtime: 0.13.9 - dev: true - /@storybook/theming/6.5.8_sfoxds7t5ydpegc3knd667wn6m: resolution: {integrity: sha512-1VaKHqj38Ls1bJwDpg3+aEOlvVib/DCFkP6WYrP/AQtNAzxiyw5WkaoRlTVJZvCdu5TxjpG4O6/Ai5TI9QftIg==} peerDependencies: @@ -12965,8 +12826,8 @@ packages: - encoding dev: true - /happy-dom/5.3.1: - resolution: {integrity: sha512-zVb0VUIK73lMZR4e9ntaEQSRTf8/Rrz9MlO2VQMOn68aZAC3qoMPS/81Rkfva4vMR+bKXDqkeHiw7HumvvBmag==} + /happy-dom/6.0.0: + resolution: {integrity: sha512-Nk+hyCemZGIyQ0gDLyb6K1PFOHepfec101dG93z5g8+LIYSUZWT3FDzWUIUwfYkcAnaRCM9hMDgmR2pFLUYE9w==} dependencies: css.escape: 1.5.1 he: 1.2.0