]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
feat: binding
author三咲智子 Kevin Deng <sxzz@sxzz.moe>
Thu, 23 Nov 2023 15:42:08 +0000 (23:42 +0800)
committer三咲智子 Kevin Deng <sxzz@sxzz.moe>
Thu, 23 Nov 2023 15:42:16 +0000 (23:42 +0800)
13 files changed:
packages/compiler-vapor/.prettierrc [new file with mode: 0644]
packages/compiler-vapor/src/generate.ts
packages/compiler-vapor/src/transform.ts
packages/runtime-vapor/src/index.ts
packages/runtime-vapor/src/on.ts [new file with mode: 0644]
packages/runtime-vapor/src/render.ts
packages/template-explorer/package.json
packages/template-explorer/src/index.ts
playground/package.json
playground/src/App.vue
playground/src/main.ts
playground/vite.config.ts
pnpm-lock.yaml

diff --git a/packages/compiler-vapor/.prettierrc b/packages/compiler-vapor/.prettierrc
new file mode 100644 (file)
index 0000000..e3b414c
--- /dev/null
@@ -0,0 +1,5 @@
+{
+  "semi": false,
+  "singleQuote": true,
+  "trailingComma": "all"
+}
index 9a22ad0310211b1993cacfcaea10bab0886655b8..d809d093ce8beda8823496f827d479d8cbb9154f 100644 (file)
@@ -1,27 +1,79 @@
 import {
   CodegenContext,
   CodegenOptions,
-  CodegenResult
+  CodegenResult,
 } from '@vue/compiler-dom'
-import { RootIRNode } from './transform'
+import { DynamicChildren, IRNodeTypes, RootIRNode } from './transform'
 
 // IR -> JS codegen
 export function generate(
-  ast: RootIRNode,
+  ir: RootIRNode,
   options: CodegenOptions & {
     onContextCreated?: (context: CodegenContext) => void
-  } = {}
+  } = {},
 ): CodegenResult {
   let code = ''
-  let preamble = "import { template } from 'vue/vapor'\n"
+  let preamble = `import { watchEffect } from 'vue'
+import { template, setAttr, setText, children, on, insert } from 'vue/vapor'\n`
 
   const isSetupInlined = !!options.inline
 
-  preamble += ast.template
+  preamble += ir.template
     .map((template, i) => `const t${i} = template(\`${template.template}\`)\n`)
     .join('')
 
-  code += 'const root = t0()\n'
+  code += `const root = t0()\n`
+
+  if (ir.children[0]) {
+    code += `const {${genChildrens(
+      ir.children[0].children,
+    )}} = children(root)\n`
+  }
+
+  for (const opration of ir.opration) {
+    switch (opration.type) {
+      case IRNodeTypes.TEXT_NODE: {
+        code += `const n${opration.id} = document.createTextNode(${opration.content})\n`
+        break
+      }
+
+      case IRNodeTypes.INSERT_NODE:
+        {
+          let anchor = ''
+          if (typeof opration.anchor === 'number') {
+            anchor = `, n${opration.anchor}`
+          } else if (opration.anchor === 'first') {
+            anchor = `, 0 /* InsertPosition.FIRST */`
+          }
+          code += `insert(n${opration.element}, n${opration.parent}${anchor})\n`
+        }
+        break
+    }
+  }
+
+  for (const [expr, effects] of Object.entries(ir.effect)) {
+    let scope = `watchEffect(() => {\n`
+    for (const effect of effects) {
+      switch (effect.type) {
+        case IRNodeTypes.SET_PROP:
+          scope += `setAttr(n${effect.element}, ${JSON.stringify(
+            effect.name,
+          )}, undefined, ${expr})\n`
+          break
+        case IRNodeTypes.SET_TEXT:
+          scope += `setText(n${effect.element}, undefined, ${expr})\n`
+          break
+        case IRNodeTypes.SET_EVENT:
+          scope += `on(n${effect.element}, ${JSON.stringify(
+            effect.name,
+          )}, ${expr})\n`
+          break
+      }
+    }
+    scope += '})\n'
+    code += scope
+  }
+
   code += 'return root'
 
   const functionName = options.ssr ? `ssrRender` : `render`
@@ -33,7 +85,22 @@ export function generate(
 
   return {
     code,
-    ast: ast as any,
-    preamble
+    ast: ir as any,
+    preamble,
+  }
+}
+
+function genChildrens(children: DynamicChildren) {
+  let str = ''
+  for (const [index, child] of Object.entries(children)) {
+    str += ` ${index}: [`
+    if (child.store) {
+      str += `n${child.id}`
+    }
+    if (Object.keys(child.children).length) {
+      str += `, {${genChildrens(child.children)}}`
+    }
+    str += '],'
   }
+  return str
 }
index 56795bec50c94723d933ee53764f7a22ade2dd38..35f1d1b6cc8776ccaad8c14e2385d0fc5a61d728 100644 (file)
@@ -1,17 +1,25 @@
 import {
+  type NodeTypes,
   RootNode,
+  Node,
   TemplateChildNode,
   ElementNode,
   AttributeNode,
   SourceLocation,
-  NodeTypes,
   InterpolationNode,
-  TransformOptions
+  TransformOptions,
+  DirectiveNode,
 } from '@vue/compiler-dom'
 
 export const enum IRNodeTypes {
   ROOT,
-  TEMPLATE_GENERATOR
+  TEMPLATE_GENERATOR,
+  SET_PROP,
+  SET_TEXT,
+  SET_EVENT,
+
+  INSERT_NODE,
+  TEXT_NODE,
 }
 
 export interface IRNode {
@@ -22,6 +30,9 @@ export interface IRNode {
 export interface RootIRNode extends IRNode {
   type: IRNodeTypes.ROOT
   template: Array<TemplateGeneratorIRNode>
+  children: DynamicChildren
+  effect: Record<string, EffectNode[]>
+  opration: OprationNode[]
   helpers: Set<string>
 }
 
@@ -30,89 +41,349 @@ export interface TemplateGeneratorIRNode extends IRNode {
   template: string
 }
 
+export interface SetPropIRNode extends IRNode {
+  type: IRNodeTypes.SET_PROP
+  element: number
+  name: string
+}
+
+export interface SetTextIRNode extends IRNode {
+  type: IRNodeTypes.SET_TEXT
+  element: number
+}
+
+export interface SetEventIRNode extends IRNode {
+  type: IRNodeTypes.SET_EVENT
+  element: number
+  name: string
+}
+
+export interface TextNodeIRNode extends IRNode {
+  type: IRNodeTypes.TEXT_NODE
+  id: number
+  content: string
+}
+
+export interface InsertNodeIRNode extends IRNode {
+  type: IRNodeTypes.INSERT_NODE
+  element: number
+  parent: number
+  anchor: number | 'first' | 'last'
+}
+
+export type EffectNode = SetPropIRNode | SetTextIRNode | SetEventIRNode
+export type OprationNode = TextNodeIRNode | InsertNodeIRNode
+
+export interface DynamicChild {
+  id: number | null
+  store: boolean
+  children: DynamicChildren
+}
+export type DynamicChildren = Record<number, DynamicChild>
+
+export interface TransformContext<T extends Node = Node> {
+  node: T
+  parent: TransformContext | null
+  root: TransformContext<RootNode>
+  index: number
+  options: TransformOptions
+  ir: RootIRNode
+  template: string
+  children: DynamicChildren
+  store: boolean
+  ghost: boolean
+
+  getElementId(): number
+  registerEffect(expr: string, effectNode: EffectNode): void
+  registerTemplate(): number
+}
+
+function createRootContext(
+  ir: RootIRNode,
+  node: RootNode,
+  options: TransformOptions,
+): TransformContext<RootNode> {
+  let i = 0
+  const { effect: bindings } = ir
+
+  const ctx: TransformContext<RootNode> = {
+    node,
+    parent: null,
+    index: 0,
+    root: undefined as any, // set later
+    options,
+    ir,
+    children: {},
+    store: false,
+    ghost: false,
+
+    getElementId: () => i++,
+    registerEffect(expr, effectNode) {
+      if (!bindings[expr]) bindings[expr] = []
+      bindings[expr].push(effectNode)
+    },
+
+    template: '',
+    registerTemplate() {
+      if (!ctx.template) return -1
+
+      const idx = ir.template.findIndex((t) => t.template === ctx.template)
+      if (idx !== -1) return idx
+
+      ir.template.push({
+        type: IRNodeTypes.TEMPLATE_GENERATOR,
+        template: ctx.template,
+        loc: node.loc,
+      })
+      return ir.template.length - 1
+    },
+  }
+  ctx.root = ctx
+  return ctx
+}
+
+function createContext<T extends TemplateChildNode>(
+  node: T,
+  parent: TransformContext,
+  index: number,
+): TransformContext<T> {
+  let id: number | undefined
+  const getElementId = () => {
+    if (id !== undefined) return id
+    return (id = parent.root.getElementId())
+  }
+  const children = {}
+
+  const ctx: TransformContext<T> = {
+    ...parent,
+    node,
+    parent,
+    index,
+    get template() {
+      return parent.template
+    },
+    set template(t) {
+      parent.template = t
+    },
+    getElementId,
+
+    children,
+    store: false,
+  }
+  return ctx
+}
+
 // AST -> IR
 export function transform(
   root: RootNode,
-  options: TransformOptions = {}
+  options: TransformOptions = {},
 ): RootIRNode {
-  const template = transformChildren(root.children)
+  // {
+  //   type: IRNodeTypes.TEMPLATE_GENERATOR,
+  //   template,
+  //   loc: root.loc
+  // }
 
-  return {
+  const ir: RootIRNode = {
     type: IRNodeTypes.ROOT,
     loc: root.loc,
-    template: [
-      {
-        type: IRNodeTypes.TEMPLATE_GENERATOR,
-        template,
-        loc: root.loc
-      }
-    ],
-    helpers: new Set(['template'])
+    template: [],
+    children: {},
+    effect: Object.create(null),
+    opration: [],
+    helpers: new Set(['template']),
   }
+  const ctx = createRootContext(ir, root, options)
+  transformChildren(ctx, true)
+  ctx.registerTemplate()
+  ir.children = ctx.children
+
+  console.log(JSON.stringify(ir, undefined, 2))
+
+  return ir
 }
 
-function transformChildren(children: TemplateChildNode[]) {
-  let template: string = ''
-  children.forEach((child, i) => walkNode(child))
-  return template
+function transformChildren(
+  ctx: TransformContext<RootNode | ElementNode>,
+  root?: boolean,
+) {
+  const {
+    node: { children },
+  } = ctx
+  let index = 0
+  children.forEach((child, i) => walkNode(child, i))
+
+  function walkNode(node: TemplateChildNode, i: number) {
+    const child = createContext(node, ctx, index)
+    const isFirst = i === 0
+    const isLast = i === children.length - 1
 
-  function walkNode(node: TemplateChildNode) {
     switch (node.type) {
       case 1 satisfies NodeTypes.ELEMENT: {
-        template += transformElement(node)
+        transformElement(child as TransformContext<ElementNode>)
         break
       }
-      case 2 satisfies NodeTypes.TEXT:
-        template += node.content
+      case 2 satisfies NodeTypes.TEXT: {
+        ctx.template += node.content
         break
-      case 3 satisfies NodeTypes.COMMENT:
-        template += `<!--${node.content}-->`
+      }
+      case 3 satisfies NodeTypes.COMMENT: {
+        ctx.template += `<!--${node.content}-->`
         break
-      case 5 satisfies NodeTypes.INTERPOLATION:
-        template += transformInterpolation(node)
+      }
+      case 5 satisfies NodeTypes.INTERPOLATION: {
+        transformInterpolation(
+          child as TransformContext<InterpolationNode>,
+          isFirst,
+          isLast,
+        )
         break
-      // case 12 satisfies NodeTypes.TEXT_CALL:
-      //   template += node.content
-      default:
-        template += `[${node.type}]`
+      }
+      default: {
+        ctx.template += `[type: ${node.type}]`
+      }
     }
+
+    if (Object.keys(child.children).length > 0 || child.store)
+      ctx.children[index] = {
+        id: child.store ? child.getElementId() : null,
+        store: child.store,
+        children: child.children,
+      }
+
+    if (!child.ghost) index++
   }
 }
 
-function transformInterpolation(node: InterpolationNode) {
-  // TODO
+function transformElement(ctx: TransformContext<ElementNode>) {
+  const { node } = ctx
+  const { tag, props, children } = node
+
+  ctx.template += `<${tag}`
+
+  props.forEach((prop) => transformProp(prop, ctx))
+  ctx.template += node.isSelfClosing ? '/>' : `>`
+
+  if (children.length > 0) {
+    transformChildren(ctx)
+  }
+  if (!node.isSelfClosing) ctx.template += `</${tag}>`
+}
+
+function transformInterpolation(
+  ctx: TransformContext<InterpolationNode>,
+  isFirst: boolean,
+  isLast: boolean,
+) {
+  const { node } = ctx
+
   if (node.content.type === (4 satisfies NodeTypes.SIMPLE_EXPRESSION)) {
-    return `{{ ${node.content.content} }}`
+    const expr = processExpression(ctx, node.content.content)
+
+    const parent = ctx.parent!
+    const parentId = parent.getElementId()
+    parent.store = true
+
+    if (isFirst && isLast) {
+      ctx.registerEffect(expr, {
+        type: IRNodeTypes.SET_TEXT,
+        loc: node.loc,
+        element: parentId,
+      })
+    } else {
+      let id: number
+      let anchor: number | 'first' | 'last'
+
+      if (!isFirst && !isLast) {
+        id = ctx.root.getElementId()
+        anchor = ctx.getElementId()
+        ctx.template += '<!>'
+        ctx.store = true
+      } else {
+        id = ctx.getElementId()
+        ctx.ghost = true
+        anchor = isFirst ? 'first' : 'last'
+      }
+
+      ctx.ir.opration.push(
+        {
+          type: IRNodeTypes.TEXT_NODE,
+          loc: node.loc,
+          id,
+          content: expr,
+        },
+        {
+          type: IRNodeTypes.INSERT_NODE,
+          loc: node.loc,
+          element: id,
+          parent: parentId,
+          anchor,
+        },
+      )
+
+      ctx.registerEffect(expr, {
+        type: IRNodeTypes.SET_TEXT,
+        loc: node.loc,
+        element: id,
+      })
+    }
+  } else {
+    // TODO
   }
-  return '[EXP]'
-  // return `{{${node.content.content}}}`
+  // TODO
 }
 
-function transformElement(node: ElementNode) {
-  const { tag, props, children } = node
-  let template = `<${tag}`
-  const propsTemplate = props
-    .filter(
-      (prop): prop is AttributeNode =>
-        prop.type === (6 satisfies NodeTypes.ATTRIBUTE)
-    )
-    .map(prop => transformProp(prop))
-    .join(' ')
-
-  if (propsTemplate) template += ' ' + propsTemplate
-  template += `>`
+function transformProp(
+  node: DirectiveNode | AttributeNode,
+  ctx: TransformContext<ElementNode>,
+): void {
+  const { name } = node
 
-  if (children.length > 0) {
-    template += transformChildren(children)
+  if (node.type === (6 satisfies NodeTypes.ATTRIBUTE)) {
+    if (node.value) {
+      ctx.template += ` ${name}="${node.value.content}"`
+    } else {
+      ctx.template += ` ${name}`
+    }
+    return
   }
 
-  template += `</${tag}>`
+  if (!node.exp) {
+    // TODO
+    return
+  } else if (node.exp.type === (8 satisfies NodeTypes.COMPOUND_EXPRESSION)) {
+    // TODO
+    return
+  } else if (
+    !node.arg ||
+    node.arg.type === (8 satisfies NodeTypes.COMPOUND_EXPRESSION)
+  ) {
+    // TODO
+    return
+  }
 
-  return template
+  const expr = processExpression(ctx, node.exp.content)
+  ctx.store = true
+  if (name === 'bind') {
+    ctx.registerEffect(expr, {
+      type: IRNodeTypes.SET_PROP,
+      loc: node.loc,
+      element: ctx.getElementId(),
+      name: node.arg.content,
+    })
+  } else if (name === 'on') {
+    ctx.registerEffect(expr, {
+      type: IRNodeTypes.SET_EVENT,
+      loc: node.loc,
+      element: ctx.getElementId(),
+      name: node.arg.content,
+    })
+  }
 }
 
-function transformProp(prop: AttributeNode) {
-  const { name, value } = prop
-  if (value) return `${name}="${value.content}"`
-  return name
+function processExpression(ctx: TransformContext, expr: string) {
+  if (ctx.options.bindingMetadata?.[expr] === 'setup-ref') {
+    expr += '.value'
+  }
+  return expr
 }
index 9ee7402761176518522727a1f0b82af1f87a7d87..a46041a60dd724c7ce099226777ac89be7bbe91e 100644 (file)
@@ -1,2 +1,8 @@
 export { template } from './template'
-export { render } from './render'
+export * from './render'
+export * from './on'
+
+type Children = Record<number, [ChildNode, Children]>
+export function children(n: ChildNode): Children {
+  return { ...Array.from(n.childNodes).map(n => [n, children(n)]) }
+}
diff --git a/packages/runtime-vapor/src/on.ts b/packages/runtime-vapor/src/on.ts
new file mode 100644 (file)
index 0000000..a1502a8
--- /dev/null
@@ -0,0 +1,8 @@
+export const on = (
+  el: any,
+  event: string,
+  handler: () => any,
+  options?: EventListenerOptions
+) => {
+  el.addEventListener(event, handler, options)
+}
index 857c5c1a0e48900d7f981daab01e794673094411..07208d601573b23f5477295debb93404192dcfbe 100644 (file)
@@ -29,11 +29,22 @@ export function normalizeContainer(container: string | ParentNode): ParentNode {
     : container
 }
 
+export const enum InsertPosition {
+  FIRST,
+  LAST
+}
+
 export function insert(
   block: Block,
   parent: ParentNode,
-  anchor: Node | null = null
+  anchor: Node | InsertPosition | null = null
 ) {
+  anchor =
+    typeof anchor === 'number'
+      ? anchor === InsertPosition.FIRST
+        ? parent.firstChild
+        : null
+      : anchor
   // if (!isHydrating) {
   if (block instanceof Node) {
     parent.insertBefore(block, anchor)
index 351768f60bbc8ea42b83dde57c2f6c3922943fe9..03742fad8be9877dd723db02bfef1d933e9c3839 100644 (file)
@@ -11,6 +11,7 @@
     "enableNonBrowserBranches": true
   },
   "dependencies": {
+    "@vue/compiler-vapor": "workspace:^",
     "monaco-editor": "^0.44.0",
     "source-map-js": "^1.0.2"
   }
index 9faeb0a59f6937a7dc1b0478ef18e62a152c7e31..08258514ea47da34f6d18b8a73b103e2d342337f 100644 (file)
@@ -1,5 +1,6 @@
 import * as m from 'monaco-editor'
-import { compile, CompilerError, CompilerOptions } from '@vue/compiler-dom'
+import { CompilerError, CompilerOptions } from '@vue/compiler-dom'
+import { compile } from '@vue/compiler-vapor'
 import { compile as ssrCompile } from '@vue/compiler-ssr'
 import {
   defaultOptions,
@@ -92,8 +93,8 @@ window.init = () => {
       console.log(`AST: `, ast)
       console.log(`Options: `, toRaw(compilerOptions))
       lastSuccessfulCode = code + `\n\n// Check the console for the AST`
-      lastSuccessfulMap = new SourceMapConsumer(map!)
-      lastSuccessfulMap!.computeColumnSpans()
+      // lastSuccessfulMap = new SourceMapConsumer(map!)
+      // lastSuccessfulMap!.computeColumnSpans()
     } catch (e: any) {
       lastSuccessfulCode = `/* ERROR: ${e.message} (see console for more info) */`
       console.error(e)
index c920827d555f20f089326f78d0099deaacc7052b..175acdc39ce68c4c42fe29195451a2519cb93f70 100644 (file)
@@ -10,8 +10,8 @@
     "vue": "workspace:*"
   },
   "devDependencies": {
-    "@vitejs/plugin-vue": "^4.4.0",
-    "vite": "^4.5.0",
+    "@vitejs/plugin-vue": "link:/Users/kevin/Developer/open-source/vite-plugin-vue/packages/plugin-vue",
+    "vite": "^5.0.2",
     "vite-plugin-inspect": "^0.7.42"
   }
 }
index cb9bd26c93737fbe1272f9e514e274a859675b5d..9497d5bdb78999918f5fb3e8485793469cd120fe 100644 (file)
@@ -1,14 +1,31 @@
 <script setup lang="ts">
-import { ref } from 'vue'
+import { ref, computed } from 'vue'
 
 const count = ref(0)
+const double = computed(() => count.value * 2)
+
+const inc = () => count.value++
+const dec = () => count.value--
+
+// @ts-expect-error
+globalThis.count = count
+// @ts-expect-error
+globalThis.double = double
+// @ts-expect-error
+globalThis.inc = inc
+// @ts-expect-error
+globalThis.dec = dec
 </script>
 
 <template>
   <div>
-    <h1 class="red">Hello world</h1>
-    <!-- {{ count }} -->
-    <button style="font-weight: bold">Inc</button>
+    <h1 class="red">Counter</h1>
+    <div>The number is {{ count }}.</div>
+    <div>{{ count }} * 2 = {{ double }}</div>
+    <div style="display: flex; gap: 8px">
+      <button @click="inc">inc</button>
+      <button @click="dec">dec</button>
+    </div>
   </div>
 </template>
 
@@ -16,4 +33,10 @@ const count = ref(0)
 .red {
   color: red;
 }
+
+html {
+  color-scheme: dark;
+  background-color: #000;
+  padding: 10px;
+}
 </style>
index 69485dcbe4b988562260b3c2125dea21d82719bc..3fa636f9deb9dacdb0de9d01637a6437680c2531 100644 (file)
@@ -1,5 +1,8 @@
 import { render } from 'vue/vapor'
 import App from './App.vue'
 
-// @ts-expect-error
-render(App.render, '#app')
+render(() => {
+  // @ts-expect-error
+  const returned = App.setup({}, { expose() {} })
+  return App.render(returned)
+}, '#app')
index bbd8c6cd83d2ac7a90f3941443119c2124077650..db2fba3a16a9a34ea9f36525210d8cf716fbccb3 100644 (file)
@@ -7,8 +7,10 @@ export default defineConfig({
   build: {
     target: 'esnext'
   },
+  clearScreen: false,
   plugins: [
     Vue({
+      isProduction: true,
       template: {
         compiler: CompilerVapor
       }
index 8294fcf2dcdf596ec50bd9b1463821dc3a6f8b8e..0d915476feecbb36e08bb7dd2c57f520b464b2ed 100644 (file)
@@ -395,6 +395,9 @@ importers:
 
   packages/template-explorer:
     dependencies:
+      '@vue/compiler-vapor':
+        specifier: workspace:^
+        version: link:../compiler-vapor
       monaco-editor:
         specifier: ^0.44.0
         version: 0.44.0
@@ -451,14 +454,14 @@ importers:
         version: link:../packages/vue
     devDependencies:
       '@vitejs/plugin-vue':
-        specifier: ^4.4.0
-        version: 4.4.0(vite@4.5.0)(vue@packages+vue)
+        specifier: link:/Users/kevin/Developer/open-source/vite-plugin-vue/packages/plugin-vue
+        version: link:../../../vite-plugin-vue/packages/plugin-vue
       vite:
-        specifier: ^4.5.0
-        version: 4.5.0(@types/node@20.9.0)(terser@5.22.0)
+        specifier: ^5.0.2
+        version: 5.0.2(@types/node@20.9.0)(terser@5.22.0)
       vite-plugin-inspect:
         specifier: ^0.7.42
-        version: 0.7.42(rollup@4.1.4)(vite@4.5.0)
+        version: 0.7.42(rollup@4.1.4)(vite@5.0.2)
 
 packages:
 
@@ -1728,17 +1731,6 @@ packages:
     resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
     dev: true
 
-  /@vitejs/plugin-vue@4.4.0(vite@4.5.0)(vue@packages+vue):
-    resolution: {integrity: sha512-xdguqb+VUwiRpSg+nsc2HtbAUSGak25DXYvpQQi4RVU1Xq1uworyoH/md9Rfd8zMmPR/pSghr309QNcftUVseg==}
-    engines: {node: ^14.18.0 || >=16.0.0}
-    peerDependencies:
-      vite: ^4.0.0
-      vue: ^3.2.25
-    dependencies:
-      vite: 4.5.0(@types/node@20.9.0)(terser@5.22.0)
-      vue: link:packages/vue
-    dev: true
-
   /@vitejs/plugin-vue@4.4.0(vite@5.0.0)(vue@packages+vue):
     resolution: {integrity: sha512-xdguqb+VUwiRpSg+nsc2HtbAUSGak25DXYvpQQi4RVU1Xq1uworyoH/md9Rfd8zMmPR/pSghr309QNcftUVseg==}
     engines: {node: ^14.18.0 || >=16.0.0}
@@ -5337,14 +5329,6 @@ packages:
       rollup: 4.1.4
     dev: true
 
-  /rollup@3.29.4:
-    resolution: {integrity: sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==}
-    engines: {node: '>=14.18.0', npm: '>=8.0.0'}
-    hasBin: true
-    optionalDependencies:
-      fsevents: 2.3.3
-    dev: true
-
   /rollup@4.1.4:
     resolution: {integrity: sha512-U8Yk1lQRKqCkDBip/pMYT+IKaN7b7UesK3fLSTuHBoBJacCE+oBqo/dfG/gkUdQNNB2OBmRP98cn2C2bkYZkyw==}
     engines: {node: '>=18.0.0', npm: '>=8.0.0'}
@@ -6187,7 +6171,7 @@ packages:
       mlly: 1.4.2
       pathe: 1.1.1
       picocolors: 1.0.0
-      vite: 5.0.0(@types/node@20.9.0)(terser@5.22.0)
+      vite: 5.0.2(@types/node@20.9.0)(terser@5.22.0)
     transitivePeerDependencies:
       - '@types/node'
       - less
@@ -6199,7 +6183,7 @@ packages:
       - terser
     dev: true
 
-  /vite-plugin-inspect@0.7.42(rollup@4.1.4)(vite@4.5.0):
+  /vite-plugin-inspect@0.7.42(rollup@4.1.4)(vite@5.0.2):
     resolution: {integrity: sha512-JCyX86wr3siQc+p9Kd0t8VkFHAJag0RaQVIpdFGSv5FEaePEVB6+V/RGtz2dQkkGSXQzRWrPs4cU3dRKg32bXw==}
     engines: {node: '>=14'}
     peerDependencies:
@@ -6217,18 +6201,18 @@ packages:
       open: 9.1.0
       picocolors: 1.0.0
       sirv: 2.0.3
-      vite: 4.5.0(@types/node@20.9.0)(terser@5.22.0)
+      vite: 5.0.2(@types/node@20.9.0)(terser@5.22.0)
     transitivePeerDependencies:
       - rollup
       - supports-color
     dev: true
 
-  /vite@4.5.0(@types/node@20.9.0)(terser@5.22.0):
-    resolution: {integrity: sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==}
-    engines: {node: ^14.18.0 || >=16.0.0}
+  /vite@5.0.0(@types/node@20.9.0)(terser@5.22.0):
+    resolution: {integrity: sha512-ESJVM59mdyGpsiNAeHQOR/0fqNoOyWPYesFto8FFZugfmhdHx8Fzd8sF3Q/xkVhZsyOxHfdM7ieiVAorI9RjFw==}
+    engines: {node: ^18.0.0 || >=20.0.0}
     hasBin: true
     peerDependencies:
-      '@types/node': '>= 14'
+      '@types/node': ^18.0.0 || >=20.0.0
       less: '*'
       lightningcss: ^1.21.0
       sass: '*'
@@ -6252,16 +6236,16 @@ packages:
         optional: true
     dependencies:
       '@types/node': 20.9.0
-      esbuild: 0.18.20
+      esbuild: 0.19.5
       postcss: 8.4.31
-      rollup: 3.29.4
+      rollup: 4.4.1
       terser: 5.22.0
     optionalDependencies:
       fsevents: 2.3.3
     dev: true
 
-  /vite@5.0.0(@types/node@20.9.0)(terser@5.22.0):
-    resolution: {integrity: sha512-ESJVM59mdyGpsiNAeHQOR/0fqNoOyWPYesFto8FFZugfmhdHx8Fzd8sF3Q/xkVhZsyOxHfdM7ieiVAorI9RjFw==}
+  /vite@5.0.2(@types/node@20.9.0)(terser@5.22.0):
+    resolution: {integrity: sha512-6CCq1CAJCNM1ya2ZZA7+jS2KgnhbzvxakmlIjN24cF/PXhRMzpM/z8QgsVJA/Dm5fWUWnVEsmtBoMhmerPxT0g==}
     engines: {node: ^18.0.0 || >=20.0.0}
     hasBin: true
     peerDependencies: