فهرست منبع

feat: scheduler

三咲智子 Kevin Deng 2 سال پیش
والد
کامیت
8b075796d7

+ 28 - 38
packages/compiler-vapor/__tests__/__snapshots__/compile.test.ts.snap

@@ -1,8 +1,7 @@
 // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
 
 exports[`comile > bindings 1`] = `
 exports[`comile > bindings 1`] = `
-"import { watchEffect } from 'vue';
-import { template, children, createTextNode, insert, setText } from 'vue/vapor';
+"import { template, children, createTextNode, insert, effect, setText } from 'vue/vapor';
 const t0 = template('<div>count is <!>.</div>');
 const t0 = template('<div>count is <!>.</div>');
 export function render() {
 export function render() {
   const n0 = t0();
   const n0 = t0();
@@ -16,7 +15,7 @@ export function render() {
   } = children(n0);
   } = children(n0);
   const n1 = createTextNode(count.value);
   const n1 = createTextNode(count.value);
   insert(n1, n3, n2);
   insert(n1, n3, n2);
-  watchEffect(() => {
+  effect(() => {
     setText(n1, undefined, count.value);
     setText(n1, undefined, count.value);
   });
   });
   return n0;
   return n0;
@@ -25,15 +24,14 @@ export function render() {
 `;
 `;
 
 
 exports[`comile > directives > v-bind > simple expression 1`] = `
 exports[`comile > directives > v-bind > simple expression 1`] = `
-"import { watchEffect } from 'vue';
-import { template, children, setAttr } from 'vue/vapor';
+"import { template, children, effect, setAttr } from 'vue/vapor';
 const t0 = template('<div></div>');
 const t0 = template('<div></div>');
 export function render() {
 export function render() {
   const n0 = t0();
   const n0 = t0();
   const {
   const {
     0: [n1],
     0: [n1],
   } = children(n0);
   } = children(n0);
-  watchEffect(() => {
+  effect(() => {
     setAttr(n1, 'id', undefined, id.value);
     setAttr(n1, 'id', undefined, id.value);
   });
   });
   return n0;
   return n0;
@@ -42,15 +40,14 @@ export function render() {
 `;
 `;
 
 
 exports[`comile > directives > v-html > no expression 1`] = `
 exports[`comile > directives > v-html > no expression 1`] = `
-"import { watchEffect } from 'vue';
-import { template, children, setHtml } from 'vue/vapor';
+"import { template, children, effect, setHtml } from 'vue/vapor';
 const t0 = template('<div></div>');
 const t0 = template('<div></div>');
 export function render() {
 export function render() {
   const n0 = t0();
   const n0 = t0();
   const {
   const {
     0: [n1],
     0: [n1],
   } = children(n0);
   } = children(n0);
-  watchEffect(() => {
+  effect(() => {
     setHtml(n1, undefined, '');
     setHtml(n1, undefined, '');
   });
   });
   return n0;
   return n0;
@@ -59,15 +56,14 @@ export function render() {
 `;
 `;
 
 
 exports[`comile > directives > v-html > simple expression 1`] = `
 exports[`comile > directives > v-html > simple expression 1`] = `
-"import { watchEffect } from 'vue';
-import { template, children, setHtml } from 'vue/vapor';
+"import { template, children, effect, setHtml } from 'vue/vapor';
 const t0 = template('<div></div>');
 const t0 = template('<div></div>');
 export function render() {
 export function render() {
   const n0 = t0();
   const n0 = t0();
   const {
   const {
     0: [n1],
     0: [n1],
   } = children(n0);
   } = children(n0);
-  watchEffect(() => {
+  effect(() => {
     setHtml(n1, undefined, code.value);
     setHtml(n1, undefined, code.value);
   });
   });
   return n0;
   return n0;
@@ -76,15 +72,14 @@ export function render() {
 `;
 `;
 
 
 exports[`comile > directives > v-on > simple expression 1`] = `
 exports[`comile > directives > v-on > simple expression 1`] = `
-"import { watchEffect } from 'vue';
-import { template, children, on } from 'vue/vapor';
+"import { template, children, effect, on } from 'vue/vapor';
 const t0 = template('<div></div>');
 const t0 = template('<div></div>');
 export function render() {
 export function render() {
   const n0 = t0();
   const n0 = t0();
   const {
   const {
     0: [n1],
     0: [n1],
   } = children(n0);
   } = children(n0);
-  watchEffect(() => {
+  effect(() => {
     on(n1, 'click', handleClick);
     on(n1, 'click', handleClick);
   });
   });
   return n0;
   return n0;
@@ -93,15 +88,14 @@ export function render() {
 `;
 `;
 
 
 exports[`comile > directives > v-once > as root node 1`] = `
 exports[`comile > directives > v-once > as root node 1`] = `
-"import { watchEffect } from 'vue';
-import { template, children, setAttr } from 'vue/vapor';
+"import { template, children, effect, setAttr } from 'vue/vapor';
 const t0 = template('<div></div>');
 const t0 = template('<div></div>');
 export function render() {
 export function render() {
   const n0 = t0();
   const n0 = t0();
   const {
   const {
     0: [n1],
     0: [n1],
   } = children(n0);
   } = children(n0);
-  watchEffect(() => {
+  effect(() => {
     setAttr(n1, 'id', undefined, foo);
     setAttr(n1, 'id', undefined, foo);
   });
   });
   return n0;
   return n0;
@@ -132,15 +126,14 @@ export function render() {
 `;
 `;
 
 
 exports[`comile > directives > v-text > no expression 1`] = `
 exports[`comile > directives > v-text > no expression 1`] = `
-"import { watchEffect } from 'vue';
-import { template, children, setText } from 'vue/vapor';
+"import { template, children, effect, setText } from 'vue/vapor';
 const t0 = template('<div></div>');
 const t0 = template('<div></div>');
 export function render() {
 export function render() {
   const n0 = t0();
   const n0 = t0();
   const {
   const {
     0: [n1],
     0: [n1],
   } = children(n0);
   } = children(n0);
-  watchEffect(() => {
+  effect(() => {
     setText(n1, undefined, '');
     setText(n1, undefined, '');
   });
   });
   return n0;
   return n0;
@@ -149,15 +142,14 @@ export function render() {
 `;
 `;
 
 
 exports[`comile > directives > v-text > simple expression 1`] = `
 exports[`comile > directives > v-text > simple expression 1`] = `
-"import { watchEffect } from 'vue';
-import { template, children, setText } from 'vue/vapor';
+"import { template, children, effect, setText } from 'vue/vapor';
 const t0 = template('<div></div>');
 const t0 = template('<div></div>');
 export function render() {
 export function render() {
   const n0 = t0();
   const n0 = t0();
   const {
   const {
     0: [n1],
     0: [n1],
   } = children(n0);
   } = children(n0);
-  watchEffect(() => {
+  effect(() => {
     setText(n1, undefined, str.value);
     setText(n1, undefined, str.value);
   });
   });
   return n0;
   return n0;
@@ -166,18 +158,17 @@ export function render() {
 `;
 `;
 
 
 exports[`comile > dynamic root 1`] = `
 exports[`comile > dynamic root 1`] = `
-"import { watchEffect } from 'vue';
-import { fragment, createTextNode, append, setText } from 'vue/vapor';
+"import { fragment, createTextNode, append, effect, setText } from 'vue/vapor';
 export function render() {
 export function render() {
   const t0 = fragment();
   const t0 = fragment();
   const n0 = t0();
   const n0 = t0();
   const n1 = createTextNode(1);
   const n1 = createTextNode(1);
   const n2 = createTextNode(2);
   const n2 = createTextNode(2);
   append(n0, n1, n2);
   append(n0, n1, n2);
-  watchEffect(() => {
+  effect(() => {
     setText(n1, undefined, 1);
     setText(n1, undefined, 1);
   });
   });
-  watchEffect(() => {
+  effect(() => {
     setText(n2, undefined, 2);
     setText(n2, undefined, 2);
   });
   });
   return n0;
   return n0;
@@ -196,8 +187,7 @@ export function render() {
 `;
 `;
 
 
 exports[`comile > static + dynamic root 1`] = `
 exports[`comile > static + dynamic root 1`] = `
-"import { watchEffect } from 'vue';
-import { template, children, createTextNode, prepend, insert, append, setText } from 'vue/vapor';
+"import { template, children, createTextNode, prepend, insert, append, effect, setText } from 'vue/vapor';
 const t0 = template('3<!>6<!>9');
 const t0 = template('3<!>6<!>9');
 export function render() {
 export function render() {
   const n0 = t0();
   const n0 = t0();
@@ -217,28 +207,28 @@ export function render() {
   insert([n3, n4], n0, n9);
   insert([n3, n4], n0, n9);
   insert([n5, n6], n0, n10);
   insert([n5, n6], n0, n10);
   append(n0, n7, n8);
   append(n0, n7, n8);
-  watchEffect(() => {
+  effect(() => {
     setText(n1, undefined, 1);
     setText(n1, undefined, 1);
   });
   });
-  watchEffect(() => {
+  effect(() => {
     setText(n2, undefined, 2);
     setText(n2, undefined, 2);
   });
   });
-  watchEffect(() => {
+  effect(() => {
     setText(n3, undefined, 4);
     setText(n3, undefined, 4);
   });
   });
-  watchEffect(() => {
+  effect(() => {
     setText(n4, undefined, 5);
     setText(n4, undefined, 5);
   });
   });
-  watchEffect(() => {
+  effect(() => {
     setText(n5, undefined, 7);
     setText(n5, undefined, 7);
   });
   });
-  watchEffect(() => {
+  effect(() => {
     setText(n6, undefined, 8);
     setText(n6, undefined, 8);
   });
   });
-  watchEffect(() => {
+  effect(() => {
     setText(n7, undefined, 'A');
     setText(n7, undefined, 'A');
   });
   });
-  watchEffect(() => {
+  effect(() => {
     setText(n8, undefined, 'B');
     setText(n8, undefined, 'B');
   });
   });
   return n0;
   return n0;

+ 5 - 6
packages/compiler-vapor/__tests__/__snapshots__/fixtures.test.ts.snap

@@ -2,8 +2,7 @@
 
 
 exports[`fixtures 1`] = `
 exports[`fixtures 1`] = `
 "import { defineComponent as _defineComponent } from 'vue'
 "import { defineComponent as _defineComponent } from 'vue'
-import { watchEffect } from 'vue'
-import { template, children, createTextNode, append, setText, on, setHtml } from 'vue/vapor'
+import { template, children, createTextNode, append, setText, effect, on, setHtml } from 'vue/vapor'
 const t0 = template(\\"<h1 id=\\\\\\"title\\\\\\">Counter</h1><p>Count: </p><p>Double: </p><button>Increment</button><div></div><input type=\\\\\\"text\\\\\\"><p>once: </p><p>{{ count }}</p>\\")
 const t0 = template(\\"<h1 id=\\\\\\"title\\\\\\">Counter</h1><p>Count: </p><p>Double: </p><button>Increment</button><div></div><input type=\\\\\\"text\\\\\\"><p>once: </p><p>{{ count }}</p>\\")
 import { ref, computed } from 'vue'
 import { ref, computed } from 'vue'
 
 
@@ -28,16 +27,16 @@ append(n4, n3)
 const n7 = createTextNode(count.value)
 const n7 = createTextNode(count.value)
 setText(n7, undefined, count.value)
 setText(n7, undefined, count.value)
 append(n8, n7)
 append(n8, n7)
-watchEffect(() => {
+effect(() => {
 setText(n1, undefined, count.value)
 setText(n1, undefined, count.value)
 })
 })
-watchEffect(() => {
+effect(() => {
 setText(n3, undefined, double.value)
 setText(n3, undefined, double.value)
 })
 })
-watchEffect(() => {
+effect(() => {
 on(n5, \\"click\\", increment)
 on(n5, \\"click\\", increment)
 })
 })
-watchEffect(() => {
+effect(() => {
 setHtml(n6, undefined, html)
 setHtml(n6, undefined, html)
 })
 })
 return n0
 return n0

+ 1 - 1
packages/compiler-vapor/__tests__/compile.test.ts

@@ -129,7 +129,7 @@ describe('comile', () => {
       test.fails('as root node', async () => {
       test.fails('as root node', async () => {
         const code = await compile(`<div :id="foo" v-once />`)
         const code = await compile(`<div :id="foo" v-once />`)
         expect(code).toMatchSnapshot()
         expect(code).toMatchSnapshot()
-        expect(code).not.contains('watchEffect')
+        expect(code).not.contains('effect')
       })
       })
     })
     })
   })
   })

+ 2 - 3
packages/compiler-vapor/src/generate.ts

@@ -45,9 +45,8 @@ export function generate(
       code += genOperation(operation)
       code += genOperation(operation)
     }
     }
     for (const [_expr, operations] of Object.entries(ir.effect)) {
     for (const [_expr, operations] of Object.entries(ir.effect)) {
-      // TODO don't use watchEffect from vue/core, implement `effect` function in runtime-vapor package
-      let scope = `watchEffect(() => {\n`
-      helpers.add('watchEffect')
+      let scope = `effect(() => {\n`
+      vaporHelpers.add('effect')
       for (const operation of operations) {
       for (const operation of operations) {
         scope += genOperation(operation)
         scope += genOperation(operation)
       }
       }

+ 4 - 2
packages/runtime-vapor/package.json

@@ -34,6 +34,8 @@
     "url": "https://github.com/vuejs/core-vapor/issues"
     "url": "https://github.com/vuejs/core-vapor/issues"
   },
   },
   "homepage": "https://github.com/vuejs/core-vapor/tree/dev/packages/runtime-vapor#readme",
   "homepage": "https://github.com/vuejs/core-vapor/tree/dev/packages/runtime-vapor#readme",
-  "dependencies": {},
-  "devDependencies": {}
+  "dependencies": {
+    "@vue/shared": "workspace:*",
+    "@vue/reactivity": "workspace:*"
+  }
 }
 }

+ 1 - 0
packages/runtime-vapor/src/index.ts

@@ -1,3 +1,4 @@
 export * from './on'
 export * from './on'
 export * from './render'
 export * from './render'
 export * from './template'
 export * from './template'
+export * from './scheduler'

+ 2 - 2
packages/runtime-vapor/src/on.ts

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

+ 4 - 4
packages/runtime-vapor/src/render.ts

@@ -1,10 +1,10 @@
 import {
 import {
-  effectScope,
   normalizeClass,
   normalizeClass,
   normalizeStyle,
   normalizeStyle,
-  toDisplayString
-} from 'vue'
-import { isArray } from '@vue/shared'
+  toDisplayString,
+  isArray
+} from '@vue/shared'
+import { effectScope } from '@vue/reactivity'
 
 
 export type Block = Node | Fragment | Block[]
 export type Block = Node | Fragment | Block[]
 export type ParentBlock = ParentNode | Node[]
 export type ParentBlock = ParentNode | Node[]

+ 30 - 0
packages/runtime-vapor/src/scheduler.ts

@@ -0,0 +1,30 @@
+import { ReactiveEffect } from '@vue/reactivity'
+
+const p = Promise.resolve()
+
+let queued: any[] | undefined
+
+const queue = (fn: any) => {
+  if (!queued) {
+    queued = [fn]
+    p.then(flush)
+  } else {
+    queued.push(fn)
+  }
+}
+
+function flush() {
+  for (let i = 0; i < queued!.length; i++) {
+    queued![i]()
+  }
+  queued = undefined
+}
+
+export const nextTick = (fn: any) => p.then(fn)
+
+export const effect = (fn: any) => {
+  let run: () => void
+  const e = new ReactiveEffect(fn, () => queue(run))
+  run = e.run.bind(e)
+  run()
+}

+ 8 - 1
pnpm-lock.yaml

@@ -348,7 +348,14 @@ importers:
         specifier: workspace:*
         specifier: workspace:*
         version: link:../shared
         version: link:../shared
 
 
-  packages/runtime-vapor: {}
+  packages/runtime-vapor:
+    dependencies:
+      '@vue/reactivity':
+        specifier: workspace:*
+        version: link:../reactivity
+      '@vue/shared':
+        specifier: workspace:*
+        version: link:../shared
 
 
   packages/server-renderer:
   packages/server-renderer:
     dependencies:
     dependencies: