From 1d2f66e1119a76cdc9db174d3fe561f21f025c6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E6=99=BA=E5=AD=90=20Kevin=20Deng?= Date: Thu, 23 Nov 2023 23:42:08 +0800 Subject: [PATCH] feat: binding --- packages/compiler-vapor/.prettierrc | 5 + packages/compiler-vapor/src/generate.ts | 85 ++++- packages/compiler-vapor/src/transform.ts | 385 +++++++++++++++++++---- packages/runtime-vapor/src/index.ts | 8 +- packages/runtime-vapor/src/on.ts | 8 + packages/runtime-vapor/src/render.ts | 13 +- packages/template-explorer/package.json | 1 + packages/template-explorer/src/index.ts | 7 +- playground/package.json | 4 +- playground/src/App.vue | 31 +- playground/src/main.ts | 7 +- playground/vite.config.ts | 2 + pnpm-lock.yaml | 54 ++-- 13 files changed, 496 insertions(+), 114 deletions(-) create mode 100644 packages/compiler-vapor/.prettierrc create mode 100644 packages/runtime-vapor/src/on.ts diff --git a/packages/compiler-vapor/.prettierrc b/packages/compiler-vapor/.prettierrc new file mode 100644 index 000000000..e3b414c7e --- /dev/null +++ b/packages/compiler-vapor/.prettierrc @@ -0,0 +1,5 @@ +{ + "semi": false, + "singleQuote": true, + "trailingComma": "all" +} diff --git a/packages/compiler-vapor/src/generate.ts b/packages/compiler-vapor/src/generate.ts index 9a22ad031..d809d093c 100644 --- a/packages/compiler-vapor/src/generate.ts +++ b/packages/compiler-vapor/src/generate.ts @@ -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 +} diff --git a/packages/compiler-vapor/src/transform.ts b/packages/compiler-vapor/src/transform.ts index 56795bec5..35f1d1b6c 100644 --- a/packages/compiler-vapor/src/transform.ts +++ b/packages/compiler-vapor/src/transform.ts @@ -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 + children: DynamicChildren + effect: Record + opration: OprationNode[] helpers: Set } @@ -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 + +export interface TransformContext { + node: T + parent: TransformContext | null + root: TransformContext + 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 { + let i = 0 + const { effect: bindings } = ir + + const ctx: TransformContext = { + 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( + node: T, + parent: TransformContext, + index: number, +): TransformContext { + let id: number | undefined + const getElementId = () => { + if (id !== undefined) return id + return (id = parent.root.getElementId()) + } + const children = {} + + const ctx: TransformContext = { + ...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, + 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) 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 += `` + } + case 3 satisfies NodeTypes.COMMENT: { + ctx.template += `` break - case 5 satisfies NodeTypes.INTERPOLATION: - template += transformInterpolation(node) + } + case 5 satisfies NodeTypes.INTERPOLATION: { + transformInterpolation( + child as TransformContext, + 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 - if (node.content.type === (4 satisfies NodeTypes.SIMPLE_EXPRESSION)) { - return `{{ ${node.content.content} }}` - } - return '[EXP]' - // return `{{${node.content.content}}}` -} - -function transformElement(node: ElementNode) { +function transformElement(ctx: TransformContext) { + const { node } = ctx 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 += `>` + ctx.template += `<${tag}` + + props.forEach((prop) => transformProp(prop, ctx)) + ctx.template += node.isSelfClosing ? '/>' : `>` if (children.length > 0) { - template += transformChildren(children) + transformChildren(ctx) + } + if (!node.isSelfClosing) ctx.template += `` +} + +function transformInterpolation( + ctx: TransformContext, + 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, +): 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 += `` + 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 } diff --git a/packages/runtime-vapor/src/index.ts b/packages/runtime-vapor/src/index.ts index 9ee740276..a46041a60 100644 --- a/packages/runtime-vapor/src/index.ts +++ b/packages/runtime-vapor/src/index.ts @@ -1,2 +1,8 @@ export { template } from './template' -export { render } from './render' +export * from './render' +export * from './on' + +type Children = Record +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 index 000000000..a1502a800 --- /dev/null +++ b/packages/runtime-vapor/src/on.ts @@ -0,0 +1,8 @@ +export const on = ( + el: any, + event: string, + handler: () => any, + options?: EventListenerOptions +) => { + el.addEventListener(event, handler, options) +} diff --git a/packages/runtime-vapor/src/render.ts b/packages/runtime-vapor/src/render.ts index 857c5c1a0..07208d601 100644 --- a/packages/runtime-vapor/src/render.ts +++ b/packages/runtime-vapor/src/render.ts @@ -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) diff --git a/packages/template-explorer/package.json b/packages/template-explorer/package.json index 351768f60..03742fad8 100644 --- a/packages/template-explorer/package.json +++ b/packages/template-explorer/package.json @@ -11,6 +11,7 @@ "enableNonBrowserBranches": true }, "dependencies": { + "@vue/compiler-vapor": "workspace:^", "monaco-editor": "^0.44.0", "source-map-js": "^1.0.2" } diff --git a/packages/template-explorer/src/index.ts b/packages/template-explorer/src/index.ts index 9faeb0a59..08258514e 100644 --- a/packages/template-explorer/src/index.ts +++ b/packages/template-explorer/src/index.ts @@ -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) diff --git a/playground/package.json b/playground/package.json index c920827d5..175acdc39 100644 --- a/playground/package.json +++ b/playground/package.json @@ -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" } } diff --git a/playground/src/App.vue b/playground/src/App.vue index cb9bd26c9..9497d5bdb 100644 --- a/playground/src/App.vue +++ b/playground/src/App.vue @@ -1,14 +1,31 @@ @@ -16,4 +33,10 @@ const count = ref(0) .red { color: red; } + +html { + color-scheme: dark; + background-color: #000; + padding: 10px; +} diff --git a/playground/src/main.ts b/playground/src/main.ts index 69485dcbe..3fa636f9d 100644 --- a/playground/src/main.ts +++ b/playground/src/main.ts @@ -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') diff --git a/playground/vite.config.ts b/playground/vite.config.ts index bbd8c6cd8..db2fba3a1 100644 --- a/playground/vite.config.ts +++ b/playground/vite.config.ts @@ -7,8 +7,10 @@ export default defineConfig({ build: { target: 'esnext' }, + clearScreen: false, plugins: [ Vue({ + isProduction: true, template: { compiler: CompilerVapor } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8294fcf2d..0d915476f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -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: