]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
feat: scheduler
author三咲智子 Kevin Deng <sxzz@sxzz.moe>
Mon, 27 Nov 2023 15:47:21 +0000 (23:47 +0800)
committer三咲智子 Kevin Deng <sxzz@sxzz.moe>
Mon, 27 Nov 2023 15:48:36 +0000 (23:48 +0800)
packages/compiler-vapor/__tests__/__snapshots__/compile.test.ts.snap
packages/compiler-vapor/__tests__/__snapshots__/fixtures.test.ts.snap
packages/compiler-vapor/__tests__/compile.test.ts
packages/compiler-vapor/src/generate.ts
packages/runtime-vapor/package.json
packages/runtime-vapor/src/index.ts
packages/runtime-vapor/src/on.ts
packages/runtime-vapor/src/render.ts
packages/runtime-vapor/src/scheduler.ts [new file with mode: 0644]
pnpm-lock.yaml

index da4d0ad4c3da3c407ba34dff470a5f82f478e2a8..9ad83079a027d28a1eb0f3256f4ec8ab0dcad487 100644 (file)
@@ -1,8 +1,7 @@
 // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
 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>');
 export function render() {
   const n0 = t0();
@@ -16,7 +15,7 @@ export function render() {
   } = children(n0);
   const n1 = createTextNode(count.value);
   insert(n1, n3, n2);
-  watchEffect(() => {
+  effect(() => {
     setText(n1, undefined, count.value);
   });
   return n0;
@@ -25,15 +24,14 @@ export function render() {
 `;
 
 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>');
 export function render() {
   const n0 = t0();
   const {
     0: [n1],
   } = children(n0);
-  watchEffect(() => {
+  effect(() => {
     setAttr(n1, 'id', undefined, id.value);
   });
   return n0;
@@ -42,15 +40,14 @@ export function render() {
 `;
 
 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>');
 export function render() {
   const n0 = t0();
   const {
     0: [n1],
   } = children(n0);
-  watchEffect(() => {
+  effect(() => {
     setHtml(n1, undefined, '');
   });
   return n0;
@@ -59,15 +56,14 @@ export function render() {
 `;
 
 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>');
 export function render() {
   const n0 = t0();
   const {
     0: [n1],
   } = children(n0);
-  watchEffect(() => {
+  effect(() => {
     setHtml(n1, undefined, code.value);
   });
   return n0;
@@ -76,15 +72,14 @@ export function render() {
 `;
 
 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>');
 export function render() {
   const n0 = t0();
   const {
     0: [n1],
   } = children(n0);
-  watchEffect(() => {
+  effect(() => {
     on(n1, 'click', handleClick);
   });
   return n0;
@@ -93,15 +88,14 @@ export function render() {
 `;
 
 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>');
 export function render() {
   const n0 = t0();
   const {
     0: [n1],
   } = children(n0);
-  watchEffect(() => {
+  effect(() => {
     setAttr(n1, 'id', undefined, foo);
   });
   return n0;
@@ -132,15 +126,14 @@ export function render() {
 `;
 
 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>');
 export function render() {
   const n0 = t0();
   const {
     0: [n1],
   } = children(n0);
-  watchEffect(() => {
+  effect(() => {
     setText(n1, undefined, '');
   });
   return n0;
@@ -149,15 +142,14 @@ export function render() {
 `;
 
 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>');
 export function render() {
   const n0 = t0();
   const {
     0: [n1],
   } = children(n0);
-  watchEffect(() => {
+  effect(() => {
     setText(n1, undefined, str.value);
   });
   return n0;
@@ -166,18 +158,17 @@ export function render() {
 `;
 
 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() {
   const t0 = fragment();
   const n0 = t0();
   const n1 = createTextNode(1);
   const n2 = createTextNode(2);
   append(n0, n1, n2);
-  watchEffect(() => {
+  effect(() => {
     setText(n1, undefined, 1);
   });
-  watchEffect(() => {
+  effect(() => {
     setText(n2, undefined, 2);
   });
   return n0;
@@ -196,8 +187,7 @@ export function render() {
 `;
 
 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');
 export function render() {
   const n0 = t0();
@@ -217,28 +207,28 @@ export function render() {
   insert([n3, n4], n0, n9);
   insert([n5, n6], n0, n10);
   append(n0, n7, n8);
-  watchEffect(() => {
+  effect(() => {
     setText(n1, undefined, 1);
   });
-  watchEffect(() => {
+  effect(() => {
     setText(n2, undefined, 2);
   });
-  watchEffect(() => {
+  effect(() => {
     setText(n3, undefined, 4);
   });
-  watchEffect(() => {
+  effect(() => {
     setText(n4, undefined, 5);
   });
-  watchEffect(() => {
+  effect(() => {
     setText(n5, undefined, 7);
   });
-  watchEffect(() => {
+  effect(() => {
     setText(n6, undefined, 8);
   });
-  watchEffect(() => {
+  effect(() => {
     setText(n7, undefined, 'A');
   });
-  watchEffect(() => {
+  effect(() => {
     setText(n8, undefined, 'B');
   });
   return n0;
index f90d49cf64952267dea9ad09718667253699b673..f2e8a3f9987113efce1db095b316768ff130559e 100644 (file)
@@ -2,8 +2,7 @@
 
 exports[`fixtures 1`] = `
 "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>\\")
 import { ref, computed } from 'vue'
 
@@ -28,16 +27,16 @@ append(n4, n3)
 const n7 = createTextNode(count.value)
 setText(n7, undefined, count.value)
 append(n8, n7)
-watchEffect(() => {
+effect(() => {
 setText(n1, undefined, count.value)
 })
-watchEffect(() => {
+effect(() => {
 setText(n3, undefined, double.value)
 })
-watchEffect(() => {
+effect(() => {
 on(n5, \\"click\\", increment)
 })
-watchEffect(() => {
+effect(() => {
 setHtml(n6, undefined, html)
 })
 return n0
index 979bb094f2c7ffc8ec7044a6d2e911715f8b0cfd..7d0c1d774f882c36aa93d6d38c921e92be59f2a5 100644 (file)
@@ -129,7 +129,7 @@ describe('comile', () => {
       test.fails('as root node', async () => {
         const code = await compile(`<div :id="foo" v-once />`)
         expect(code).toMatchSnapshot()
-        expect(code).not.contains('watchEffect')
+        expect(code).not.contains('effect')
       })
     })
   })
index f87f5fab51ddb8c1408dab7fce4891016b6f490a..0af9d764bc0b6b66c775d21aafaccd0271a863f5 100644 (file)
@@ -45,9 +45,8 @@ export function generate(
       code += genOperation(operation)
     }
     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) {
         scope += genOperation(operation)
       }
index 7015bd1674fcabc664b4edfc9cb1c102981de16a..a2f218cbf07755baebe92eadc543e3440f24297c 100644 (file)
@@ -34,6 +34,8 @@
     "url": "https://github.com/vuejs/core-vapor/issues"
   },
   "homepage": "https://github.com/vuejs/core-vapor/tree/dev/packages/runtime-vapor#readme",
-  "dependencies": {},
-  "devDependencies": {}
+  "dependencies": {
+    "@vue/shared": "workspace:*",
+    "@vue/reactivity": "workspace:*"
+  }
 }
index 8553412a3e0d72f302ea6d62fa597d5c0c7ffad6..d6c95e4376c1fefe5286eeee915e30144c5fc448 100644 (file)
@@ -1,3 +1,4 @@
 export * from './on'
 export * from './render'
 export * from './template'
+export * from './scheduler'
index a1502a800da0b99eceb9d9283c67f7c7ba969d45..d4192b35405d69eed55dbf765112073b6b90fef7 100644 (file)
@@ -1,8 +1,8 @@
-export const on = (
+export function on(
   el: any,
   event: string,
   handler: () => any,
   options?: EventListenerOptions
-) => {
+) {
   el.addEventListener(event, handler, options)
 }
index ed276c356586556873a53c7c05ba9248f96ee24c..a120412fe92e1dd1a7a38b45e3395810210a08c4 100644 (file)
@@ -1,10 +1,10 @@
 import {
-  effectScope,
   normalizeClass,
   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 ParentBlock = ParentNode | Node[]
diff --git a/packages/runtime-vapor/src/scheduler.ts b/packages/runtime-vapor/src/scheduler.ts
new file mode 100644 (file)
index 0000000..1af662e
--- /dev/null
@@ -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()
+}
index 4496dfcd983207733dce42287d8c10498810e1ad..ef2662c4766f1f3898b9f8da257a5cb0a28c69b4 100644 (file)
@@ -348,7 +348,14 @@ importers:
         specifier: workspace:*
         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:
     dependencies: