feat: binding

This commit is contained in:
三咲智子 Kevin Deng 2023-11-23 23:42:08 +08:00
parent 717aad275d
commit 1d2f66e111
No known key found for this signature in database
GPG Key ID: 69992F2250DFD93E
13 changed files with 496 additions and 114 deletions

View File

@ -0,0 +1,5 @@
{
"semi": false,
"singleQuote": true,
"trailingComma": "all"
}

View File

@ -1,27 +1,79 @@
import { import {
CodegenContext, CodegenContext,
CodegenOptions, CodegenOptions,
CodegenResult CodegenResult,
} from '@vue/compiler-dom' } from '@vue/compiler-dom'
import { RootIRNode } from './transform' import { DynamicChildren, IRNodeTypes, RootIRNode } from './transform'
// IR -> JS codegen // IR -> JS codegen
export function generate( export function generate(
ast: RootIRNode, ir: RootIRNode,
options: CodegenOptions & { options: CodegenOptions & {
onContextCreated?: (context: CodegenContext) => void onContextCreated?: (context: CodegenContext) => void
} = {} } = {},
): CodegenResult { ): CodegenResult {
let code = '' 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 const isSetupInlined = !!options.inline
preamble += ast.template preamble += ir.template
.map((template, i) => `const t${i} = template(\`${template.template}\`)\n`) .map((template, i) => `const t${i} = template(\`${template.template}\`)\n`)
.join('') .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' code += 'return root'
const functionName = options.ssr ? `ssrRender` : `render` const functionName = options.ssr ? `ssrRender` : `render`
@ -33,7 +85,22 @@ export function generate(
return { return {
code, code,
ast: ast as any, ast: ir as any,
preamble 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
}

View File

@ -1,17 +1,25 @@
import { import {
type NodeTypes,
RootNode, RootNode,
Node,
TemplateChildNode, TemplateChildNode,
ElementNode, ElementNode,
AttributeNode, AttributeNode,
SourceLocation, SourceLocation,
NodeTypes,
InterpolationNode, InterpolationNode,
TransformOptions TransformOptions,
DirectiveNode,
} from '@vue/compiler-dom' } from '@vue/compiler-dom'
export const enum IRNodeTypes { export const enum IRNodeTypes {
ROOT, ROOT,
TEMPLATE_GENERATOR TEMPLATE_GENERATOR,
SET_PROP,
SET_TEXT,
SET_EVENT,
INSERT_NODE,
TEXT_NODE,
} }
export interface IRNode { export interface IRNode {
@ -22,6 +30,9 @@ export interface IRNode {
export interface RootIRNode extends IRNode { export interface RootIRNode extends IRNode {
type: IRNodeTypes.ROOT type: IRNodeTypes.ROOT
template: Array<TemplateGeneratorIRNode> template: Array<TemplateGeneratorIRNode>
children: DynamicChildren
effect: Record<string, EffectNode[]>
opration: OprationNode[]
helpers: Set<string> helpers: Set<string>
} }
@ -30,89 +41,349 @@ export interface TemplateGeneratorIRNode extends IRNode {
template: string 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 // AST -> IR
export function transform( export function transform(
root: RootNode, root: RootNode,
options: TransformOptions = {} options: TransformOptions = {},
): RootIRNode { ): RootIRNode {
const template = transformChildren(root.children) // {
// type: IRNodeTypes.TEMPLATE_GENERATOR,
// template,
// loc: root.loc
// }
return { const ir: RootIRNode = {
type: IRNodeTypes.ROOT, type: IRNodeTypes.ROOT,
loc: root.loc, loc: root.loc,
template: [ template: [],
{ children: {},
type: IRNodeTypes.TEMPLATE_GENERATOR, effect: Object.create(null),
template, opration: [],
loc: root.loc helpers: new Set(['template']),
}
],
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[]) { function transformChildren(
let template: string = '' ctx: TransformContext<RootNode | ElementNode>,
children.forEach((child, i) => walkNode(child)) root?: boolean,
return template ) {
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) { switch (node.type) {
case 1 satisfies NodeTypes.ELEMENT: { case 1 satisfies NodeTypes.ELEMENT: {
template += transformElement(node) transformElement(child as TransformContext<ElementNode>)
break break
} }
case 2 satisfies NodeTypes.TEXT: case 2 satisfies NodeTypes.TEXT: {
template += node.content ctx.template += node.content
break break
case 3 satisfies NodeTypes.COMMENT: }
template += `<!--${node.content}-->` case 3 satisfies NodeTypes.COMMENT: {
ctx.template += `<!--${node.content}-->`
break break
case 5 satisfies NodeTypes.INTERPOLATION: }
template += transformInterpolation(node) case 5 satisfies NodeTypes.INTERPOLATION: {
transformInterpolation(
child as TransformContext<InterpolationNode>,
isFirst,
isLast,
)
break break
// case 12 satisfies NodeTypes.TEXT_CALL: }
// template += node.content default: {
default: ctx.template += `[type: ${node.type}]`
template += `[${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) { function transformElement(ctx: TransformContext<ElementNode>) {
// TODO const { node } = ctx
if (node.content.type === (4 satisfies NodeTypes.SIMPLE_EXPRESSION)) {
return `{{ ${node.content.content} }}`
}
return '[EXP]'
// return `{{${node.content.content}}}`
}
function transformElement(node: ElementNode) {
const { tag, props, children } = node 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 ctx.template += `<${tag}`
template += `>`
props.forEach((prop) => transformProp(prop, ctx))
ctx.template += node.isSelfClosing ? '/>' : `>`
if (children.length > 0) { if (children.length > 0) {
template += transformChildren(children) 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)) {
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
}
// TODO
}
function transformProp(
node: DirectiveNode | AttributeNode,
ctx: TransformContext<ElementNode>,
): void {
const { name } = node
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) { function processExpression(ctx: TransformContext, expr: string) {
const { name, value } = prop if (ctx.options.bindingMetadata?.[expr] === 'setup-ref') {
if (value) return `${name}="${value.content}"` expr += '.value'
return name }
return expr
} }

View File

@ -1,2 +1,8 @@
export { template } from './template' 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)]) }
}

View File

@ -0,0 +1,8 @@
export const on = (
el: any,
event: string,
handler: () => any,
options?: EventListenerOptions
) => {
el.addEventListener(event, handler, options)
}

View File

@ -29,11 +29,22 @@ export function normalizeContainer(container: string | ParentNode): ParentNode {
: container : container
} }
export const enum InsertPosition {
FIRST,
LAST
}
export function insert( export function insert(
block: Block, block: Block,
parent: ParentNode, 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 (!isHydrating) {
if (block instanceof Node) { if (block instanceof Node) {
parent.insertBefore(block, anchor) parent.insertBefore(block, anchor)

View File

@ -11,6 +11,7 @@
"enableNonBrowserBranches": true "enableNonBrowserBranches": true
}, },
"dependencies": { "dependencies": {
"@vue/compiler-vapor": "workspace:^",
"monaco-editor": "^0.44.0", "monaco-editor": "^0.44.0",
"source-map-js": "^1.0.2" "source-map-js": "^1.0.2"
} }

View File

@ -1,5 +1,6 @@
import * as m from 'monaco-editor' 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 { compile as ssrCompile } from '@vue/compiler-ssr'
import { import {
defaultOptions, defaultOptions,
@ -92,8 +93,8 @@ window.init = () => {
console.log(`AST: `, ast) console.log(`AST: `, ast)
console.log(`Options: `, toRaw(compilerOptions)) console.log(`Options: `, toRaw(compilerOptions))
lastSuccessfulCode = code + `\n\n// Check the console for the AST` lastSuccessfulCode = code + `\n\n// Check the console for the AST`
lastSuccessfulMap = new SourceMapConsumer(map!) // lastSuccessfulMap = new SourceMapConsumer(map!)
lastSuccessfulMap!.computeColumnSpans() // lastSuccessfulMap!.computeColumnSpans()
} catch (e: any) { } catch (e: any) {
lastSuccessfulCode = `/* ERROR: ${e.message} (see console for more info) */` lastSuccessfulCode = `/* ERROR: ${e.message} (see console for more info) */`
console.error(e) console.error(e)

View File

@ -10,8 +10,8 @@
"vue": "workspace:*" "vue": "workspace:*"
}, },
"devDependencies": { "devDependencies": {
"@vitejs/plugin-vue": "^4.4.0", "@vitejs/plugin-vue": "link:/Users/kevin/Developer/open-source/vite-plugin-vue/packages/plugin-vue",
"vite": "^4.5.0", "vite": "^5.0.2",
"vite-plugin-inspect": "^0.7.42" "vite-plugin-inspect": "^0.7.42"
} }
} }

View File

@ -1,14 +1,31 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue' import { ref, computed } from 'vue'
const count = ref(0) 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> </script>
<template> <template>
<div> <div>
<h1 class="red">Hello world</h1> <h1 class="red">Counter</h1>
<!-- {{ count }} --> <div>The number is {{ count }}.</div>
<button style="font-weight: bold">Inc</button> <div>{{ count }} * 2 = {{ double }}</div>
<div style="display: flex; gap: 8px">
<button @click="inc">inc</button>
<button @click="dec">dec</button>
</div>
</div> </div>
</template> </template>
@ -16,4 +33,10 @@ const count = ref(0)
.red { .red {
color: red; color: red;
} }
html {
color-scheme: dark;
background-color: #000;
padding: 10px;
}
</style> </style>

View File

@ -1,5 +1,8 @@
import { render } from 'vue/vapor' import { render } from 'vue/vapor'
import App from './App.vue' import App from './App.vue'
// @ts-expect-error render(() => {
render(App.render, '#app') // @ts-expect-error
const returned = App.setup({}, { expose() {} })
return App.render(returned)
}, '#app')

View File

@ -7,8 +7,10 @@ export default defineConfig({
build: { build: {
target: 'esnext' target: 'esnext'
}, },
clearScreen: false,
plugins: [ plugins: [
Vue({ Vue({
isProduction: true,
template: { template: {
compiler: CompilerVapor compiler: CompilerVapor
} }

View File

@ -395,6 +395,9 @@ importers:
packages/template-explorer: packages/template-explorer:
dependencies: dependencies:
'@vue/compiler-vapor':
specifier: workspace:^
version: link:../compiler-vapor
monaco-editor: monaco-editor:
specifier: ^0.44.0 specifier: ^0.44.0
version: 0.44.0 version: 0.44.0
@ -451,14 +454,14 @@ importers:
version: link:../packages/vue version: link:../packages/vue
devDependencies: devDependencies:
'@vitejs/plugin-vue': '@vitejs/plugin-vue':
specifier: ^4.4.0 specifier: link:/Users/kevin/Developer/open-source/vite-plugin-vue/packages/plugin-vue
version: 4.4.0(vite@4.5.0)(vue@packages+vue) version: link:../../../vite-plugin-vue/packages/plugin-vue
vite: vite:
specifier: ^4.5.0 specifier: ^5.0.2
version: 4.5.0(@types/node@20.9.0)(terser@5.22.0) version: 5.0.2(@types/node@20.9.0)(terser@5.22.0)
vite-plugin-inspect: vite-plugin-inspect:
specifier: ^0.7.42 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: packages:
@ -1728,17 +1731,6 @@ packages:
resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
dev: true 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): /@vitejs/plugin-vue@4.4.0(vite@5.0.0)(vue@packages+vue):
resolution: {integrity: sha512-xdguqb+VUwiRpSg+nsc2HtbAUSGak25DXYvpQQi4RVU1Xq1uworyoH/md9Rfd8zMmPR/pSghr309QNcftUVseg==} resolution: {integrity: sha512-xdguqb+VUwiRpSg+nsc2HtbAUSGak25DXYvpQQi4RVU1Xq1uworyoH/md9Rfd8zMmPR/pSghr309QNcftUVseg==}
engines: {node: ^14.18.0 || >=16.0.0} engines: {node: ^14.18.0 || >=16.0.0}
@ -5337,14 +5329,6 @@ packages:
rollup: 4.1.4 rollup: 4.1.4
dev: true 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: /rollup@4.1.4:
resolution: {integrity: sha512-U8Yk1lQRKqCkDBip/pMYT+IKaN7b7UesK3fLSTuHBoBJacCE+oBqo/dfG/gkUdQNNB2OBmRP98cn2C2bkYZkyw==} resolution: {integrity: sha512-U8Yk1lQRKqCkDBip/pMYT+IKaN7b7UesK3fLSTuHBoBJacCE+oBqo/dfG/gkUdQNNB2OBmRP98cn2C2bkYZkyw==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'} engines: {node: '>=18.0.0', npm: '>=8.0.0'}
@ -6187,7 +6171,7 @@ packages:
mlly: 1.4.2 mlly: 1.4.2
pathe: 1.1.1 pathe: 1.1.1
picocolors: 1.0.0 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: transitivePeerDependencies:
- '@types/node' - '@types/node'
- less - less
@ -6199,7 +6183,7 @@ packages:
- terser - terser
dev: true 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==} resolution: {integrity: sha512-JCyX86wr3siQc+p9Kd0t8VkFHAJag0RaQVIpdFGSv5FEaePEVB6+V/RGtz2dQkkGSXQzRWrPs4cU3dRKg32bXw==}
engines: {node: '>=14'} engines: {node: '>=14'}
peerDependencies: peerDependencies:
@ -6217,18 +6201,18 @@ packages:
open: 9.1.0 open: 9.1.0
picocolors: 1.0.0 picocolors: 1.0.0
sirv: 2.0.3 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: transitivePeerDependencies:
- rollup - rollup
- supports-color - supports-color
dev: true dev: true
/vite@4.5.0(@types/node@20.9.0)(terser@5.22.0): /vite@5.0.0(@types/node@20.9.0)(terser@5.22.0):
resolution: {integrity: sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==} resolution: {integrity: sha512-ESJVM59mdyGpsiNAeHQOR/0fqNoOyWPYesFto8FFZugfmhdHx8Fzd8sF3Q/xkVhZsyOxHfdM7ieiVAorI9RjFw==}
engines: {node: ^14.18.0 || >=16.0.0} engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
'@types/node': '>= 14' '@types/node': ^18.0.0 || >=20.0.0
less: '*' less: '*'
lightningcss: ^1.21.0 lightningcss: ^1.21.0
sass: '*' sass: '*'
@ -6252,16 +6236,16 @@ packages:
optional: true optional: true
dependencies: dependencies:
'@types/node': 20.9.0 '@types/node': 20.9.0
esbuild: 0.18.20 esbuild: 0.19.5
postcss: 8.4.31 postcss: 8.4.31
rollup: 3.29.4 rollup: 4.4.1
terser: 5.22.0 terser: 5.22.0
optionalDependencies: optionalDependencies:
fsevents: 2.3.3 fsevents: 2.3.3
dev: true dev: true
/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):
resolution: {integrity: sha512-ESJVM59mdyGpsiNAeHQOR/0fqNoOyWPYesFto8FFZugfmhdHx8Fzd8sF3Q/xkVhZsyOxHfdM7ieiVAorI9RjFw==} resolution: {integrity: sha512-6CCq1CAJCNM1ya2ZZA7+jS2KgnhbzvxakmlIjN24cF/PXhRMzpM/z8QgsVJA/Dm5fWUWnVEsmtBoMhmerPxT0g==}
engines: {node: ^18.0.0 || >=20.0.0} engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true hasBin: true
peerDependencies: peerDependencies: