Merge branch 'main' into feat/reactiveity-transform-shorthands

This commit is contained in:
Anthony Fu 2022-08-19 23:12:17 +08:00
commit d1d594aad3
19 changed files with 225 additions and 210 deletions

View File

@ -93,7 +93,7 @@
"todomvc-app-css": "^2.3.0", "todomvc-app-css": "^2.3.0",
"ts-jest": "^27.0.5", "ts-jest": "^27.0.5",
"tslib": "^2.4.0", "tslib": "^2.4.0",
"typescript": "^4.6.4", "typescript": "^4.7.4",
"vite": "^2.9.8", "vite": "^2.9.8",
"vue": "workspace:*", "vue": "workspace:*",
"yorkie": "^2.0.0" "yorkie": "^2.0.0"

View File

@ -480,21 +480,27 @@ describe('reactivity/readonly', () => {
const r = ref(false) const r = ref(false)
const ror = readonly(r) const ror = readonly(r)
const obj = reactive({ ror }) const obj = reactive({ ror })
try { expect(() => {
obj.ror = true obj.ror = true
} catch (e) {} }).toThrow()
expect(obj.ror).toBe(false) expect(obj.ror).toBe(false)
}) })
test('replacing a readonly ref nested in a reactive object with a new ref', () => { test('replacing a readonly ref nested in a reactive object with a new ref', () => {
const r = ref(false) const r = ref(false)
const ror = readonly(r) const ror = readonly(r)
const obj = reactive({ ror }) const obj = reactive({ ror })
try {
obj.ror = ref(true) as unknown as boolean obj.ror = ref(true) as unknown as boolean
} catch (e) {}
expect(obj.ror).toBe(true) expect(obj.ror).toBe(true)
expect(toRaw(obj).ror).not.toBe(ror) // ref successfully replaced expect(toRaw(obj).ror).not.toBe(ror) // ref successfully replaced
}) })
test('setting readonly object to writable nested ref', () => {
const r = ref<any>()
const obj = reactive({ r })
const ro = readonly({})
obj.r = ro
expect(obj.r).toBe(ro)
expect(r.value).toBe(ro)
})
}) })

View File

@ -10,7 +10,7 @@ import {
} from '../src/index' } from '../src/index'
import { computed } from '@vue/runtime-dom' import { computed } from '@vue/runtime-dom'
import { shallowRef, unref, customRef, triggerRef } from '../src/ref' import { shallowRef, unref, customRef, triggerRef } from '../src/ref'
import { isShallow } from '../src/reactive' import { isShallow, readonly, shallowReactive } from '../src/reactive'
describe('reactivity/ref', () => { describe('reactivity/ref', () => {
it('should hold a value', () => { it('should hold a value', () => {
@ -400,4 +400,22 @@ describe('reactivity/ref', () => {
b.value = obj b.value = obj
expect(spy2).toBeCalledTimes(1) expect(spy2).toBeCalledTimes(1)
}) })
test('ref should preserve value shallow/readonly-ness', () => {
const original = {}
const r = reactive(original)
const s = shallowReactive(original)
const rr = readonly(original)
const a = ref(original)
expect(a.value).toBe(r)
a.value = s
expect(a.value).toBe(s)
expect(a.value).not.toBe(r)
a.value = rr
expect(a.value).toBe(rr)
expect(a.value).not.toBe(r)
})
}) })

View File

@ -7,6 +7,7 @@ import {
} from '../src/reactive' } from '../src/reactive'
import { effect } from '../src/effect' import { effect } from '../src/effect'
import { Ref, isRef, ref } from '../src/ref'
describe('shallowReactive', () => { describe('shallowReactive', () => {
test('should not make non-reactive properties reactive', () => { test('should not make non-reactive properties reactive', () => {
@ -46,6 +47,27 @@ describe('shallowReactive', () => {
expect(isReactive(r.foo.bar)).toBe(false) expect(isReactive(r.foo.bar)).toBe(false)
}) })
// vuejs/vue#12597
test('should not unwrap refs', () => {
const foo = shallowReactive({
bar: ref(123)
})
expect(isRef(foo.bar)).toBe(true)
expect(foo.bar.value).toBe(123)
})
// vuejs/vue#12688
test('should not mutate refs', () => {
const original = ref(123)
const foo = shallowReactive<{ bar: Ref<number> | number }>({
bar: original
})
expect(foo.bar).toBe(original)
foo.bar = 234
expect(foo.bar).toBe(234)
expect(original.value).toBe(123)
})
test('should respect shallow/deep versions of same target on access', () => { test('should respect shallow/deep versions of same target on access', () => {
const original = {} const original = {}
const shallow = shallowReactive(original) const shallow = shallowReactive(original)

View File

@ -158,10 +158,10 @@ function createSetter(shallow = false) {
if (isReadonly(oldValue) && isRef(oldValue) && !isRef(value)) { if (isReadonly(oldValue) && isRef(oldValue) && !isRef(value)) {
return false return false
} }
if (!shallow && !isReadonly(value)) { if (!shallow) {
if (!isShallow(value)) { if (!isShallow(value) && !isReadonly(value)) {
value = toRaw(value)
oldValue = toRaw(oldValue) oldValue = toRaw(oldValue)
value = toRaw(value)
} }
if (!isArray(target) && isRef(oldValue) && !isRef(value)) { if (!isArray(target) && isRef(oldValue) && !isRef(value)) {
oldValue.value = value oldValue.value = value

View File

@ -30,7 +30,7 @@ export class ComputedRefImpl<T> {
public readonly effect: ReactiveEffect<T> public readonly effect: ReactiveEffect<T>
public readonly __v_isRef = true public readonly __v_isRef = true
public readonly [ReactiveFlags.IS_READONLY]: boolean public readonly [ReactiveFlags.IS_READONLY]: boolean = false
public _dirty = true public _dirty = true
public _cacheable: boolean public _cacheable: boolean

View File

@ -6,7 +6,14 @@ import {
} from './effect' } from './effect'
import { TrackOpTypes, TriggerOpTypes } from './operations' import { TrackOpTypes, TriggerOpTypes } from './operations'
import { isArray, hasChanged, IfAny } from '@vue/shared' import { isArray, hasChanged, IfAny } from '@vue/shared'
import { isProxy, toRaw, isReactive, toReactive } from './reactive' import {
isProxy,
toRaw,
isReactive,
toReactive,
isReadonly,
isShallow
} from './reactive'
import type { ShallowReactiveMarker } from './reactive' import type { ShallowReactiveMarker } from './reactive'
import { CollectionTypes } from './collectionHandlers' import { CollectionTypes } from './collectionHandlers'
import { createDep, Dep } from './dep' import { createDep, Dep } from './dep'
@ -112,10 +119,12 @@ class RefImpl<T> {
} }
set value(newVal) { set value(newVal) {
newVal = this.__v_isShallow ? newVal : toRaw(newVal) const useDirectValue =
this.__v_isShallow || isShallow(newVal) || isReadonly(newVal)
newVal = useDirectValue ? newVal : toRaw(newVal)
if (hasChanged(newVal, this._rawValue)) { if (hasChanged(newVal, this._rawValue)) {
this._rawValue = newVal this._rawValue = newVal
this._value = this.__v_isShallow ? newVal : toReactive(newVal) this._value = useDirectValue ? newVal : toReactive(newVal)
triggerRefValue(this, newVal) triggerRefValue(this, newVal)
} }
} }

View File

@ -509,7 +509,8 @@ describe('api: watch', () => {
expect(cb).not.toHaveBeenCalled() expect(cb).not.toHaveBeenCalled()
}) })
it('should fire on component unmount w/ flush: pre', async () => { // #2291
it('should not fire on component unmount w/ flush: pre', async () => {
const toggle = ref(true) const toggle = ref(true)
const cb = jest.fn() const cb = jest.fn()
const Comp = { const Comp = {
@ -527,7 +528,7 @@ describe('api: watch', () => {
expect(cb).not.toHaveBeenCalled() expect(cb).not.toHaveBeenCalled()
toggle.value = false toggle.value = false
await nextTick() await nextTick()
expect(cb).toHaveBeenCalledTimes(1) expect(cb).not.toHaveBeenCalled()
}) })
// #1763 // #1763

View File

@ -3,9 +3,8 @@ import {
nextTick, nextTick,
queuePostFlushCb, queuePostFlushCb,
invalidateJob, invalidateJob,
queuePreFlushCb, flushPostFlushCbs,
flushPreFlushCbs, flushPreFlushCbs
flushPostFlushCbs
} from '../src/scheduler' } from '../src/scheduler'
describe('scheduler', () => { describe('scheduler', () => {
@ -114,65 +113,7 @@ describe('scheduler', () => {
}) })
}) })
describe('queuePreFlushCb', () => { describe('pre flush jobs', () => {
it('basic usage', async () => {
const calls: string[] = []
const cb1 = () => {
calls.push('cb1')
}
const cb2 = () => {
calls.push('cb2')
}
queuePreFlushCb(cb1)
queuePreFlushCb(cb2)
expect(calls).toEqual([])
await nextTick()
expect(calls).toEqual(['cb1', 'cb2'])
})
it('should dedupe queued preFlushCb', async () => {
const calls: string[] = []
const cb1 = () => {
calls.push('cb1')
}
const cb2 = () => {
calls.push('cb2')
}
const cb3 = () => {
calls.push('cb3')
}
queuePreFlushCb(cb1)
queuePreFlushCb(cb2)
queuePreFlushCb(cb1)
queuePreFlushCb(cb2)
queuePreFlushCb(cb3)
expect(calls).toEqual([])
await nextTick()
expect(calls).toEqual(['cb1', 'cb2', 'cb3'])
})
it('chained queuePreFlushCb', async () => {
const calls: string[] = []
const cb1 = () => {
calls.push('cb1')
// cb2 will be executed after cb1 at the same tick
queuePreFlushCb(cb2)
}
const cb2 = () => {
calls.push('cb2')
}
queuePreFlushCb(cb1)
await nextTick()
expect(calls).toEqual(['cb1', 'cb2'])
})
})
describe('queueJob w/ queuePreFlushCb', () => {
it('queueJob inside preFlushCb', async () => { it('queueJob inside preFlushCb', async () => {
const calls: string[] = [] const calls: string[] = []
const job1 = () => { const job1 = () => {
@ -183,8 +124,9 @@ describe('scheduler', () => {
calls.push('cb1') calls.push('cb1')
queueJob(job1) queueJob(job1)
} }
cb1.pre = true
queuePreFlushCb(cb1) queueJob(cb1)
await nextTick() await nextTick()
expect(calls).toEqual(['cb1', 'job1']) expect(calls).toEqual(['cb1', 'job1'])
}) })
@ -194,17 +136,23 @@ describe('scheduler', () => {
const job1 = () => { const job1 = () => {
calls.push('job1') calls.push('job1')
} }
job1.id = 1
const cb1 = () => { const cb1 = () => {
calls.push('cb1') calls.push('cb1')
queueJob(job1) queueJob(job1)
// cb2 should execute before the job // cb2 should execute before the job
queuePreFlushCb(cb2) queueJob(cb2)
} }
cb1.pre = true
const cb2 = () => { const cb2 = () => {
calls.push('cb2') calls.push('cb2')
} }
cb2.pre = true
cb2.id = 1
queuePreFlushCb(cb1) queueJob(cb1)
await nextTick() await nextTick()
expect(calls).toEqual(['cb1', 'cb2', 'job1']) expect(calls).toEqual(['cb1', 'cb2', 'job1'])
}) })
@ -216,9 +164,9 @@ describe('scheduler', () => {
// when updating the props of a child component. This is handled // when updating the props of a child component. This is handled
// directly inside `updateComponentPreRender` to avoid non atomic // directly inside `updateComponentPreRender` to avoid non atomic
// cb triggers (#1763) // cb triggers (#1763)
queuePreFlushCb(cb1) queueJob(cb1)
queuePreFlushCb(cb2) queueJob(cb2)
flushPreFlushCbs(undefined, job1) flushPreFlushCbs()
calls.push('job1') calls.push('job1')
} }
const cb1 = () => { const cb1 = () => {
@ -226,9 +174,11 @@ describe('scheduler', () => {
// a cb triggers its parent job, which should be skipped // a cb triggers its parent job, which should be skipped
queueJob(job1) queueJob(job1)
} }
cb1.pre = true
const cb2 = () => { const cb2 = () => {
calls.push('cb2') calls.push('cb2')
} }
cb2.pre = true
queueJob(job1) queueJob(job1)
await nextTick() await nextTick()
@ -237,12 +187,14 @@ describe('scheduler', () => {
// #3806 // #3806
it('queue preFlushCb inside postFlushCb', async () => { it('queue preFlushCb inside postFlushCb', async () => {
const cb = jest.fn() const spy = jest.fn()
const cb = () => spy()
cb.pre = true
queuePostFlushCb(() => { queuePostFlushCb(() => {
queuePreFlushCb(cb) queueJob(cb)
}) })
await nextTick() await nextTick()
expect(cb).toHaveBeenCalled() expect(spy).toHaveBeenCalled()
}) })
}) })

View File

@ -103,7 +103,7 @@ export function defineComponent<
M extends MethodOptions = {}, M extends MethodOptions = {},
Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
Extends extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
E extends EmitsOptions = EmitsOptions, E extends EmitsOptions = {},
EE extends string = string EE extends string = string
>( >(
options: ComponentOptionsWithoutProps< options: ComponentOptionsWithoutProps<
@ -130,7 +130,7 @@ export function defineComponent<
M extends MethodOptions = {}, M extends MethodOptions = {},
Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
Extends extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
E extends EmitsOptions = Record<string, any>, E extends EmitsOptions = {},
EE extends string = string EE extends string = string
>( >(
options: ComponentOptionsWithArrayProps< options: ComponentOptionsWithArrayProps<
@ -168,7 +168,7 @@ export function defineComponent<
M extends MethodOptions = {}, M extends MethodOptions = {},
Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
Extends extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
E extends EmitsOptions = Record<string, any>, E extends EmitsOptions = {},
EE extends string = string EE extends string = string
>( >(
options: ComponentOptionsWithObjectProps< options: ComponentOptionsWithObjectProps<

View File

@ -9,7 +9,7 @@ import {
EffectScheduler, EffectScheduler,
DebuggerOptions DebuggerOptions
} from '@vue/reactivity' } from '@vue/reactivity'
import { SchedulerJob, queuePreFlushCb } from './scheduler' import { SchedulerJob, queueJob } from './scheduler'
import { import {
EMPTY_OBJ, EMPTY_OBJ,
isObject, isObject,
@ -345,7 +345,9 @@ function doWatch(
scheduler = () => queuePostRenderEffect(job, instance && instance.suspense) scheduler = () => queuePostRenderEffect(job, instance && instance.suspense)
} else { } else {
// default: 'pre' // default: 'pre'
scheduler = () => queuePreFlushCb(job) job.pre = true
if (instance) job.id = instance.uid
scheduler = () => queueJob(job)
} }
const effect = new ReactiveEffect(getter, scheduler) const effect = new ReactiveEffect(getter, scheduler)

View File

@ -814,6 +814,7 @@ export function finishComponentSetup(
// pass runtime compat config into the compiler // pass runtime compat config into the compiler
finalCompilerOptions.compatConfig = Object.create(globalCompatConfig) finalCompilerOptions.compatConfig = Object.create(globalCompatConfig)
if (Component.compatConfig) { if (Component.compatConfig) {
// @ts-expect-error types are not compatible
extend(finalCompilerOptions.compatConfig, Component.compatConfig) extend(finalCompilerOptions.compatConfig, Component.compatConfig)
} }
} }

View File

@ -1590,7 +1590,7 @@ function baseCreateRenderer(
pauseTracking() pauseTracking()
// props update may have triggered pre-flush watchers. // props update may have triggered pre-flush watchers.
// flush them before the render update. // flush them before the render update.
flushPreFlushCbs(undefined, instance.update) flushPreFlushCbs()
resetTracking() resetTracking()
} }
@ -2331,6 +2331,7 @@ function baseCreateRenderer(
} else { } else {
patch(container._vnode || null, vnode, container, null, null, null, isSVG) patch(container._vnode || null, vnode, container, null, null, null, isSVG)
} }
flushPreFlushCbs()
flushPostFlushCbs() flushPostFlushCbs()
container._vnode = vnode container._vnode = vnode
} }

View File

@ -5,6 +5,7 @@ import { warn } from './warning'
export interface SchedulerJob extends Function { export interface SchedulerJob extends Function {
id?: number id?: number
pre?: boolean
active?: boolean active?: boolean
computed?: boolean computed?: boolean
/** /**
@ -39,10 +40,6 @@ let isFlushPending = false
const queue: SchedulerJob[] = [] const queue: SchedulerJob[] = []
let flushIndex = 0 let flushIndex = 0
const pendingPreFlushCbs: SchedulerJob[] = []
let activePreFlushCbs: SchedulerJob[] | null = null
let preFlushIndex = 0
const pendingPostFlushCbs: SchedulerJob[] = [] const pendingPostFlushCbs: SchedulerJob[] = []
let activePostFlushCbs: SchedulerJob[] | null = null let activePostFlushCbs: SchedulerJob[] | null = null
let postFlushIndex = 0 let postFlushIndex = 0
@ -50,8 +47,6 @@ let postFlushIndex = 0
const resolvedPromise = /*#__PURE__*/ Promise.resolve() as Promise<any> const resolvedPromise = /*#__PURE__*/ Promise.resolve() as Promise<any>
let currentFlushPromise: Promise<void> | null = null let currentFlushPromise: Promise<void> | null = null
let currentPreFlushParentJob: SchedulerJob | null = null
const RECURSION_LIMIT = 100 const RECURSION_LIMIT = 100
type CountMap = Map<SchedulerJob, number> type CountMap = Map<SchedulerJob, number>
@ -89,12 +84,11 @@ export function queueJob(job: SchedulerJob) {
// allow it recursively trigger itself - it is the user's responsibility to // allow it recursively trigger itself - it is the user's responsibility to
// ensure it doesn't end up in an infinite loop. // ensure it doesn't end up in an infinite loop.
if ( if (
(!queue.length || !queue.length ||
!queue.includes( !queue.includes(
job, job,
isFlushing && job.allowRecurse ? flushIndex + 1 : flushIndex isFlushing && job.allowRecurse ? flushIndex + 1 : flushIndex
)) && )
job !== currentPreFlushParentJob
) { ) {
if (job.id == null) { if (job.id == null) {
queue.push(job) queue.push(job)
@ -119,71 +113,44 @@ export function invalidateJob(job: SchedulerJob) {
} }
} }
function queueCb( export function queuePostFlushCb(cb: SchedulerJobs) {
cb: SchedulerJobs,
activeQueue: SchedulerJob[] | null,
pendingQueue: SchedulerJob[],
index: number
) {
if (!isArray(cb)) { if (!isArray(cb)) {
if ( if (
!activeQueue || !activePostFlushCbs ||
!activeQueue.includes(cb, cb.allowRecurse ? index + 1 : index) !activePostFlushCbs.includes(
cb,
cb.allowRecurse ? postFlushIndex + 1 : postFlushIndex
)
) { ) {
pendingQueue.push(cb) pendingPostFlushCbs.push(cb)
} }
} else { } else {
// if cb is an array, it is a component lifecycle hook which can only be // if cb is an array, it is a component lifecycle hook which can only be
// triggered by a job, which is already deduped in the main queue, so // triggered by a job, which is already deduped in the main queue, so
// we can skip duplicate check here to improve perf // we can skip duplicate check here to improve perf
pendingQueue.push(...cb) pendingPostFlushCbs.push(...cb)
} }
queueFlush() queueFlush()
} }
export function queuePreFlushCb(cb: SchedulerJob) { export function flushPreFlushCbs(seen?: CountMap, i = flushIndex) {
queueCb(cb, activePreFlushCbs, pendingPreFlushCbs, preFlushIndex)
}
export function queuePostFlushCb(cb: SchedulerJobs) {
queueCb(cb, activePostFlushCbs, pendingPostFlushCbs, postFlushIndex)
}
export function flushPreFlushCbs(
seen?: CountMap,
parentJob: SchedulerJob | null = null
) {
if (pendingPreFlushCbs.length) {
currentPreFlushParentJob = parentJob
activePreFlushCbs = [...new Set(pendingPreFlushCbs)]
pendingPreFlushCbs.length = 0
if (__DEV__) { if (__DEV__) {
seen = seen || new Map() seen = seen || new Map()
} }
for ( for (; i < queue.length; i++) {
preFlushIndex = 0; const cb = queue[i]
preFlushIndex < activePreFlushCbs.length; if (cb && cb.pre) {
preFlushIndex++ if (__DEV__ && checkRecursiveUpdates(seen!, cb)) {
) {
if (
__DEV__ &&
checkRecursiveUpdates(seen!, activePreFlushCbs[preFlushIndex])
) {
continue continue
} }
activePreFlushCbs[preFlushIndex]() queue.splice(i, 1)
i--
cb()
} }
activePreFlushCbs = null
preFlushIndex = 0
currentPreFlushParentJob = null
// recursively flush until it drains
flushPreFlushCbs(seen, parentJob)
} }
} }
export function flushPostFlushCbs(seen?: CountMap) { export function flushPostFlushCbs(seen?: CountMap) {
// flush any pre cbs queued during the flush (e.g. pre watchers)
flushPreFlushCbs()
if (pendingPostFlushCbs.length) { if (pendingPostFlushCbs.length) {
const deduped = [...new Set(pendingPostFlushCbs)] const deduped = [...new Set(pendingPostFlushCbs)]
pendingPostFlushCbs.length = 0 pendingPostFlushCbs.length = 0
@ -222,6 +189,15 @@ export function flushPostFlushCbs(seen?: CountMap) {
const getId = (job: SchedulerJob): number => const getId = (job: SchedulerJob): number =>
job.id == null ? Infinity : job.id job.id == null ? Infinity : job.id
const comparator = (a: SchedulerJob, b: SchedulerJob): number => {
const diff = getId(a) - getId(b)
if (diff === 0) {
if (a.pre && !b.pre) return -1
if (b.pre && !a.pre) return 1
}
return diff
}
function flushJobs(seen?: CountMap) { function flushJobs(seen?: CountMap) {
isFlushPending = false isFlushPending = false
isFlushing = true isFlushing = true
@ -229,8 +205,6 @@ function flushJobs(seen?: CountMap) {
seen = seen || new Map() seen = seen || new Map()
} }
flushPreFlushCbs(seen)
// Sort queue before flush. // Sort queue before flush.
// This ensures that: // This ensures that:
// 1. Components are updated from parent to child. (because parent is always // 1. Components are updated from parent to child. (because parent is always
@ -238,7 +212,7 @@ function flushJobs(seen?: CountMap) {
// priority number) // priority number)
// 2. If a component is unmounted during a parent component's update, // 2. If a component is unmounted during a parent component's update,
// its update can be skipped. // its update can be skipped.
queue.sort((a, b) => getId(a) - getId(b)) queue.sort(comparator)
// conditional usage of checkRecursiveUpdate must be determined out of // conditional usage of checkRecursiveUpdate must be determined out of
// try ... catch block since Rollup by default de-optimizes treeshaking // try ... catch block since Rollup by default de-optimizes treeshaking
@ -270,11 +244,7 @@ function flushJobs(seen?: CountMap) {
currentFlushPromise = null currentFlushPromise = null
// some postFlushCb queued jobs! // some postFlushCb queued jobs!
// keep flushing until it drains. // keep flushing until it drains.
if ( if (queue.length || pendingPostFlushCbs.length) {
queue.length ||
pendingPreFlushCbs.length ||
pendingPostFlushCbs.length
) {
flushJobs(seen) flushJobs(seen)
} }
} }

View File

@ -128,14 +128,14 @@ function testRender(type: string, render: typeof renderToString) {
await render( await render(
createApp( createApp(
defineComponent({ defineComponent({
extends: { extends: defineComponent({
data() { data() {
return { msg: 'hello' } return { msg: 'hello' }
}, },
render(this: any) { render() {
return h('div', this.msg) return h('div', this.msg)
} }
} })
}) })
) )
) )
@ -148,14 +148,14 @@ function testRender(type: string, render: typeof renderToString) {
createApp( createApp(
defineComponent({ defineComponent({
mixins: [ mixins: [
{ defineComponent({
data() { data() {
return { msg: 'hello' } return { msg: 'hello' }
}, },
render(this: any) { render() {
return h('div', this.msg) return h('div', this.msg)
} }
} })
] ]
}) })
) )
@ -675,9 +675,7 @@ function testRender(type: string, render: typeof renderToString) {
const MyComp = { const MyComp = {
render: () => h('p', 'hello') render: () => h('p', 'hello')
} }
expect(await render(h(KeepAlive, () => h(MyComp)))).toBe( expect(await render(h(KeepAlive, () => h(MyComp)))).toBe(`<p>hello</p>`)
`<p>hello</p>`
)
}) })
test('Transition', async () => { test('Transition', async () => {

View File

@ -77,7 +77,7 @@ export async function resolveTeleports(context: SSRContext) {
// note: it's OK to await sequentially here because the Promises were // note: it's OK to await sequentially here because the Promises were
// created eagerly in parallel. // created eagerly in parallel.
context.teleports[key] = await unrollBuffer( context.teleports[key] = await unrollBuffer(
(await Promise.all(context.__teleportBuffers[key])) as SSRBuffer await Promise.all([context.__teleportBuffers[key]])
) )
} }
} }

View File

@ -28,11 +28,13 @@
}, },
"./server-renderer": { "./server-renderer": {
"import": "./server-renderer/index.mjs", "import": "./server-renderer/index.mjs",
"require": "./server-renderer/index.js" "require": "./server-renderer/index.js",
"types": "./server-renderer/index.d.ts"
}, },
"./compiler-sfc": { "./compiler-sfc": {
"import": "./compiler-sfc/index.mjs", "import": "./compiler-sfc/index.mjs",
"require": "./compiler-sfc/index.js" "require": "./compiler-sfc/index.js",
"types": "./compiler-sfc/index.d.ts"
}, },
"./dist/*": "./dist/*", "./dist/*": "./dist/*",
"./package.json": "./package.json", "./package.json": "./package.json",

View File

@ -48,7 +48,7 @@ importers:
todomvc-app-css: ^2.3.0 todomvc-app-css: ^2.3.0
ts-jest: ^27.0.5 ts-jest: ^27.0.5
tslib: ^2.4.0 tslib: ^2.4.0
typescript: ^4.6.4 typescript: ^4.7.4
vite: ^2.9.8 vite: ^2.9.8
vue: workspace:* vue: workspace:*
yorkie: ^2.0.0 yorkie: ^2.0.0
@ -64,7 +64,7 @@ importers:
'@types/jest': 27.0.3 '@types/jest': 27.0.3
'@types/node': 16.11.12 '@types/node': 16.11.12
'@types/puppeteer': 5.4.4 '@types/puppeteer': 5.4.4
'@typescript-eslint/parser': 5.23.0_e4zyhrvfnqudwdx5bevnvkluy4 '@typescript-eslint/parser': 5.23.0_hxadhbs2xogijvk7vq4t2azzbu
'@vue/reactivity': link:packages/reactivity '@vue/reactivity': link:packages/reactivity
'@vue/runtime-core': link:packages/runtime-core '@vue/runtime-core': link:packages/runtime-core
'@vue/runtime-dom': link:packages/runtime-dom '@vue/runtime-dom': link:packages/runtime-dom
@ -75,7 +75,7 @@ importers:
enquirer: 2.3.6 enquirer: 2.3.6
esbuild: 0.14.35 esbuild: 0.14.35
eslint: 7.32.0 eslint: 7.32.0
eslint-plugin-jest: 26.1.5_kkaclaimgki2r45yqzc3bxhmwy eslint-plugin-jest: 26.1.5_fublp7hbjjjut4jarqgrlzb3ey
execa: 4.1.0 execa: 4.1.0
fs-extra: 9.1.0 fs-extra: 9.1.0
jest: 27.4.4 jest: 27.4.4
@ -91,13 +91,13 @@ importers:
rollup-plugin-node-globals: 1.4.0 rollup-plugin-node-globals: 1.4.0
rollup-plugin-polyfill-node: 0.6.2_rollup@2.38.5 rollup-plugin-polyfill-node: 0.6.2_rollup@2.38.5
rollup-plugin-terser: 7.0.2_rollup@2.38.5 rollup-plugin-terser: 7.0.2_rollup@2.38.5
rollup-plugin-typescript2: 0.27.3_zlmz7jga2mttuvx4qwelsmvyxm rollup-plugin-typescript2: 0.27.3_svygma56heasd5pd4q5yjh2bo4
semver: 7.3.5 semver: 7.3.5
serve: 12.0.1 serve: 12.0.1
todomvc-app-css: 2.4.1 todomvc-app-css: 2.4.1
ts-jest: 27.1.1_fl6hqye43ip7rnu7q76f35ejrm ts-jest: 27.1.1_3hnzclobtp5be2lqcsbwijsi7u
tslib: 2.4.0 tslib: 2.4.0
typescript: 4.6.4 typescript: 4.7.4
vite: 2.9.8 vite: 2.9.8
vue: link:packages/vue vue: link:packages/vue
yorkie: 2.0.0 yorkie: 2.0.0
@ -912,7 +912,7 @@ packages:
resolve: 1.17.0 resolve: 1.17.0
semver: 7.3.5 semver: 7.3.5
source-map: 0.6.1 source-map: 0.6.1
typescript: 4.5.3 typescript: 4.5.5
dev: true dev: true
/@microsoft/tsdoc-config/0.15.2: /@microsoft/tsdoc-config/0.15.2:
@ -1205,15 +1205,15 @@ packages:
'@types/yargs-parser': 20.2.1 '@types/yargs-parser': 20.2.1
dev: true dev: true
/@types/yauzl/2.9.2: /@types/yauzl/2.10.0:
resolution: {integrity: sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA==} resolution: {integrity: sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==}
requiresBuild: true requiresBuild: true
dependencies: dependencies:
'@types/node': 16.11.12 '@types/node': 16.11.12
dev: true dev: true
optional: true optional: true
/@typescript-eslint/parser/5.23.0_e4zyhrvfnqudwdx5bevnvkluy4: /@typescript-eslint/parser/5.23.0_hxadhbs2xogijvk7vq4t2azzbu:
resolution: {integrity: sha512-V06cYUkqcGqpFjb8ttVgzNF53tgbB/KoQT/iB++DOIExKmzI9vBJKjZKt/6FuV9c+zrDsvJKbJ2DOCYwX91cbw==} resolution: {integrity: sha512-V06cYUkqcGqpFjb8ttVgzNF53tgbB/KoQT/iB++DOIExKmzI9vBJKjZKt/6FuV9c+zrDsvJKbJ2DOCYwX91cbw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies: peerDependencies:
@ -1225,10 +1225,10 @@ packages:
dependencies: dependencies:
'@typescript-eslint/scope-manager': 5.23.0 '@typescript-eslint/scope-manager': 5.23.0
'@typescript-eslint/types': 5.23.0 '@typescript-eslint/types': 5.23.0
'@typescript-eslint/typescript-estree': 5.23.0_typescript@4.6.4 '@typescript-eslint/typescript-estree': 5.23.0_typescript@4.7.4
debug: 4.3.3 debug: 4.3.3
eslint: 7.32.0 eslint: 7.32.0
typescript: 4.6.4 typescript: 4.7.4
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
dev: true dev: true
@ -1259,7 +1259,7 @@ packages:
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true dev: true
/@typescript-eslint/typescript-estree/5.19.0_typescript@4.6.4: /@typescript-eslint/typescript-estree/5.19.0_typescript@4.7.4:
resolution: {integrity: sha512-dRPuD4ocXdaE1BM/dNR21elSEUPKaWgowCA0bqJ6YbYkvtrPVEvZ+zqcX5a8ECYn3q5iBSSUcBBD42ubaOp0Hw==} resolution: {integrity: sha512-dRPuD4ocXdaE1BM/dNR21elSEUPKaWgowCA0bqJ6YbYkvtrPVEvZ+zqcX5a8ECYn3q5iBSSUcBBD42ubaOp0Hw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies: peerDependencies:
@ -1274,13 +1274,13 @@ packages:
globby: 11.0.4 globby: 11.0.4
is-glob: 4.0.3 is-glob: 4.0.3
semver: 7.3.5 semver: 7.3.5
tsutils: 3.21.0_typescript@4.6.4 tsutils: 3.21.0_typescript@4.7.4
typescript: 4.6.4 typescript: 4.7.4
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
dev: true dev: true
/@typescript-eslint/typescript-estree/5.23.0_typescript@4.6.4: /@typescript-eslint/typescript-estree/5.23.0_typescript@4.7.4:
resolution: {integrity: sha512-xE9e0lrHhI647SlGMl+m+3E3CKPF1wzvvOEWnuE3CCjjT7UiRnDGJxmAcVKJIlFgK6DY9RB98eLr1OPigPEOGg==} resolution: {integrity: sha512-xE9e0lrHhI647SlGMl+m+3E3CKPF1wzvvOEWnuE3CCjjT7UiRnDGJxmAcVKJIlFgK6DY9RB98eLr1OPigPEOGg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies: peerDependencies:
@ -1295,13 +1295,13 @@ packages:
globby: 11.0.4 globby: 11.0.4
is-glob: 4.0.3 is-glob: 4.0.3
semver: 7.3.5 semver: 7.3.5
tsutils: 3.21.0_typescript@4.6.4 tsutils: 3.21.0_typescript@4.7.4
typescript: 4.6.4 typescript: 4.7.4
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
dev: true dev: true
/@typescript-eslint/utils/5.19.0_e4zyhrvfnqudwdx5bevnvkluy4: /@typescript-eslint/utils/5.19.0_hxadhbs2xogijvk7vq4t2azzbu:
resolution: {integrity: sha512-ZuEckdupXpXamKvFz/Ql8YnePh2ZWcwz7APICzJL985Rp5C2AYcHO62oJzIqNhAMtMK6XvrlBTZeNG8n7gS3lQ==} resolution: {integrity: sha512-ZuEckdupXpXamKvFz/Ql8YnePh2ZWcwz7APICzJL985Rp5C2AYcHO62oJzIqNhAMtMK6XvrlBTZeNG8n7gS3lQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies: peerDependencies:
@ -1310,7 +1310,7 @@ packages:
'@types/json-schema': 7.0.11 '@types/json-schema': 7.0.11
'@typescript-eslint/scope-manager': 5.19.0 '@typescript-eslint/scope-manager': 5.19.0
'@typescript-eslint/types': 5.19.0 '@typescript-eslint/types': 5.19.0
'@typescript-eslint/typescript-estree': 5.19.0_typescript@4.6.4 '@typescript-eslint/typescript-estree': 5.19.0_typescript@4.7.4
eslint: 7.32.0 eslint: 7.32.0
eslint-scope: 5.1.1 eslint-scope: 5.1.1
eslint-utils: 3.0.0_eslint@7.32.0 eslint-utils: 3.0.0_eslint@7.32.0
@ -2906,7 +2906,7 @@ packages:
source-map: 0.6.1 source-map: 0.6.1
dev: true dev: true
/eslint-plugin-jest/26.1.5_kkaclaimgki2r45yqzc3bxhmwy: /eslint-plugin-jest/26.1.5_fublp7hbjjjut4jarqgrlzb3ey:
resolution: {integrity: sha512-su89aDuljL9bTjEufTXmKUMSFe2kZUL9bi7+woq+C2ukHZordhtfPm4Vg+tdioHBaKf8v3/FXW9uV0ksqhYGFw==} resolution: {integrity: sha512-su89aDuljL9bTjEufTXmKUMSFe2kZUL9bi7+woq+C2ukHZordhtfPm4Vg+tdioHBaKf8v3/FXW9uV0ksqhYGFw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies: peerDependencies:
@ -2919,7 +2919,7 @@ packages:
jest: jest:
optional: true optional: true
dependencies: dependencies:
'@typescript-eslint/utils': 5.19.0_e4zyhrvfnqudwdx5bevnvkluy4 '@typescript-eslint/utils': 5.19.0_hxadhbs2xogijvk7vq4t2azzbu
eslint: 7.32.0 eslint: 7.32.0
jest: 27.4.4 jest: 27.4.4
transitivePeerDependencies: transitivePeerDependencies:
@ -3177,7 +3177,7 @@ packages:
get-stream: 5.2.0 get-stream: 5.2.0
yauzl: 2.10.0 yauzl: 2.10.0
optionalDependencies: optionalDependencies:
'@types/yauzl': 2.9.2 '@types/yauzl': 2.10.0
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
dev: true dev: true
@ -3521,7 +3521,7 @@ packages:
source-map: 0.6.1 source-map: 0.6.1
wordwrap: 1.0.0 wordwrap: 1.0.0
optionalDependencies: optionalDependencies:
uglify-js: 3.14.4 uglify-js: 3.16.1
dev: true dev: true
/hard-rejection/2.1.0: /hard-rejection/2.1.0:
@ -5130,6 +5130,7 @@ packages:
resolution: {integrity: sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==} resolution: {integrity: sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true hasBin: true
dev: false
/nanoid/3.3.4: /nanoid/3.3.4:
resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==}
@ -5597,6 +5598,7 @@ packages:
nanoid: 3.1.30 nanoid: 3.1.30
picocolors: 1.0.0 picocolors: 1.0.0
source-map-js: 1.0.1 source-map-js: 1.0.1
dev: false
/prelude-ls/1.1.2: /prelude-ls/1.1.2:
resolution: {integrity: sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=} resolution: {integrity: sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=}
@ -6118,7 +6120,7 @@ packages:
terser: 5.10.0 terser: 5.10.0
dev: true dev: true
/rollup-plugin-typescript2/0.27.3_zlmz7jga2mttuvx4qwelsmvyxm: /rollup-plugin-typescript2/0.27.3_svygma56heasd5pd4q5yjh2bo4:
resolution: {integrity: sha512-gmYPIFmALj9D3Ga1ZbTZAKTXq1JKlTQBtj299DXhqYz9cL3g/AQfUvbb2UhH+Nf++cCq941W2Mv7UcrcgLzJJg==} resolution: {integrity: sha512-gmYPIFmALj9D3Ga1ZbTZAKTXq1JKlTQBtj299DXhqYz9cL3g/AQfUvbb2UhH+Nf++cCq941W2Mv7UcrcgLzJJg==}
peerDependencies: peerDependencies:
rollup: '>=1.26.3' rollup: '>=1.26.3'
@ -6130,7 +6132,7 @@ packages:
resolve: 1.17.0 resolve: 1.17.0
rollup: 2.38.5 rollup: 2.38.5
tslib: 2.0.1 tslib: 2.0.1
typescript: 4.6.4 typescript: 4.7.4
dev: true dev: true
/rollup-pluginutils/2.8.2: /rollup-pluginutils/2.8.2:
@ -6755,7 +6757,7 @@ packages:
engines: {node: '>=8'} engines: {node: '>=8'}
dev: true dev: true
/ts-jest/27.1.1_fl6hqye43ip7rnu7q76f35ejrm: /ts-jest/27.1.1_3hnzclobtp5be2lqcsbwijsi7u:
resolution: {integrity: sha512-Ds0VkB+cB+8g2JUmP/GKWndeZcCKrbe6jzolGrVWdqVUFByY/2KDHqxJ7yBSon7hDB1TA4PXxjfZ+JjzJisvgA==} resolution: {integrity: sha512-Ds0VkB+cB+8g2JUmP/GKWndeZcCKrbe6jzolGrVWdqVUFByY/2KDHqxJ7yBSon7hDB1TA4PXxjfZ+JjzJisvgA==}
engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
hasBin: true hasBin: true
@ -6786,7 +6788,7 @@ packages:
lodash.memoize: 4.1.2 lodash.memoize: 4.1.2
make-error: 1.3.6 make-error: 1.3.6
semver: 7.3.5 semver: 7.3.5
typescript: 4.6.4 typescript: 4.7.4
yargs-parser: 20.2.9 yargs-parser: 20.2.9
dev: true dev: true
@ -6806,14 +6808,14 @@ packages:
resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==}
dev: true dev: true
/tsutils/3.21.0_typescript@4.6.4: /tsutils/3.21.0_typescript@4.7.4:
resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
engines: {node: '>= 6'} engines: {node: '>= 6'}
peerDependencies: peerDependencies:
typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta'
dependencies: dependencies:
tslib: 1.14.1 tslib: 1.14.1
typescript: 4.6.4 typescript: 4.7.4
dev: true dev: true
/type-check/0.3.2: /type-check/0.3.2:
@ -6874,20 +6876,20 @@ packages:
resolution: {integrity: sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=} resolution: {integrity: sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=}
dev: true dev: true
/typescript/4.5.3: /typescript/4.5.5:
resolution: {integrity: sha512-eVYaEHALSt+s9LbvgEv4Ef+Tdq7hBiIZgii12xXJnukryt3pMgJf6aKhoCZ3FWQsu6sydEnkg11fYXLzhLBjeQ==} resolution: {integrity: sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==}
engines: {node: '>=4.2.0'} engines: {node: '>=4.2.0'}
hasBin: true hasBin: true
dev: true dev: true
/typescript/4.6.4: /typescript/4.7.4:
resolution: {integrity: sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==} resolution: {integrity: sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==}
engines: {node: '>=4.2.0'} engines: {node: '>=4.2.0'}
hasBin: true hasBin: true
dev: true dev: true
/uglify-js/3.14.4: /uglify-js/3.16.1:
resolution: {integrity: sha512-AbiSR44J0GoCeV81+oxcy/jDOElO2Bx3d0MfQCUShq7JRXaM4KtQopZsq2vFv8bCq2yMaGrw1FgygUd03RyRDA==} resolution: {integrity: sha512-X5BGTIDH8U6IQ1TIRP62YC36k+ULAa1d59BxlWvPUJ1NkW5L3FwcGfEzuVvGmhJFBu0YJ5Ge25tmRISqCmLiRQ==}
engines: {node: '>=0.8.0'} engines: {node: '>=0.8.0'}
hasBin: true hasBin: true
requiresBuild: true requiresBuild: true

View File

@ -1163,6 +1163,38 @@ describe('should allow to assign props', () => {
expectType<JSX.Element>(<Parent {...child.$props} />) expectType<JSX.Element>(<Parent {...child.$props} />)
}) })
// #6052
describe('prop starting with `on*` is broken', () => {
defineComponent({
props: {
onX: {
type: Function as PropType<(a: 1) => void>,
required: true
}
},
setup(props) {
expectType<(a: 1) => void>(props.onX)
props.onX(1)
}
})
defineComponent({
props: {
onX: {
type: Function as PropType<(a: 1) => void>,
required: true
}
},
emits: {
test: (a: 1) => true
},
setup(props) {
expectType<(a: 1) => void>(props.onX)
expectType<undefined | ((a: 1) => any)>(props.onTest)
}
})
})
// check if defineComponent can be exported // check if defineComponent can be exported
export default { export default {
// function components // function components
@ -1209,5 +1241,4 @@ declare const MyButton: DefineComponent<
Readonly<ExtractPropTypes<{}>>, Readonly<ExtractPropTypes<{}>>,
{} {}
> >
;<MyButton class="x" /> ;<MyButton class="x" />