From 00458cd38d209410d3c675729230a42a0a34a4b9 Mon Sep 17 00:00:00 2001
From: jf-paradis <89814003+jf-paradis@users.noreply.github.com>
Date: Mon, 8 Aug 2022 17:50:53 -0700
Subject: [PATCH 01/41] fix(types): Make SetupBindings optional on ExtendedVue
and CombinedVueInstance (#12727)
fix #12726
fix #12717
---
types/vue.d.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/types/vue.d.ts b/types/vue.d.ts
index 74bce2c8a45..8c91bc88a2f 100644
--- a/types/vue.d.ts
+++ b/types/vue.d.ts
@@ -100,7 +100,7 @@ export type CombinedVueInstance<
Methods,
Computed,
Props,
- SetupBindings
+ SetupBindings = {}
> = Data &
Methods &
Computed &
@@ -114,7 +114,7 @@ export type ExtendedVue<
Methods,
Computed,
Props,
- SetupBindings
+ SetupBindings = {}
> = VueConstructor<
CombinedVueInstance &
Vue
From 5c742eb2e0d8dad268fb29ed4f92d286b5e0f4b5 Mon Sep 17 00:00:00 2001
From: Jonas <30421456+jonaskuske@users.noreply.github.com>
Date: Mon, 15 Aug 2022 03:37:08 +0200
Subject: [PATCH 02/41] fix(compiler-sfc): allow full hostnames in asset url
base (#12732)
fix #12731
---
.../compiler-sfc/src/templateCompilerModules/utils.ts | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/packages/compiler-sfc/src/templateCompilerModules/utils.ts b/packages/compiler-sfc/src/templateCompilerModules/utils.ts
index 3e635b00207..8a2d19c6ce7 100644
--- a/packages/compiler-sfc/src/templateCompilerModules/utils.ts
+++ b/packages/compiler-sfc/src/templateCompilerModules/utils.ts
@@ -24,10 +24,15 @@ export function urlToRequire(
// does not apply to absolute urls or urls that start with `@`
// since they are aliases
if (firstChar === '.' || firstChar === '~') {
+ // Allow for full hostnames provided in options.base
+ const base = parseUriParts(transformAssetUrlsOption.base)
+ const protocol = base.protocol || ''
+ const host = base.host ? protocol + '//' + base.host : ''
+ const basePath = base.path || '/'
// when packaged in the browser, path will be using the posix-
// only version provided by rollup-plugin-node-builtins.
- return `"${(path.posix || path).join(
- transformAssetUrlsOption.base,
+ return `"${host}${(path.posix || path).join(
+ basePath,
uriParts.path + (uriParts.hash || '')
)}"`
}
@@ -64,7 +69,7 @@ function parseUriParts(urlString: string): UrlWithStringQuery {
// @see https://nodejs.org/api/url.html#url_url_parse_urlstring_parsequerystring_slashesdenotehost
if ('string' === typeof urlString) {
// check is an uri
- return uriParse(urlString) // take apart the uri
+ return uriParse(urlString, false, true) // take apart the uri
}
}
return returnValue
From 4b37b568c7c3fd238aa61fcc956f882223f8e87f Mon Sep 17 00:00:00 2001
From: Evan You
Date: Mon, 15 Aug 2022 09:53:12 +0800
Subject: [PATCH 03/41] fix(types): fix options suggestions when using
defineComponent
functional component overloads should be moved last
fix #12736
---
types/v3-define-component.d.ts | 56 +++++++++++++++++-----------------
1 file changed, 28 insertions(+), 28 deletions(-)
diff --git a/types/v3-define-component.d.ts b/types/v3-define-component.d.ts
index 30f7046e403..a2c47322b49 100644
--- a/types/v3-define-component.d.ts
+++ b/types/v3-define-component.d.ts
@@ -67,30 +67,6 @@ type DefineComponent<
props: PropsOrPropOptions
}
-/**
- * overload 0.0: functional component with array props
- */
-export function defineComponent<
- PropNames extends string,
- Props = Readonly<{ [key in PropNames]?: any }>
->(options: {
- functional: true
- props?: PropNames[]
- render?: (h: CreateElement, context: RenderContext) => any
-}): DefineComponent
-
-/**
- * overload 0.1: functional component with object props
- */
-export function defineComponent<
- PropsOptions extends ComponentPropsOptions = ComponentPropsOptions,
- Props = ExtractPropTypes
->(options: {
- functional: true
- props?: PropsOptions
- render?: (h: CreateElement, context: RenderContext) => any
-}): DefineComponent
-
/**
* overload 1: object format with no props
*/
@@ -104,7 +80,7 @@ export function defineComponent<
Emits extends EmitsOptions = {},
EmitsNames extends string = string
>(
- options: ComponentOptionsWithoutProps<
+ options: { functional?: never } & ComponentOptionsWithoutProps<
{},
RawBindings,
D,
@@ -135,7 +111,7 @@ export function defineComponent<
EmitsNames extends string = string,
PropsOptions extends ComponentPropsOptions = ComponentPropsOptions
>(
- options: ComponentOptionsWithArrayProps<
+ options: { functional?: never } & ComponentOptionsWithArrayProps<
PropNames,
RawBindings,
D,
@@ -175,7 +151,7 @@ export function defineComponent<
PropsOptions extends ComponentPropsOptions = ComponentPropsOptions
>(
options: HasDefined extends true
- ? ComponentOptionsWithProps<
+ ? { functional?: never } & ComponentOptionsWithProps<
PropsOptions,
RawBindings,
D,
@@ -187,7 +163,7 @@ export function defineComponent<
EmitsNames,
Props
>
- : ComponentOptionsWithProps<
+ : { functional?: never } & ComponentOptionsWithProps<
PropsOptions,
RawBindings,
D,
@@ -199,3 +175,27 @@ export function defineComponent<
EmitsNames
>
): DefineComponent
+
+/**
+ * overload 4.1: functional component with array props
+ */
+export function defineComponent<
+ PropNames extends string,
+ Props = Readonly<{ [key in PropNames]?: any }>
+>(options: {
+ functional: true
+ props?: PropNames[]
+ render?: (h: CreateElement, context: RenderContext) => any
+}): DefineComponent
+
+/**
+ * overload 4.2: functional component with object props
+ */
+export function defineComponent<
+ PropsOptions extends ComponentPropsOptions = ComponentPropsOptions,
+ Props = ExtractPropTypes
+>(options: {
+ functional: true
+ props?: PropsOptions
+ render?: (h: CreateElement, context: RenderContext) => any
+}): DefineComponent
From bd89ce53a9de417a9372630bb5d433a40acc1a53 Mon Sep 17 00:00:00 2001
From: Evan You
Date: Mon, 15 Aug 2022 15:37:13 +0800
Subject: [PATCH 04/41] fix: ensure render watcher of manually created instance
is correctly tracked in owner scope
fix #12701
---
src/core/instance/lifecycle.ts | 2 ++
src/core/observer/watcher.ts | 6 ++----
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/core/instance/lifecycle.ts b/src/core/instance/lifecycle.ts
index df70b7113fd..fec330ad5fc 100644
--- a/src/core/instance/lifecycle.ts
+++ b/src/core/instance/lifecycle.ts
@@ -209,6 +209,7 @@ export function mountComponent(
// we set this to vm._watcher inside the watcher's constructor
// since the watcher's initial patch may call $forceUpdate (e.g. inside child
// component's mounted hook), which relies on vm._watcher being already defined
+ vm._scope.on()
new Watcher(
vm,
updateComponent,
@@ -216,6 +217,7 @@ export function mountComponent(
watcherOptions,
true /* isRenderWatcher */
)
+ vm._scope.off()
hydrating = false
// flush buffer for flush: "pre" watchers queued in setup()
diff --git a/src/core/observer/watcher.ts b/src/core/observer/watcher.ts
index b1f491acb33..00bf19b9123 100644
--- a/src/core/observer/watcher.ts
+++ b/src/core/observer/watcher.ts
@@ -72,10 +72,8 @@ export default class Watcher implements DepTarget {
isRenderWatcher?: boolean
) {
recordEffectScope(this, activeEffectScope || (vm ? vm._scope : undefined))
- if ((this.vm = vm)) {
- if (isRenderWatcher) {
- vm._watcher = this
- }
+ if ((this.vm = vm) && isRenderWatcher) {
+ vm._watcher = this
}
// options
if (options) {
From f0057b101e6451d5095cdb7fd6308fd31ac0450c Mon Sep 17 00:00:00 2001
From: Evan You
Date: Mon, 15 Aug 2022 19:06:38 +0800
Subject: [PATCH 05/41] fix(watch): avoid pre watcher firing on unmount
fix #12703
---
src/v3/apiWatch.ts | 5 +----
test/unit/features/v3/apiWatch.spec.ts | 4 ++--
2 files changed, 3 insertions(+), 6 deletions(-)
diff --git a/src/v3/apiWatch.ts b/src/v3/apiWatch.ts
index 7fe5eeb9dcc..141a58eb686 100644
--- a/src/v3/apiWatch.ts
+++ b/src/v3/apiWatch.ts
@@ -274,10 +274,7 @@ function doWatch(
let oldValue = isMultiSource ? [] : INITIAL_WATCHER_VALUE
// overwrite default run
watcher.run = () => {
- if (
- !watcher.active &&
- !(flush === 'pre' && instance && instance._isBeingDestroyed)
- ) {
+ if (!watcher.active) {
return
}
if (cb) {
diff --git a/test/unit/features/v3/apiWatch.spec.ts b/test/unit/features/v3/apiWatch.spec.ts
index 0206e8df3bf..c92bc150ae7 100644
--- a/test/unit/features/v3/apiWatch.spec.ts
+++ b/test/unit/features/v3/apiWatch.spec.ts
@@ -542,7 +542,7 @@ describe('api: watch', () => {
expect(cb).not.toHaveBeenCalled()
})
- it('should fire on component unmount w/ flush: pre', async () => {
+ it('should not fire on component unmount w/ flush: pre', async () => {
const toggle = ref(true)
const cb = vi.fn()
const Comp = {
@@ -560,7 +560,7 @@ describe('api: watch', () => {
expect(cb).not.toHaveBeenCalled()
toggle.value = false
await nextTick()
- expect(cb).toHaveBeenCalledTimes(1)
+ expect(cb).not.toHaveBeenCalled()
})
// vuejs/core#1763
From 80d1baf92050da411fb1bfe714401c498001dd36 Mon Sep 17 00:00:00 2001
From: Evan You
Date: Thu, 18 Aug 2022 15:23:47 +0800
Subject: [PATCH 06/41] feat(types): export DefineComponent
close #12748
---
types/index.d.ts | 2 +-
types/v3-define-component.d.ts | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/types/index.d.ts b/types/index.d.ts
index 2b5d3a89da2..19fce98726f 100644
--- a/types/index.d.ts
+++ b/types/index.d.ts
@@ -41,7 +41,7 @@ export * from './v3-setup-helpers'
export { Data } from './common'
export { SetupContext } from './v3-setup-context'
-export { defineComponent } from './v3-define-component'
+export { defineComponent, DefineComponent } from './v3-define-component'
export { defineAsyncComponent } from './v3-define-async-component'
export {
SetupFunction,
diff --git a/types/v3-define-component.d.ts b/types/v3-define-component.d.ts
index a2c47322b49..69f65a2ec35 100644
--- a/types/v3-define-component.d.ts
+++ b/types/v3-define-component.d.ts
@@ -20,7 +20,7 @@ import { Data, HasDefined } from './common'
import { EmitsOptions } from './v3-setup-context'
import { CreateElement, RenderContext } from './umd'
-type DefineComponent<
+export type DefineComponent<
PropsOrPropOptions = {},
RawBindings = {},
D = {},
From b4bf4c52ad31e02307cfd4d643dc5610c893e3ba Mon Sep 17 00:00:00 2001
From: Evan You
Date: Thu, 18 Aug 2022 15:32:12 +0800
Subject: [PATCH 07/41] fix(types): allow attaching unknown options to defined
component
fix #12742
---
types/test/v3/define-component-test.tsx | 4 ++++
types/v3-component-options.d.ts | 3 +++
2 files changed, 7 insertions(+)
diff --git a/types/test/v3/define-component-test.tsx b/types/test/v3/define-component-test.tsx
index 42d0f32eb0d..481a2d11ac7 100644
--- a/types/test/v3/define-component-test.tsx
+++ b/types/test/v3/define-component-test.tsx
@@ -1165,3 +1165,7 @@ defineComponent({
return h('div', {}, [...this.$slots.default!])
}
})
+
+// #12742 allow attaching custom properties (consistent with v3)
+const Foo = defineComponent({})
+Foo.foobar = 123
diff --git a/types/v3-component-options.d.ts b/types/v3-component-options.d.ts
index d8c64ab13ab..e2da34e753f 100644
--- a/types/v3-component-options.d.ts
+++ b/types/v3-component-options.d.ts
@@ -88,6 +88,9 @@ export interface ComponentOptionsBase<
'data' | 'computed' | 'methods' | 'setup' | 'props' | 'mixins' | 'extends'
>,
ComponentCustomOptions {
+ // allow any options
+ [key: string]: any
+
// rewrite options api types
data?: (
this: CreateComponentPublicInstance,
From 89a6b5e8658a6e3ae2cf649829901784ac9deb3c Mon Sep 17 00:00:00 2001
From: gu <11851303+gulewei@users.noreply.github.com>
Date: Thu, 18 Aug 2022 15:56:37 +0800
Subject: [PATCH 08/41] feat(types): support mixins inference for new Vue()
(#12737)
close #12730
---
types/options.d.ts | 33 +++++--
types/test/vue-test.ts | 39 +++++++-
types/v3-component-public-instance.d.ts | 4 +-
types/vue.d.ts | 124 +++++++++++++++++++-----
4 files changed, 166 insertions(+), 34 deletions(-)
diff --git a/types/options.d.ts b/types/options.d.ts
index e11020f4948..c82c6c5f8ae 100644
--- a/types/options.d.ts
+++ b/types/options.d.ts
@@ -3,6 +3,7 @@ import { VNode, VNodeData, VNodeDirective, NormalizedScopedSlot } from './vnode'
import { SetupContext } from './v3-setup-context'
import { DebuggerEvent } from './v3-generated'
import { DefineComponent } from './v3-define-component'
+import { ComponentOptionsMixin } from './v3-component-options'
type Constructor = {
new (...args: any[]): any
@@ -93,7 +94,9 @@ export type ThisTypedComponentOptionsWithArrayProps<
Methods,
Computed,
PropNames extends string,
- SetupBindings
+ SetupBindings,
+ Mixin,
+ Extends
> = object &
ComponentOptions<
V,
@@ -102,7 +105,9 @@ export type ThisTypedComponentOptionsWithArrayProps<
Computed,
PropNames[],
Record,
- SetupBindings
+ SetupBindings,
+ Mixin,
+ Extends
> &
ThisType<
CombinedVueInstance<
@@ -111,7 +116,9 @@ export type ThisTypedComponentOptionsWithArrayProps<
Methods,
Computed,
Readonly>,
- SetupBindings
+ SetupBindings,
+ Mixin,
+ Extends
>
>
@@ -124,7 +131,9 @@ export type ThisTypedComponentOptionsWithRecordProps<
Methods,
Computed,
Props,
- SetupBindings
+ SetupBindings,
+ Mixin,
+ Extends
> = object &
ComponentOptions<
V,
@@ -133,7 +142,9 @@ export type ThisTypedComponentOptionsWithRecordProps<
Computed,
RecordPropsDefinition,
Props,
- SetupBindings
+ SetupBindings,
+ Mixin,
+ Extends
> &
ThisType<
CombinedVueInstance<
@@ -142,7 +153,9 @@ export type ThisTypedComponentOptionsWithRecordProps<
Methods,
Computed,
Readonly,
- SetupBindings
+ SetupBindings,
+ Mixin,
+ Extends
>
>
@@ -158,7 +171,9 @@ export interface ComponentOptions<
Computed = DefaultComputed,
PropsDef = PropsDefinition,
Props = DefaultProps,
- RawBindings = {}
+ RawBindings = {},
+ Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
+ Extends extends ComponentOptionsMixin = ComponentOptionsMixin
> {
data?: Data
props?: PropsDef
@@ -217,12 +232,12 @@ export interface ComponentOptions<
}
parent?: Vue
- mixins?: (ComponentOptions | typeof Vue)[]
+ mixins?: (Mixin | ComponentOptions | typeof Vue)[]
name?: string
// for SFC auto name inference w/ ts-loader check
__name?: string
// TODO: support properly inferred 'extends'
- extends?: ComponentOptions | typeof Vue
+ extends?: Extends | ComponentOptions | typeof Vue
delimiters?: [string, string]
comments?: boolean
inheritAttrs?: boolean
diff --git a/types/test/vue-test.ts b/types/test/vue-test.ts
index 8489f3ae8ed..b792cec583d 100644
--- a/types/test/vue-test.ts
+++ b/types/test/vue-test.ts
@@ -1,4 +1,4 @@
-import Vue, { VNode } from '../index'
+import Vue, { VNode, defineComponent } from '../index'
import { ComponentOptions } from '../options'
class Test extends Vue {
@@ -246,3 +246,40 @@ const ComponentWithStyleInVNodeData = Vue.extend({
])
}
})
+
+// infer mixin type with new Vue() #12730
+new Vue({
+ mixins: [
+ defineComponent({
+ props: {
+ p1: String,
+ p2: {
+ type: Number,
+ default: 0
+ }
+ },
+ data() {
+ return {
+ foo: 123
+ }
+ },
+ computed: {
+ bar() {
+ return 123
+ }
+ }
+ }),
+ {
+ methods: {
+ hello(n: number) {}
+ }
+ }
+ ],
+ created() {
+ this.hello(this.foo)
+ this.hello(this.bar)
+ // @ts-expect-error
+ this.hello(this.p1)
+ this.hello(this.p2)
+ }
+})
diff --git a/types/v3-component-public-instance.d.ts b/types/v3-component-public-instance.d.ts
index 3586f4031e8..1c55908ac73 100644
--- a/types/v3-component-public-instance.d.ts
+++ b/types/v3-component-public-instance.d.ts
@@ -79,11 +79,11 @@ type ExtractMixin = {
Mixin: MixinToOptionTypes
}[T extends ComponentOptionsMixin ? 'Mixin' : never]
-type IntersectionMixin = IsDefaultMixinComponent extends true
+export type IntersectionMixin = IsDefaultMixinComponent extends true
? OptionTypesType<{}, {}, {}, {}, {}, {}>
: UnionToIntersection>
-type UnwrapMixinsType<
+export type UnwrapMixinsType<
T,
Type extends OptionTypesKeys
> = T extends OptionTypesType ? T[Type] : never
diff --git a/types/vue.d.ts b/types/vue.d.ts
index 8c91bc88a2f..5a2027a0179 100644
--- a/types/vue.d.ts
+++ b/types/vue.d.ts
@@ -13,7 +13,15 @@ import {
import { VNode, VNodeData, VNodeChildren, NormalizedScopedSlot } from './vnode'
import { PluginFunction, PluginObject } from './plugin'
import { DefineComponent } from './v3-define-component'
-import { nextTick } from './v3-generated'
+import { nextTick, UnwrapNestedRefs, ShallowUnwrapRef } from './v3-generated'
+import {
+ UnwrapMixinsType,
+ IntersectionMixin
+} from './v3-component-public-instance'
+import {
+ ExtractComputedReturns,
+ ComponentOptionsMixin
+} from './v3-component-options'
export interface CreateElement {
(
@@ -100,12 +108,20 @@ export type CombinedVueInstance<
Methods,
Computed,
Props,
- SetupBindings = {}
-> = Data &
+ SetupBindings = {},
+ Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
+ Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
+ PublicMixin = IntersectionMixin & IntersectionMixin
+> = UnwrapNestedRefs> &
+ Data &
+ UnwrapMixinsType &
Methods &
+ ExtractComputedReturns> &
Computed &
+ UnwrapMixinsType &
Props &
Instance &
+ ShallowUnwrapRef> &
(SetupBindings extends void ? {} : SetupBindings)
export type ExtendedVue<
@@ -114,9 +130,20 @@ export type ExtendedVue<
Methods,
Computed,
Props,
- SetupBindings = {}
+ SetupBindings = {},
+ Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
+ Extends extends ComponentOptionsMixin = ComponentOptionsMixin
> = VueConstructor<
- CombinedVueInstance &
+ CombinedVueInstance<
+ Instance,
+ Data,
+ Methods,
+ Computed,
+ Props,
+ SetupBindings,
+ Mixin,
+ Extends
+ > &
Vue
>
@@ -142,7 +169,9 @@ export interface VueConstructor {
Methods = object,
Computed = object,
PropNames extends string = never,
- SetupBindings = {}
+ SetupBindings = {},
+ Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
+ Extends extends ComponentOptionsMixin = ComponentOptionsMixin
>(
options?: ThisTypedComponentOptionsWithArrayProps<
V,
@@ -150,7 +179,9 @@ export interface VueConstructor {
Methods,
Computed,
PropNames,
- SetupBindings
+ SetupBindings,
+ Mixin,
+ Extends
>
): CombinedVueInstance<
V,
@@ -158,7 +189,9 @@ export interface VueConstructor {
Methods,
Computed,
Record,
- SetupBindings
+ SetupBindings,
+ Mixin,
+ Extends
>
/**
@@ -172,7 +205,9 @@ export interface VueConstructor {
Methods = object,
Computed = object,
Props = object,
- SetupBindings = {}
+ SetupBindings = {},
+ Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
+ Extends extends ComponentOptionsMixin = ComponentOptionsMixin
>(
options?: ThisTypedComponentOptionsWithRecordProps<
V,
@@ -180,7 +215,9 @@ export interface VueConstructor {
Methods,
Computed,
Props,
- SetupBindings
+ SetupBindings,
+ Mixin,
+ Extends
>
): CombinedVueInstance<
V,
@@ -188,7 +225,9 @@ export interface VueConstructor {
Methods,
Computed,
Record,
- SetupBindings
+ SetupBindings,
+ Mixin,
+ Extends
>
/**
@@ -211,7 +250,9 @@ export interface VueConstructor {
Methods,
Computed,
PropNames extends string = never,
- SetupBindings = {}
+ SetupBindings = {},
+ Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
+ Extends extends ComponentOptionsMixin = ComponentOptionsMixin
>(
options?: ThisTypedComponentOptionsWithArrayProps<
V,
@@ -219,7 +260,9 @@ export interface VueConstructor {
Methods,
Computed,
PropNames,
- SetupBindings
+ SetupBindings,
+ Mixin,
+ Extends
>
): ExtendedVue<
V,
@@ -227,22 +270,43 @@ export interface VueConstructor {
Methods,
Computed,
Record,
- SetupBindings
+ SetupBindings,
+ Mixin,
+ Extends
>
/**
* extend with object props
*/
- extend(
+ extend<
+ Data,
+ Methods,
+ Computed,
+ Props,
+ SetupBindings = {},
+ Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
+ Extends extends ComponentOptionsMixin = ComponentOptionsMixin
+ >(
options?: ThisTypedComponentOptionsWithRecordProps<
V,
Data,
Methods,
Computed,
Props,
- SetupBindings
+ SetupBindings,
+ Mixin,
+ Extends
>
- ): ExtendedVue
+ ): ExtendedVue<
+ V,
+ Data,
+ Methods,
+ Computed,
+ Props,
+ SetupBindings,
+ Mixin,
+ Extends
+ >
/**
* extend with functional + array props
@@ -287,7 +351,9 @@ export interface VueConstructor {
Methods,
Computed,
PropNames extends string = never,
- SetupBindings = {}
+ SetupBindings = {},
+ Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
+ Extends extends ComponentOptionsMixin = ComponentOptionsMixin
>(
id: string,
definition?: ThisTypedComponentOptionsWithArrayProps<
@@ -296,7 +362,9 @@ export interface VueConstructor {
Methods,
Computed,
PropNames,
- SetupBindings
+ SetupBindings,
+ Mixin,
+ Extends
>
): ExtendedVue<
V,
@@ -304,9 +372,19 @@ export interface VueConstructor {
Methods,
Computed,
Record,
- SetupBindings
+ SetupBindings,
+ Mixin,
+ Extends
>
- component(
+ component<
+ Data,
+ Methods,
+ Computed,
+ Props,
+ SetupBindings,
+ Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
+ Extends extends ComponentOptionsMixin = ComponentOptionsMixin
+ >(
id: string,
definition?: ThisTypedComponentOptionsWithRecordProps<
V,
@@ -314,7 +392,9 @@ export interface VueConstructor {
Methods,
Computed,
Props,
- SetupBindings
+ SetupBindings,
+ Mixin,
+ Extends
>
): ExtendedVue
component(
From 5221d4d3b6049c87d196d99dbb64bcd3f3b07279 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9E=97=E7=83=81=E5=A3=95?= <1138674510@qq.com>
Date: Thu, 18 Aug 2022 16:01:00 +0800
Subject: [PATCH 09/41] fix(compiler-sfc): rewriteDefault for class with
decorators (#12747)
---
packages/compiler-sfc/src/rewriteDefault.ts | 7 +-
.../compiler-sfc/test/rewriteDefault.spec.ts | 245 ++++++++++++++++++
2 files changed, 251 insertions(+), 1 deletion(-)
create mode 100644 packages/compiler-sfc/test/rewriteDefault.spec.ts
diff --git a/packages/compiler-sfc/src/rewriteDefault.ts b/packages/compiler-sfc/src/rewriteDefault.ts
index ced9f56d8a9..e61cf691bba 100644
--- a/packages/compiler-sfc/src/rewriteDefault.ts
+++ b/packages/compiler-sfc/src/rewriteDefault.ts
@@ -42,7 +42,12 @@ export function rewriteDefault(
}).program.body
ast.forEach(node => {
if (node.type === 'ExportDefaultDeclaration') {
- s.overwrite(node.start!, node.declaration.start!, `const ${as} = `)
+ if (node.declaration.type === 'ClassDeclaration') {
+ s.overwrite(node.start!, node.declaration.id.start!, `class `)
+ s.append(`\nconst ${as} = ${node.declaration.id.name}`)
+ } else {
+ s.overwrite(node.start!, node.declaration.start!, `const ${as} = `)
+ }
}
if (node.type === 'ExportNamedDeclaration') {
for (const specifier of node.specifiers) {
diff --git a/packages/compiler-sfc/test/rewriteDefault.spec.ts b/packages/compiler-sfc/test/rewriteDefault.spec.ts
new file mode 100644
index 00000000000..9fb4c64bbb3
--- /dev/null
+++ b/packages/compiler-sfc/test/rewriteDefault.spec.ts
@@ -0,0 +1,245 @@
+import { rewriteDefault } from '../src'
+
+describe('compiler sfc: rewriteDefault', () => {
+ test('without export default', () => {
+ expect(rewriteDefault(`export a = {}`, 'script')).toMatchInlineSnapshot(`
+ "export a = {}
+ const script = {}"
+ `)
+ })
+
+ test('rewrite export default', () => {
+ expect(
+ rewriteDefault(`export default {}`, 'script')
+ ).toMatchInlineSnapshot(`"const script = {}"`)
+ })
+
+ test('rewrite export named default', () => {
+ expect(
+ rewriteDefault(
+ `const a = 1 \n export { a as b, a as default, a as c}`,
+ 'script'
+ )
+ ).toMatchInlineSnapshot(`
+ "const a = 1
+ export { a as b, a as c}
+ const script = a"
+ `)
+
+ expect(
+ rewriteDefault(
+ `const a = 1 \n export { a as b, a as default , a as c}`,
+ 'script'
+ )
+ ).toMatchInlineSnapshot(`
+ "const a = 1
+ export { a as b, a as c}
+ const script = a"
+ `)
+ })
+
+ test('w/ comments', async () => {
+ expect(rewriteDefault(`// export default\nexport default {}`, 'script'))
+ .toMatchInlineSnapshot(`
+ "// export default
+ const script = {}"
+ `)
+ })
+
+ test('export named default multiline', () => {
+ expect(
+ rewriteDefault(`let App = {}\n export {\nApp as default\n}`, '_sfc_main')
+ ).toMatchInlineSnapshot(`
+ "let App = {}
+ export {
+
+ }
+ const _sfc_main = App"
+ `)
+ })
+
+ test('export named default multiline /w comments', () => {
+ expect(
+ rewriteDefault(
+ `const a = 1 \n export {\n a as b,\n a as default,\n a as c}\n` +
+ `// export { myFunction as default }`,
+ 'script'
+ )
+ ).toMatchInlineSnapshot(`
+ "const a = 1
+ export {
+ a as b,
+
+ a as c}
+ // export { myFunction as default }
+ const script = a"
+ `)
+
+ expect(
+ rewriteDefault(
+ `const a = 1 \n export {\n a as b,\n a as default ,\n a as c}\n` +
+ `// export { myFunction as default }`,
+ 'script'
+ )
+ ).toMatchInlineSnapshot(`
+ "const a = 1
+ export {
+ a as b,
+
+ a as c}
+ // export { myFunction as default }
+ const script = a"
+ `)
+ })
+
+ test(`export { default } from '...'`, async () => {
+ expect(
+ rewriteDefault(`export { default, foo } from './index.js'`, 'script')
+ ).toMatchInlineSnapshot(`
+ "import { default as __VUE_DEFAULT__ } from './index.js'
+ export { foo } from './index.js'
+ const script = __VUE_DEFAULT__"
+ `)
+
+ expect(
+ rewriteDefault(`export { default , foo } from './index.js'`, 'script')
+ ).toMatchInlineSnapshot(`
+ "import { default as __VUE_DEFAULT__ } from './index.js'
+ export { foo } from './index.js'
+ const script = __VUE_DEFAULT__"
+ `)
+
+ expect(
+ rewriteDefault(`export { foo, default } from './index.js'`, 'script')
+ ).toMatchInlineSnapshot(`
+ "import { default as __VUE_DEFAULT__ } from './index.js'
+ export { foo, } from './index.js'
+ const script = __VUE_DEFAULT__"
+ `)
+
+ expect(
+ rewriteDefault(
+ `export { foo as default, bar } from './index.js'`,
+ 'script'
+ )
+ ).toMatchInlineSnapshot(`
+ "import { foo } from './index.js'
+ export { bar } from './index.js'
+ const script = foo"
+ `)
+
+ expect(
+ rewriteDefault(
+ `export { foo as default , bar } from './index.js'`,
+ 'script'
+ )
+ ).toMatchInlineSnapshot(`
+ "import { foo } from './index.js'
+ export { bar } from './index.js'
+ const script = foo"
+ `)
+
+ expect(
+ rewriteDefault(
+ `export { bar, foo as default } from './index.js'`,
+ 'script'
+ )
+ ).toMatchInlineSnapshot(`
+ "import { foo } from './index.js'
+ export { bar, } from './index.js'
+ const script = foo"
+ `)
+ })
+
+ test('export default class', async () => {
+ expect(rewriteDefault(`export default class Foo {}`, 'script'))
+ .toMatchInlineSnapshot(`
+ "class Foo {}
+ const script = Foo"
+ `)
+ })
+
+ test('export default class w/ comments', async () => {
+ expect(
+ rewriteDefault(`// export default\nexport default class Foo {}`, 'script')
+ ).toMatchInlineSnapshot(`
+ "// export default
+ class Foo {}
+ const script = Foo"
+ `)
+ })
+
+ test('export default class w/ comments 2', async () => {
+ expect(
+ rewriteDefault(
+ `export default {}\n` + `// export default class Foo {}`,
+ 'script'
+ )
+ ).toMatchInlineSnapshot(`
+ "const script = {}
+ // export default class Foo {}"
+ `)
+ })
+
+ test('export default class w/ comments 3', async () => {
+ expect(
+ rewriteDefault(
+ `/*\nexport default class Foo {}*/\n` + `export default class Bar {}`,
+ 'script'
+ )
+ ).toMatchInlineSnapshot(`
+ "/*
+ export default class Foo {}*/
+ class Bar {}
+ const script = Bar"
+ `)
+ })
+
+ test('@Component\nexport default class', async () => {
+ expect(rewriteDefault(`@Component\nexport default class Foo {}`, 'script'))
+ .toMatchInlineSnapshot(`
+ "@Component
+ class Foo {}
+ const script = Foo"
+ `)
+ })
+
+ test('@Component\nexport default class w/ comments', async () => {
+ expect(
+ rewriteDefault(`// export default\n@Component\nexport default class Foo {}`, 'script')
+ ).toMatchInlineSnapshot(`
+ "// export default
+ @Component
+ class Foo {}
+ const script = Foo"
+ `)
+ })
+
+ test('@Component\nexport default class w/ comments 2', async () => {
+ expect(
+ rewriteDefault(
+ `export default {}\n` + `// @Component\n// export default class Foo {}`,
+ 'script'
+ )
+ ).toMatchInlineSnapshot(`
+ "const script = {}
+ // @Component
+ // export default class Foo {}"
+ `)
+ })
+
+ test('@Component\nexport default class w/ comments 3', async () => {
+ expect(
+ rewriteDefault(
+ `/*\n@Component\nexport default class Foo {}*/\n` + `export default class Bar {}`,
+ 'script'
+ )
+ ).toMatchInlineSnapshot(`
+ "/*
+ @Component
+ export default class Foo {}*/
+ class Bar {}
+ const script = Bar"
+ `)
+ })
+})
From 2263948c249e7486403bc5880712e6d9fd15c17f Mon Sep 17 00:00:00 2001
From: JuniorTour
Date: Thu, 18 Aug 2022 16:11:47 +0800
Subject: [PATCH 10/41] fix: directives shorthand normalize error (#12744)
fix #12743
---
src/core/vdom/modules/directives.ts | 10 +++++++++-
test/unit/features/v3/apiSetup.spec.ts | 13 +++++++++++++
2 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/src/core/vdom/modules/directives.ts b/src/core/vdom/modules/directives.ts
index 9e4a87f7f6e..853b20021e7 100644
--- a/src/core/vdom/modules/directives.ts
+++ b/src/core/vdom/modules/directives.ts
@@ -103,7 +103,15 @@ function normalizeDirectives(
}
res[getRawDirName(dir)] = dir
if (vm._setupState && vm._setupState.__sfc) {
- dir.def = dir.def || resolveAsset(vm, '_setupState', 'v-' + dir.name)
+ const setupDef = dir.def || resolveAsset(vm, '_setupState', 'v-' + dir.name)
+ if (typeof setupDef === 'function') {
+ dir.def = {
+ bind: setupDef,
+ update: setupDef,
+ }
+ } else {
+ dir.def = setupDef
+ }
}
dir.def = dir.def || resolveAsset(vm.$options, 'directives', dir.name, true)
}
diff --git a/test/unit/features/v3/apiSetup.spec.ts b/test/unit/features/v3/apiSetup.spec.ts
index 7c69d06d1c4..11757878e9c 100644
--- a/test/unit/features/v3/apiSetup.spec.ts
+++ b/test/unit/features/v3/apiSetup.spec.ts
@@ -251,6 +251,19 @@ describe('api: setup context', () => {
expect(spy).toHaveBeenCalled()
})
+ // #12743
+ it('directive resolution for shorthand', () => {
+ const spy = vi.fn()
+ new Vue({
+ setup: () => ({
+ __sfc: true,
+ vDir: spy
+ }),
+ template: ``
+ }).$mount()
+ expect(spy).toHaveBeenCalled()
+ })
+
// #12561
it('setup props should be reactive', () => {
const msg = ref('hi')
From 9eb8ea5b63eec2b09f268738e9d0e311d9eafb19 Mon Sep 17 00:00:00 2001
From: GU Yiling
Date: Thu, 18 Aug 2022 16:12:20 +0800
Subject: [PATCH 11/41] chore: fix some legacy doc urls in warnings and readme
(#12725) [ci skip]
---
README.md | 2 +-
src/core/instance/proxy.ts | 4 ++--
src/core/instance/state.ts | 2 +-
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index 5a3f576d716..5eef53d3fa0 100644
--- a/README.md
+++ b/README.md
@@ -73,7 +73,7 @@ Vue.js supports all browsers that are [ES5-compliant](https://kangax.github.io/c
## Documentation
-To check out [live examples](https://vuejs.org/v2/examples/) and docs, visit [vuejs.org](https://vuejs.org).
+To check out [live examples](https://v2.vuejs.org/v2/examples/) and docs, visit [vuejs.org](https://v2.vuejs.org).
## Questions
diff --git a/src/core/instance/proxy.ts b/src/core/instance/proxy.ts
index 3543d74954a..685d9651fcc 100644
--- a/src/core/instance/proxy.ts
+++ b/src/core/instance/proxy.ts
@@ -19,7 +19,7 @@ if (__DEV__) {
'referenced during render. Make sure that this property is reactive, ' +
'either in the data option, or for class-based components, by ' +
'initializing the property. ' +
- 'See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.',
+ 'See: https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.',
target
)
}
@@ -29,7 +29,7 @@ if (__DEV__) {
`Property "${key}" must be accessed with "$data.${key}" because ` +
'properties starting with "$" or "_" are not proxied in the Vue instance to ' +
'prevent conflicts with Vue internals. ' +
- 'See: https://vuejs.org/v2/api/#data',
+ 'See: https://v2.vuejs.org/v2/api/#data',
target
)
}
diff --git a/src/core/instance/state.ts b/src/core/instance/state.ts
index e22ec6705fb..aedb72555c9 100644
--- a/src/core/instance/state.ts
+++ b/src/core/instance/state.ts
@@ -127,7 +127,7 @@ function initData(vm: Component) {
__DEV__ &&
warn(
'data functions should return an object:\n' +
- 'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',
+ 'https://v2.vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',
vm
)
}
From bba6b3d6b4e3e26d28abbf20e74ec2f3e64f1a92 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E4=B8=8D=E8=A7=81=E6=9C=88?=
<61452855+nooooooom@users.noreply.github.com>
Date: Thu, 18 Aug 2022 16:20:27 +0800
Subject: [PATCH 12/41] feat(types): enhance type for onErrorCaptured (#12735)
---
src/v3/apiLifecycle.ts | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/src/v3/apiLifecycle.ts b/src/v3/apiLifecycle.ts
index dc47bc4652b..31e0542920c 100644
--- a/src/v3/apiLifecycle.ts
+++ b/src/v3/apiLifecycle.ts
@@ -42,7 +42,6 @@ export const onBeforeUpdate = createLifeCycle('beforeUpdate')
export const onUpdated = createLifeCycle('updated')
export const onBeforeUnmount = createLifeCycle('beforeDestroy')
export const onUnmounted = createLifeCycle('destroyed')
-export const onErrorCaptured = createLifeCycle('errorCaptured')
export const onActivated = createLifeCycle('activated')
export const onDeactivated = createLifeCycle('deactivated')
export const onServerPrefetch = createLifeCycle('serverPrefetch')
@@ -51,3 +50,19 @@ export const onRenderTracked =
createLifeCycle<(e: DebuggerEvent) => any>('renderTracked')
export const onRenderTriggered =
createLifeCycle<(e: DebuggerEvent) => any>('renderTriggered')
+
+export type ErrorCapturedHook = (
+ err: TError,
+ instance: any,
+ info: string
+) => boolean | void
+
+const injectErrorCapturedHook =
+ createLifeCycle>('errorCaptured')
+
+export function onErrorCaptured(
+ hook: ErrorCapturedHook,
+ target: any = currentInstance
+) {
+ injectErrorCapturedHook(hook, target)
+}
From 165a14a6c6c406176037465d2961259c5c980399 Mon Sep 17 00:00:00 2001
From: Alexander Lichter
Date: Thu, 18 Aug 2022 10:22:55 +0200
Subject: [PATCH 13/41] fix(ssr): fix on-component directives rendering
(#12661)
fix #10733
---
packages/server-renderer/src/render.ts | 10 +-
.../server-renderer/test/ssr-string.spec.ts | 94 ++++++++++++++++++-
src/core/vdom/vnode.ts | 1 +
3 files changed, 103 insertions(+), 2 deletions(-)
diff --git a/packages/server-renderer/src/render.ts b/packages/server-renderer/src/render.ts
index 907b795d797..b1116840ed5 100644
--- a/packages/server-renderer/src/render.ts
+++ b/packages/server-renderer/src/render.ts
@@ -206,6 +206,11 @@ function renderComponentInner(node, isRoot, context) {
type: 'Component',
prevActive
})
+ if (isDef(node.data) && isDef(node.data.directives)) {
+ childNode.data = childNode.data || {}
+ childNode.data.directives = node.data.directives
+ childNode.isComponentRootElement = true
+ }
renderNode(childNode, isRoot, context)
}
@@ -372,7 +377,10 @@ function renderStartingTag(node: VNode, context) {
if (dirRenderer) {
// directives mutate the node's data
// which then gets rendered by modules
- dirRenderer(node, dirs[i])
+ dirRenderer(
+ node.isComponentRootElement ? node.parent : node,
+ dirs[i]
+ )
}
}
}
diff --git a/packages/server-renderer/test/ssr-string.spec.ts b/packages/server-renderer/test/ssr-string.spec.ts
index 35810c8ed58..391671c1e52 100644
--- a/packages/server-renderer/test/ssr-string.spec.ts
+++ b/packages/server-renderer/test/ssr-string.spec.ts
@@ -1086,7 +1086,7 @@ describe('SSR: renderToString', () => {
)
})
- it('custom directives', done => {
+ it('custom directives on raw element', done => {
const renderer = createRenderer({
directives: {
'class-prefixer': (node, dir) => {
@@ -1129,6 +1129,98 @@ describe('SSR: renderToString', () => {
)
})
+ it('custom directives on component', done => {
+ const Test = {
+ template: 'hello world'
+ }
+ const renderer = createRenderer({
+ directives: {
+ 'class-prefixer': (node, dir) => {
+ if (node.data.class) {
+ node.data.class = `${dir.value}-${node.data.class}`
+ }
+ if (node.data.staticClass) {
+ node.data.staticClass = `${dir.value}-${node.data.staticClass}`
+ }
+ }
+ }
+ })
+ renderer.renderToString(
+ new Vue({
+ template:
+ '
',
+ components: { Test }
+ }),
+ (err, result) => {
+ expect(err).toBeNull()
+ expect(result).toContain(
+ 'hello world
'
+ )
+ done()
+ }
+ )
+ })
+
+ it('custom directives on element root of a component', done => {
+ const Test = {
+ template:
+ 'hello world'
+ }
+ const renderer = createRenderer({
+ directives: {
+ 'class-prefixer': (node, dir) => {
+ if (node.data.class) {
+ node.data.class = `${dir.value}-${node.data.class}`
+ }
+ if (node.data.staticClass) {
+ node.data.staticClass = `${dir.value}-${node.data.staticClass}`
+ }
+ }
+ }
+ })
+ renderer.renderToString(
+ new Vue({
+ template: '
',
+ components: { Test }
+ }),
+ (err, result) => {
+ expect(err).toBeNull()
+ expect(result).toContain(
+ 'hello world
'
+ )
+ done()
+ }
+ )
+ })
+
+ it('custom directives on element with parent element', done => {
+ const renderer = createRenderer({
+ directives: {
+ 'class-prefixer': (node, dir) => {
+ if (node.data.class) {
+ node.data.class = `${dir.value}-${node.data.class}`
+ }
+ if (node.data.staticClass) {
+ node.data.staticClass = `${dir.value}-${node.data.staticClass}`
+ }
+ }
+ }
+ })
+ renderer.renderToString(
+ new Vue({
+ template:
+ 'hello world
'
+ }),
+ (err, result) => {
+ expect(err).toBeNull()
+ expect(result).toContain(
+ 'hello world
'
+ )
+ done()
+ }
+ )
+ })
+
it('should not warn for custom directives that do not have server-side implementation', done => {
renderToString(
new Vue({
diff --git a/src/core/vdom/vnode.ts b/src/core/vdom/vnode.ts
index 80f784167ba..3b57f9aca0c 100644
--- a/src/core/vdom/vnode.ts
+++ b/src/core/vdom/vnode.ts
@@ -33,6 +33,7 @@ export default class VNode {
fnOptions?: ComponentOptions | null // for SSR caching
devtoolsMeta?: Object | null // used to store functional render context for devtools
fnScopeId?: string | null // functional scope id support
+ isComponentRootElement?: boolean | null // for SSR directives
constructor(
tag?: string,
From 7161176cd0dff10d65ab58e266018aff2660610f Mon Sep 17 00:00:00 2001
From: Evan You
Date: Thu, 18 Aug 2022 18:14:50 +0800
Subject: [PATCH 14/41] fix: fix effect scope tracking for manually created
instances
fix #12705
---
src/core/instance/init.ts | 1 +
src/core/instance/lifecycle.ts | 2 --
src/core/observer/watcher.ts | 11 ++++++++++-
src/v3/reactivity/effectScope.ts | 6 +++++-
4 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/src/core/instance/init.ts b/src/core/instance/init.ts
index 876c9ddbf96..91456c21920 100644
--- a/src/core/instance/init.ts
+++ b/src/core/instance/init.ts
@@ -34,6 +34,7 @@ export function initMixin(Vue: typeof Component) {
vm.__v_skip = true
// effect scope
vm._scope = new EffectScope(true /* detached */)
+ vm._scope._vm = true
// merge options
if (options && options._isComponent) {
// optimize internal component instantiation
diff --git a/src/core/instance/lifecycle.ts b/src/core/instance/lifecycle.ts
index fec330ad5fc..df70b7113fd 100644
--- a/src/core/instance/lifecycle.ts
+++ b/src/core/instance/lifecycle.ts
@@ -209,7 +209,6 @@ export function mountComponent(
// we set this to vm._watcher inside the watcher's constructor
// since the watcher's initial patch may call $forceUpdate (e.g. inside child
// component's mounted hook), which relies on vm._watcher being already defined
- vm._scope.on()
new Watcher(
vm,
updateComponent,
@@ -217,7 +216,6 @@ export function mountComponent(
watcherOptions,
true /* isRenderWatcher */
)
- vm._scope.off()
hydrating = false
// flush buffer for flush: "pre" watchers queued in setup()
diff --git a/src/core/observer/watcher.ts b/src/core/observer/watcher.ts
index 00bf19b9123..b2989b53772 100644
--- a/src/core/observer/watcher.ts
+++ b/src/core/observer/watcher.ts
@@ -71,7 +71,16 @@ export default class Watcher implements DepTarget {
options?: WatcherOptions | null,
isRenderWatcher?: boolean
) {
- recordEffectScope(this, activeEffectScope || (vm ? vm._scope : undefined))
+ recordEffectScope(
+ this,
+ // if the active effect scope is manually created (not a component scope),
+ // prioritize it
+ activeEffectScope && !activeEffectScope._vm
+ ? activeEffectScope
+ : vm
+ ? vm._scope
+ : undefined
+ )
if ((this.vm = vm) && isRenderWatcher) {
vm._watcher = this
}
diff --git a/src/v3/reactivity/effectScope.ts b/src/v3/reactivity/effectScope.ts
index bc15380eb4a..2ba50cd9ca8 100644
--- a/src/v3/reactivity/effectScope.ts
+++ b/src/v3/reactivity/effectScope.ts
@@ -27,10 +27,14 @@ export class EffectScope {
* @internal
*/
scopes: EffectScope[] | undefined
+ /**
+ * indicates this being a component root scope
+ * @internal
+ */
+ _vm?: boolean
/**
* track a child scope's index in its parent's scopes array for optimized
* removal
- * @internal
*/
private index: number | undefined
From 8521f9d3f63d26bde99b747f0cb14d0ac5ba5971 Mon Sep 17 00:00:00 2001
From: Evan You
Date: Fri, 19 Aug 2022 12:22:51 +0800
Subject: [PATCH 15/41] fix(types): fix missing error for accessing undefined
instance properties
fix #12718
---
types/test/v3/define-component-test.tsx | 62 +++++++++++++++++++++++--
types/v3-define-component.d.ts | 10 ++--
2 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/types/test/v3/define-component-test.tsx b/types/test/v3/define-component-test.tsx
index 481a2d11ac7..7e6d1968ca3 100644
--- a/types/test/v3/define-component-test.tsx
+++ b/types/test/v3/define-component-test.tsx
@@ -1166,6 +1166,62 @@ defineComponent({
}
})
-// #12742 allow attaching custom properties (consistent with v3)
-const Foo = defineComponent({})
-Foo.foobar = 123
+describe('constructor attach custom properties', () => {
+ // #12742 allow attaching custom properties (consistent with v3)
+ const Foo = defineComponent({})
+ Foo.foobar = 123
+})
+
+describe('constructor instance type', () => {
+ const Comp = defineComponent({
+ data() {
+ return {
+ a: 1
+ }
+ },
+
+ computed: {
+ ac() {
+ return 1
+ }
+ },
+
+ methods: {
+ callA(b: number) {
+ return b
+ }
+ },
+
+ setup() {
+ return {
+ sa: '1'
+ }
+ }
+ })
+
+ const comp = new Comp()
+
+ expectType(comp.a)
+ expectType(comp.ac)
+ expectType(comp.sa)
+ expectType<(b: number) => number>(comp.callA)
+})
+
+describe('should report non-existent properties in instance', () => {
+ const Foo = defineComponent({})
+ const instance = new Foo()
+ // @ts-expect-error
+ instance.foo
+
+ const Foo2 = defineComponent({
+ data() {
+ return {}
+ },
+ methods: {
+ example() {}
+ }
+ })
+ const instance2 = new Foo2()
+ // @ts-expect-error
+ instance2.foo
+})
diff --git a/types/v3-define-component.d.ts b/types/v3-define-component.d.ts
index 69f65a2ec35..03ef52d1856 100644
--- a/types/v3-define-component.d.ts
+++ b/types/v3-define-component.d.ts
@@ -72,7 +72,7 @@ export type DefineComponent<
*/
export function defineComponent<
RawBindings,
- D = Data,
+ D = {},
C extends ComputedOptions = {},
M extends MethodOptions = {},
Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
@@ -101,8 +101,8 @@ export function defineComponent<
*/
export function defineComponent<
PropNames extends string,
- RawBindings = Data,
- D = Data,
+ RawBindings = {},
+ D = {},
C extends ComputedOptions = {},
M extends MethodOptions = {},
Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
@@ -140,8 +140,8 @@ export function defineComponent<
*/
export function defineComponent<
Props,
- RawBindings = Data,
- D = Data,
+ RawBindings = {},
+ D = {},
C extends ComputedOptions = {},
M extends MethodOptions = {},
Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
From 15618888cb6aae2b6f0151b32c261b1fc19db1b8 Mon Sep 17 00:00:00 2001
From: Evan You
Date: Fri, 19 Aug 2022 12:27:12 +0800
Subject: [PATCH 16/41] release: v2.7.9
---
CHANGELOG.md | 26 +++++++++++++++++++++++++
package.json | 2 +-
packages/compiler-sfc/package.json | 2 +-
packages/server-renderer/package.json | 2 +-
packages/template-compiler/package.json | 2 +-
5 files changed, 30 insertions(+), 4 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bc98f138f33..b5d38472209 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,29 @@
+## [2.7.9](https://github.com/vuejs/vue/compare/v2.7.8...v2.7.9) (2022-08-19)
+
+
+### Bug Fixes
+
+* **compiler-sfc:** allow full hostnames in asset url base ([#12732](https://github.com/vuejs/vue/issues/12732)) ([5c742eb](https://github.com/vuejs/vue/commit/5c742eb2e0d8dad268fb29ed4f92d286b5e0f4b5)), closes [#12731](https://github.com/vuejs/vue/issues/12731)
+* **compiler-sfc:** rewriteDefault for class with decorators ([#12747](https://github.com/vuejs/vue/issues/12747)) ([5221d4d](https://github.com/vuejs/vue/commit/5221d4d3b6049c87d196d99dbb64bcd3f3b07279))
+* directives shorthand normalize error ([#12744](https://github.com/vuejs/vue/issues/12744)) ([2263948](https://github.com/vuejs/vue/commit/2263948c249e7486403bc5880712e6d9fd15c17f)), closes [#12743](https://github.com/vuejs/vue/issues/12743)
+* ensure render watcher of manually created instance is correctly tracked in owner scope ([bd89ce5](https://github.com/vuejs/vue/commit/bd89ce53a9de417a9372630bb5d433a40acc1a53)), closes [#12701](https://github.com/vuejs/vue/issues/12701)
+* fix effect scope tracking for manually created instances ([7161176](https://github.com/vuejs/vue/commit/7161176cd0dff10d65ab58e266018aff2660610f)), closes [#12705](https://github.com/vuejs/vue/issues/12705)
+* **ssr:** fix on-component directives rendering ([#12661](https://github.com/vuejs/vue/issues/12661)) ([165a14a](https://github.com/vuejs/vue/commit/165a14a6c6c406176037465d2961259c5c980399)), closes [#10733](https://github.com/vuejs/vue/issues/10733)
+* **types:** allow attaching unknown options to defined component ([b4bf4c5](https://github.com/vuejs/vue/commit/b4bf4c52ad31e02307cfd4d643dc5610c893e3ba)), closes [#12742](https://github.com/vuejs/vue/issues/12742)
+* **types:** fix missing error for accessing undefined instance properties ([8521f9d](https://github.com/vuejs/vue/commit/8521f9d3f63d26bde99b747f0cb14d0ac5ba5971)), closes [#12718](https://github.com/vuejs/vue/issues/12718)
+* **types:** fix options suggestions when using defineComponent ([4b37b56](https://github.com/vuejs/vue/commit/4b37b568c7c3fd238aa61fcc956f882223f8e87f)), closes [#12736](https://github.com/vuejs/vue/issues/12736)
+* **types:** Make SetupBindings optional on ExtendedVue and CombinedVueInstance ([#12727](https://github.com/vuejs/vue/issues/12727)) ([00458cd](https://github.com/vuejs/vue/commit/00458cd38d209410d3c675729230a42a0a34a4b9)), closes [#12726](https://github.com/vuejs/vue/issues/12726) [#12717](https://github.com/vuejs/vue/issues/12717)
+* **watch:** avoid pre watcher firing on unmount ([f0057b1](https://github.com/vuejs/vue/commit/f0057b101e6451d5095cdb7fd6308fd31ac0450c)), closes [#12703](https://github.com/vuejs/vue/issues/12703)
+
+
+### Features
+
+* **types:** enhance type for onErrorCaptured ([#12735](https://github.com/vuejs/vue/issues/12735)) ([bba6b3d](https://github.com/vuejs/vue/commit/bba6b3d6b4e3e26d28abbf20e74ec2f3e64f1a92))
+* **types:** export DefineComponent ([80d1baf](https://github.com/vuejs/vue/commit/80d1baf92050da411fb1bfe714401c498001dd36)), closes [#12748](https://github.com/vuejs/vue/issues/12748)
+* **types:** support mixins inference for new Vue() ([#12737](https://github.com/vuejs/vue/issues/12737)) ([89a6b5e](https://github.com/vuejs/vue/commit/89a6b5e8658a6e3ae2cf649829901784ac9deb3c)), closes [#12730](https://github.com/vuejs/vue/issues/12730)
+
+
+
## [2.7.8](https://github.com/vuejs/vue/compare/v2.7.7...v2.7.8) (2022-07-22)
diff --git a/package.json b/package.json
index 039c8882375..0bbc17d6b0b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "vue",
- "version": "2.7.8",
+ "version": "2.7.9",
"packageManager": "pnpm@7.1.0",
"description": "Reactive, component-oriented view layer for modern web interfaces.",
"main": "dist/vue.runtime.common.js",
diff --git a/packages/compiler-sfc/package.json b/packages/compiler-sfc/package.json
index 6a6037a3111..3e88b96778c 100644
--- a/packages/compiler-sfc/package.json
+++ b/packages/compiler-sfc/package.json
@@ -1,6 +1,6 @@
{
"name": "@vue/compiler-sfc",
- "version": "2.7.8",
+ "version": "2.7.9",
"description": "compiler-sfc for Vue 2",
"main": "dist/compiler-sfc.js",
"types": "dist/compiler-sfc.d.ts",
diff --git a/packages/server-renderer/package.json b/packages/server-renderer/package.json
index 5e8adfd83f6..784b7838cbe 100644
--- a/packages/server-renderer/package.json
+++ b/packages/server-renderer/package.json
@@ -1,6 +1,6 @@
{
"name": "vue-server-renderer",
- "version": "2.7.8",
+ "version": "2.7.9",
"description": "server renderer for Vue 2.0",
"main": "index.js",
"types": "types/index.d.ts",
diff --git a/packages/template-compiler/package.json b/packages/template-compiler/package.json
index d1be678cdfb..26bf6586f94 100644
--- a/packages/template-compiler/package.json
+++ b/packages/template-compiler/package.json
@@ -1,6 +1,6 @@
{
"name": "vue-template-compiler",
- "version": "2.7.8",
+ "version": "2.7.9",
"description": "template compiler for Vue 2.0",
"main": "index.js",
"unpkg": "browser.js",
From 810f6d12edea47cde7f39eaf7ec3ae1b7300d40c Mon Sep 17 00:00:00 2001
From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com>
Date: Sun, 21 Aug 2022 19:28:39 -0700
Subject: [PATCH 17/41] fix(types): Add missing type parameter constraints
(#12754)
---
types/options.d.ts | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/types/options.d.ts b/types/options.d.ts
index c82c6c5f8ae..9fcdaca624f 100644
--- a/types/options.d.ts
+++ b/types/options.d.ts
@@ -95,8 +95,8 @@ export type ThisTypedComponentOptionsWithArrayProps<
Computed,
PropNames extends string,
SetupBindings,
- Mixin,
- Extends
+ Mixin extends ComponentOptionsMixin,
+ Extends extends ComponentOptionsMixin
> = object &
ComponentOptions<
V,
@@ -132,8 +132,8 @@ export type ThisTypedComponentOptionsWithRecordProps<
Computed,
Props,
SetupBindings,
- Mixin,
- Extends
+ Mixin extends ComponentOptionsMixin,
+ Extends extends ComponentOptionsMixin
> = object &
ComponentOptions<
V,
From 46ca7bcddc06c50796ccff82d8c45693f1f14f47 Mon Sep 17 00:00:00 2001
From: Evan You
Date: Tue, 23 Aug 2022 09:18:36 +0800
Subject: [PATCH 18/41] fix(compiler-sfc): avoid deindent when lang is jsx/tsx
fix #12755
---
packages/compiler-sfc/src/parseComponent.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/compiler-sfc/src/parseComponent.ts b/packages/compiler-sfc/src/parseComponent.ts
index 65b858c9fc0..05489280e63 100644
--- a/packages/compiler-sfc/src/parseComponent.ts
+++ b/packages/compiler-sfc/src/parseComponent.ts
@@ -179,11 +179,11 @@ export function parseComponent(
let text = source.slice(currentBlock.start, currentBlock.end)
if (
options.deindent === true ||
- // by default, deindent unless it's script with default lang or ts
+ // by default, deindent unless it's script with default lang or (j/t)sx?
(options.deindent !== false &&
!(
currentBlock.type === 'script' &&
- (!currentBlock.lang || currentBlock.lang === 'ts')
+ (!currentBlock.lang || /^(j|t)sx?$/.test(currentBlock.lang))
))
) {
text = deindent(text)
From e0b26c483a1ba407a818b1fcba1a439df24e84a8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E4=B8=8D=E8=A7=81=E6=9C=88?=
<61452855+nooooooom@users.noreply.github.com>
Date: Tue, 23 Aug 2022 09:22:45 +0800
Subject: [PATCH 19/41] fix: fix parent of multi-nested HOC $el not updating
(#12757)
fix #12589
---
src/core/instance/lifecycle.ts | 11 +++++++++--
test/unit/modules/vdom/patch/edge-cases.spec.ts | 4 ++++
2 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/src/core/instance/lifecycle.ts b/src/core/instance/lifecycle.ts
index df70b7113fd..94f42e27eb5 100644
--- a/src/core/instance/lifecycle.ts
+++ b/src/core/instance/lifecycle.ts
@@ -83,8 +83,15 @@ export function lifecycleMixin(Vue: typeof Component) {
vm.$el.__vue__ = vm
}
// if parent is an HOC, update its $el as well
- if (vm.$vnode && vm.$parent && vm.$vnode === vm.$parent._vnode) {
- vm.$parent.$el = vm.$el
+ let wrapper: Component | undefined = vm
+ while (
+ wrapper &&
+ wrapper.$vnode &&
+ wrapper.$parent &&
+ wrapper.$vnode === wrapper.$parent._vnode
+ ) {
+ wrapper.$parent.$el = wrapper.$el
+ wrapper = wrapper.$parent
}
// updated hook is called by the scheduler to ensure that children are
// updated in a parent's updated hook.
diff --git a/test/unit/modules/vdom/patch/edge-cases.spec.ts b/test/unit/modules/vdom/patch/edge-cases.spec.ts
index 10b8ad8179d..f9295533b1e 100644
--- a/test/unit/modules/vdom/patch/edge-cases.spec.ts
+++ b/test/unit/modules/vdom/patch/edge-cases.spec.ts
@@ -257,11 +257,15 @@ describe('vdom patch: edge cases', () => {
expect(vm.$refs.foo.$refs.bar.$el.tagName).toBe('DIV')
expect(vm.$refs.foo.$refs.bar.$el.className).toBe(`hello`)
+ expect(vm.$el.tagName).toBe('DIV')
+ expect(vm.$el.className).toBe(`hello`)
vm.$refs.foo.$refs.bar.ok = false
waitForUpdate(() => {
expect(vm.$refs.foo.$refs.bar.$el.tagName).toBe('SPAN')
expect(vm.$refs.foo.$refs.bar.$el.className).toBe(`hello`)
+ expect(vm.$el.tagName).toBe('SPAN')
+ expect(vm.$el.className).toBe(`hello`)
}).then(done)
})
From ee57d9fd1d51abe245c6c37e6f8f2d45977b929e Mon Sep 17 00:00:00 2001
From: Evan You
Date: Tue, 23 Aug 2022 09:29:42 +0800
Subject: [PATCH 20/41] release: v2.7.10
---
CHANGELOG.md | 11 +++++++++++
package.json | 2 +-
packages/compiler-sfc/package.json | 2 +-
packages/server-renderer/package.json | 2 +-
packages/template-compiler/package.json | 2 +-
5 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b5d38472209..3ccae2540a9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,14 @@
+## [2.7.10](https://github.com/vuejs/vue/compare/v2.7.9...v2.7.10) (2022-08-23)
+
+
+### Bug Fixes
+
+* **compiler-sfc:** avoid deindent when lang is jsx/tsx ([46ca7bc](https://github.com/vuejs/vue/commit/46ca7bcddc06c50796ccff82d8c45693f1f14f47)), closes [#12755](https://github.com/vuejs/vue/issues/12755)
+* fix parent of multi-nested HOC $el not updating ([#12757](https://github.com/vuejs/vue/issues/12757)) ([e0b26c4](https://github.com/vuejs/vue/commit/e0b26c483a1ba407a818b1fcba1a439df24e84a8)), closes [#12589](https://github.com/vuejs/vue/issues/12589)
+* **types:** Add missing type parameter constraints ([#12754](https://github.com/vuejs/vue/issues/12754)) ([810f6d1](https://github.com/vuejs/vue/commit/810f6d12edea47cde7f39eaf7ec3ae1b7300d40c))
+
+
+
## [2.7.9](https://github.com/vuejs/vue/compare/v2.7.8...v2.7.9) (2022-08-19)
diff --git a/package.json b/package.json
index 0bbc17d6b0b..e8750ff7385 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "vue",
- "version": "2.7.9",
+ "version": "2.7.10",
"packageManager": "pnpm@7.1.0",
"description": "Reactive, component-oriented view layer for modern web interfaces.",
"main": "dist/vue.runtime.common.js",
diff --git a/packages/compiler-sfc/package.json b/packages/compiler-sfc/package.json
index 3e88b96778c..115ae6e775b 100644
--- a/packages/compiler-sfc/package.json
+++ b/packages/compiler-sfc/package.json
@@ -1,6 +1,6 @@
{
"name": "@vue/compiler-sfc",
- "version": "2.7.9",
+ "version": "2.7.10",
"description": "compiler-sfc for Vue 2",
"main": "dist/compiler-sfc.js",
"types": "dist/compiler-sfc.d.ts",
diff --git a/packages/server-renderer/package.json b/packages/server-renderer/package.json
index 784b7838cbe..5470ebfaca3 100644
--- a/packages/server-renderer/package.json
+++ b/packages/server-renderer/package.json
@@ -1,6 +1,6 @@
{
"name": "vue-server-renderer",
- "version": "2.7.9",
+ "version": "2.7.10",
"description": "server renderer for Vue 2.0",
"main": "index.js",
"types": "types/index.d.ts",
diff --git a/packages/template-compiler/package.json b/packages/template-compiler/package.json
index 26bf6586f94..75285bc0e85 100644
--- a/packages/template-compiler/package.json
+++ b/packages/template-compiler/package.json
@@ -1,6 +1,6 @@
{
"name": "vue-template-compiler",
- "version": "2.7.9",
+ "version": "2.7.10",
"description": "template compiler for Vue 2.0",
"main": "index.js",
"unpkg": "browser.js",
From d189b4beaa90b9fe58fd3f66ba9e09d340755196 Mon Sep 17 00:00:00 2001
From: Evan You
Date: Thu, 1 Sep 2022 14:30:09 +0800
Subject: [PATCH 21/41] chore: special sponsor [ci skip]
---
README.md | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/README.md b/README.md
index 5eef53d3fa0..cfaef3e361e 100644
--- a/README.md
+++ b/README.md
@@ -17,6 +17,16 @@ You are looking at the repository for Vue 2. The repo for Vue 3 is [vuejs/core](
Vue.js is an MIT-licensed open source project with its ongoing development made possible entirely by the support of these awesome [backers](https://github.com/vuejs/core/blob/main/BACKERS.md). If you'd like to join them, please consider [ sponsor Vue's development](https://vuejs.org/sponsor/).
+
+
Special Sponsor
+
+
+
+
+
+
+
+
From 60d268c4261a0b9c5125f308468b31996a8145ad Mon Sep 17 00:00:00 2001
From: Evan You
Date: Thu, 1 Sep 2022 14:31:31 +0800
Subject: [PATCH 22/41] chore: cache bust svg [ci skip]
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index cfaef3e361e..bca41a49405 100644
--- a/README.md
+++ b/README.md
@@ -29,7 +29,7 @@ Vue.js is an MIT-licensed open source project with its ongoing development made
-
+
From 2f335b2f9d09b962f40e38740826d444e4fff073 Mon Sep 17 00:00:00 2001
From: Evan You
Date: Tue, 11 Oct 2022 11:41:31 +0800
Subject: [PATCH 23/41] fix(sfc): remove sfc scoped deep syntax deprecation
warnings
---
.../compiler-sfc/src/stylePlugins/scoped.ts | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/packages/compiler-sfc/src/stylePlugins/scoped.ts b/packages/compiler-sfc/src/stylePlugins/scoped.ts
index 25332731ef6..55f17c386f3 100644
--- a/packages/compiler-sfc/src/stylePlugins/scoped.ts
+++ b/packages/compiler-sfc/src/stylePlugins/scoped.ts
@@ -1,6 +1,5 @@
import { PluginCreator, Rule, AtRule } from 'postcss'
import selectorParser from 'postcss-selector-parser'
-import { warn } from '../warn'
const animationNameRE = /^(-\w+-)?animation-name$/
const animationRE = /^(-\w+-)?animation$/
@@ -94,10 +93,10 @@ function rewriteSelector(
) {
n.value = ' '
n.spaces.before = n.spaces.after = ''
- warn(
- `the >>> and /deep/ combinators have been deprecated. ` +
- `Use :deep() instead.`
- )
+ // warn(
+ // `the >>> and /deep/ combinators have been deprecated. ` +
+ // `Use :deep() instead.`
+ // )
return false
}
@@ -126,12 +125,12 @@ function rewriteSelector(
}
selector.removeChild(n)
} else {
- // DEPRECATED usage
+ // DEPRECATED usage in v3
// .foo ::v-deep .bar -> .foo[xxxxxxx] .bar
- warn(
- `::v-deep usage as a combinator has ` +
- `been deprecated. Use :deep() instead.`
- )
+ // warn(
+ // `::v-deep usage as a combinator has ` +
+ // `been deprecated. Use :deep() instead.`
+ // )
const prev = selector.at(selector.index(n) - 1)
if (prev && isSpaceCombinator(prev)) {
selector.removeChild(prev)
From 27eed829ccf9978a63b8cd989ff4c03897276bc2 Mon Sep 17 00:00:00 2001
From: ZHAO Jinxiang
Date: Mon, 10 Oct 2022 20:51:05 -0700
Subject: [PATCH 24/41] fix(types): vue 3 directive type compatibility (#12792)
---
types/options.d.ts | 7 +++++++
types/vue.d.ts | 5 +++++
2 files changed, 12 insertions(+)
diff --git a/types/options.d.ts b/types/options.d.ts
index 9fcdaca624f..93379edbef2 100644
--- a/types/options.d.ts
+++ b/types/options.d.ts
@@ -4,6 +4,7 @@ import { SetupContext } from './v3-setup-context'
import { DebuggerEvent } from './v3-generated'
import { DefineComponent } from './v3-define-component'
import { ComponentOptionsMixin } from './v3-component-options'
+import { ObjectDirective, FunctionDirective } from './v3-directive'
type Constructor = {
new (...args: any[]): any
@@ -318,6 +319,9 @@ export interface DirectiveBinding extends Readonly {
readonly modifiers: { [key: string]: boolean }
}
+/**
+ * @deprecated use {@link FunctionDirective} instead
+ */
export type DirectiveFunction = (
el: HTMLElement,
binding: DirectiveBinding,
@@ -325,6 +329,9 @@ export type DirectiveFunction = (
oldVnode: VNode
) => void
+/**
+ * @deprecated use {@link ObjectDirective} instead
+ */
export interface DirectiveOptions {
bind?: DirectiveFunction
inserted?: DirectiveFunction
diff --git a/types/vue.d.ts b/types/vue.d.ts
index 5a2027a0179..f158cf01716 100644
--- a/types/vue.d.ts
+++ b/types/vue.d.ts
@@ -22,6 +22,7 @@ import {
ExtractComputedReturns,
ComponentOptionsMixin
} from './v3-component-options'
+import { Directive, ObjectDirective } from './v3-directive'
export interface CreateElement {
(
@@ -338,6 +339,10 @@ export interface VueConstructor {
id: string,
definition?: DirectiveOptions | DirectiveFunction
): DirectiveOptions
+ directive(
+ id: string,
+ definition?: Directive
+ ): ObjectDirective
filter(id: string, definition?: Function): Function
component(id: string): VueConstructor
From 4a0d88e46e4180edc7f22e36c25df3f8ac5d60d2 Mon Sep 17 00:00:00 2001
From: Evan You
Date: Tue, 11 Oct 2022 12:26:19 +0800
Subject: [PATCH 25/41] fix(reactivity): use WeakMap for proxy/raw checks,
compat with non-extensible objects
fix #12799
close #12798
---
src/core/observer/index.ts | 4 +++-
src/v3/reactivity/reactive.ts | 9 +++++++--
src/v3/reactivity/readonly.ts | 10 +++++-----
test/unit/features/v3/reactivity/reactive.spec.ts | 6 ++++++
test/unit/features/v3/reactivity/readonly.spec.ts | 7 +++++++
5 files changed, 28 insertions(+), 8 deletions(-)
diff --git a/src/core/observer/index.ts b/src/core/observer/index.ts
index 3770c489a9f..dcf6bde1e76 100644
--- a/src/core/observer/index.ts
+++ b/src/core/observer/index.ts
@@ -17,6 +17,7 @@ import {
noop
} from '../util/index'
import { isReadonly, isRef, TrackOpTypes, TriggerOpTypes } from '../../v3'
+import { rawMap } from '../../v3/reactivity/reactive'
const arrayKeys = Object.getOwnPropertyNames(arrayMethods)
@@ -118,7 +119,8 @@ export function observe(
(ssrMockReactivity || !isServerRendering()) &&
(isArray(value) || isPlainObject(value)) &&
Object.isExtensible(value) &&
- !value.__v_skip /* ReactiveFlags.SKIP */
+ !value.__v_skip /* ReactiveFlags.SKIP */ &&
+ !rawMap.has(value)
) {
ob = new Observer(value, shallow, ssrMockReactivity)
}
diff --git a/src/v3/reactivity/reactive.ts b/src/v3/reactivity/reactive.ts
index 0ff682243a2..c65f25e67d8 100644
--- a/src/v3/reactivity/reactive.ts
+++ b/src/v3/reactivity/reactive.ts
@@ -5,10 +5,13 @@ import {
isPrimitive,
warn,
toRawType,
- isServerRendering
+ isServerRendering,
+ isObject
} from 'core/util'
import type { Ref, UnwrapRefSimple, RawSymbol } from './ref'
+export const rawMap = new WeakMap()
+
export const enum ReactiveFlags {
SKIP = '__v_skip',
IS_READONLY = '__v_isReadonly',
@@ -119,7 +122,9 @@ export function toRaw(observed: T): T {
export function markRaw(
value: T
): T & { [RawSymbol]?: true } {
- def(value, ReactiveFlags.SKIP, true)
+ if (isObject(value)) {
+ rawMap.set(value, true)
+ }
return value
}
diff --git a/src/v3/reactivity/readonly.ts b/src/v3/reactivity/readonly.ts
index 933f910b69f..c3794bb53b3 100644
--- a/src/v3/reactivity/readonly.ts
+++ b/src/v3/reactivity/readonly.ts
@@ -32,8 +32,8 @@ export type DeepReadonly = T extends Builtin
? { readonly [K in keyof T]: DeepReadonly }
: Readonly
-const rawToReadonlyFlag = `__v_rawToReadonly`
-const rawToShallowReadonlyFlag = `__v_rawToShallowReadonly`
+const rawToReadonlyMap = new WeakMap()
+const rawToShallowReadonlyMap = new WeakMap()
export function readonly(
target: T
@@ -63,14 +63,14 @@ function createReadonly(target: any, shallow: boolean) {
}
// already has a readonly proxy
- const existingFlag = shallow ? rawToShallowReadonlyFlag : rawToReadonlyFlag
- const existingProxy = target[existingFlag]
+ const map = shallow ? rawToShallowReadonlyMap : rawToReadonlyMap
+ const existingProxy = map.get(target)
if (existingProxy) {
return existingProxy
}
const proxy = Object.create(Object.getPrototypeOf(target))
- def(target, existingFlag, proxy)
+ map.set(target, proxy)
def(proxy, ReactiveFlags.IS_READONLY, true)
def(proxy, ReactiveFlags.RAW, target)
diff --git a/test/unit/features/v3/reactivity/reactive.spec.ts b/test/unit/features/v3/reactivity/reactive.spec.ts
index f636d44d4a1..a8a30e0353c 100644
--- a/test/unit/features/v3/reactivity/reactive.spec.ts
+++ b/test/unit/features/v3/reactivity/reactive.spec.ts
@@ -258,6 +258,12 @@ describe('reactivity/reactive', () => {
expect(isReactive(obj.bar)).toBe(false)
})
+ test('markRaw on non-extensible objects', () => {
+ const foo = Object.freeze({})
+ markRaw(foo)
+ expect(isReactive(reactive(foo))).toBe(false)
+ })
+
test('should not observe non-extensible objects', () => {
const obj = reactive({
foo: Object.preventExtensions({ a: 1 }),
diff --git a/test/unit/features/v3/reactivity/readonly.spec.ts b/test/unit/features/v3/reactivity/readonly.spec.ts
index 012e142d451..fab99bbfbcb 100644
--- a/test/unit/features/v3/reactivity/readonly.spec.ts
+++ b/test/unit/features/v3/reactivity/readonly.spec.ts
@@ -525,4 +525,11 @@ describe('reactivity/readonly', () => {
expect(readonlyFoo.x).toBe(1)
expect(`et operation on key "x" failed`).toHaveBeenWarned()
})
+
+ test('compatibility with non-extensible objects', () => {
+ const foo = Object.freeze({ a: 1 })
+ const bar = readonly(foo)
+ expect(isReadonly(bar)).toBe(true)
+ expect(readonly(foo)).toBe(bar)
+ })
})
From 5d26f815c643d41e6ca6f29329593223b981fc24 Mon Sep 17 00:00:00 2001
From: Xiersa
Date: Tue, 11 Oct 2022 13:26:20 +0800
Subject: [PATCH 26/41] fix(reactivity): check skip first before checking ref
when creating observer (#12813)
fix #12812
---
src/core/observer/index.ts | 17 +++++++----------
1 file changed, 7 insertions(+), 10 deletions(-)
diff --git a/src/core/observer/index.ts b/src/core/observer/index.ts
index dcf6bde1e76..51f928c5c24 100644
--- a/src/core/observer/index.ts
+++ b/src/core/observer/index.ts
@@ -7,7 +7,6 @@ import {
hasOwn,
isArray,
hasProto,
- isObject,
isPlainObject,
isPrimitive,
isUndef,
@@ -108,23 +107,21 @@ export function observe(
shallow?: boolean,
ssrMockReactivity?: boolean
): Observer | void {
- if (!isObject(value) || isRef(value) || value instanceof VNode) {
- return
+ if (value && hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
+ return value.__ob__
}
- let ob: Observer | void
- if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
- ob = value.__ob__
- } else if (
+ if (
shouldObserve &&
(ssrMockReactivity || !isServerRendering()) &&
(isArray(value) || isPlainObject(value)) &&
Object.isExtensible(value) &&
!value.__v_skip /* ReactiveFlags.SKIP */ &&
- !rawMap.has(value)
+ !rawMap.has(value) &&
+ !isRef(value) &&
+ !(value instanceof VNode)
) {
- ob = new Observer(value, shallow, ssrMockReactivity)
+ return new Observer(value, shallow, ssrMockReactivity)
}
- return ob
}
/**
From 87f69aa26f195390b948fbb0ff62cf954b58c82c Mon Sep 17 00:00:00 2001
From: Shiluo34
Date: Tue, 11 Oct 2022 13:36:50 +0800
Subject: [PATCH 27/41] fix(types): support Ref and function types in tsx ref
attribute (#12759)
fix #12758
---
types/test/v3/tsx-test.tsx | 7 ++++++-
types/vnode.d.ts | 12 +++++++++++-
2 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/types/test/v3/tsx-test.tsx b/types/test/v3/tsx-test.tsx
index 16a767acc5a..286c16997a0 100644
--- a/types/test/v3/tsx-test.tsx
+++ b/types/test/v3/tsx-test.tsx
@@ -1,4 +1,4 @@
-import { VNode, defineComponent } from '../../index'
+import { VNode, defineComponent, ref } from '../../index'
import { expectType } from '../utils'
expectType()
@@ -22,6 +22,11 @@ expectError()
expectType()
expectType()
+// allow Ref type type on arbitrary element
+const fooRef = ref()
+expectType()
+expectType( {fooRef.value = el as HTMLElement}} />)
+
expectType(
{
diff --git a/types/vnode.d.ts b/types/vnode.d.ts
index 7a543f0a39b..29bdb398c1c 100644
--- a/types/vnode.d.ts
+++ b/types/vnode.d.ts
@@ -1,5 +1,7 @@
import { Vue } from './vue'
import { DirectiveFunction, DirectiveOptions } from './options'
+import { Ref } from './v3-generated'
+import { ComponentPublicInstance } from './v3-component-public-instance'
/**
* For extending allowed non-declared props on components in TSX
@@ -65,11 +67,19 @@ export interface VNodeComponentOptions {
tag?: string
}
+export type VNodeRef =
+ | string
+ | Ref
+ | ((
+ ref: Element | ComponentPublicInstance | null,
+ refs: Record
+ ) => void)
+
export interface VNodeData {
key?: string | number
slot?: string
scopedSlots?: { [key: string]: ScopedSlot | undefined }
- ref?: string
+ ref?: VNodeRef
refInFor?: boolean
tag?: string
staticClass?: string
From fb1393009660b38046b1f6dfb532b481cc53b3b7 Mon Sep 17 00:00:00 2001
From: Evan You
Date: Tue, 11 Oct 2022 14:09:10 +0800
Subject: [PATCH 28/41] fix(sfc): prune returned bindings for non-TS as well
In Vue 3, pruning is only done for TS to produce valid code and
tree-shaking is done by inlining the template for production.
In Vue 2 we do not inline the template in production, so return binding
pruning is needed in all cases.
fix #12765
---
packages/compiler-sfc/src/compileScript.ts | 36 +++++++++----------
.../__snapshots__/compileScript.spec.ts.snap | 2 +-
2 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/packages/compiler-sfc/src/compileScript.ts b/packages/compiler-sfc/src/compileScript.ts
index 094120c38f7..7d171a9b78a 100644
--- a/packages/compiler-sfc/src/compileScript.ts
+++ b/packages/compiler-sfc/src/compileScript.ts
@@ -284,11 +284,9 @@ export function compileScript(
userImportAlias[imported] = local
}
- // template usage check is only needed in non-inline mode, so we can skip
- // the work if inlineTemplate is true.
let isUsedInTemplate = true
- if (isTS && sfc.template && !sfc.template.src && !sfc.template.lang) {
- isUsedInTemplate = isImportUsed(local, sfc)
+ if (sfc.template && !sfc.template.src && !sfc.template.lang) {
+ isUsedInTemplate = isImportUsed(local, sfc, isTS)
}
userImports[local] = {
@@ -1782,7 +1780,7 @@ function getObjectOrArrayExpressionKeys(value: Node): string[] {
const templateUsageCheckCache = new LRU(512)
-function resolveTemplateUsageCheckString(sfc: SFCDescriptor) {
+function resolveTemplateUsageCheckString(sfc: SFCDescriptor, isTS: boolean) {
const { content } = sfc.template!
const cached = templateUsageCheckCache.get(content)
if (cached) {
@@ -1809,7 +1807,7 @@ function resolveTemplateUsageCheckString(sfc: SFCDescriptor) {
code += `,v${capitalize(camelize(baseName))}`
}
if (value) {
- code += `,${processExp(value, baseName)}`
+ code += `,${processExp(value, isTS, baseName)}`
}
}
}
@@ -1817,7 +1815,7 @@ function resolveTemplateUsageCheckString(sfc: SFCDescriptor) {
chars(text) {
const res = parseText(text)
if (res) {
- code += `,${processExp(res.expression)}`
+ code += `,${processExp(res.expression, isTS)}`
}
}
})
@@ -1829,8 +1827,8 @@ function resolveTemplateUsageCheckString(sfc: SFCDescriptor) {
const forAliasRE = /([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/
-function processExp(exp: string, dir?: string): string {
- if (/ as\s+\w|<.*>|:/.test(exp)) {
+function processExp(exp: string, isTS: boolean, dir?: string): string {
+ if (isTS && / as\s+\w|<.*>|:/.test(exp)) {
if (dir === 'slot') {
exp = `(${exp})=>{}`
} else if (dir === 'on') {
@@ -1839,7 +1837,7 @@ function processExp(exp: string, dir?: string): string {
const inMatch = exp.match(forAliasRE)
if (inMatch) {
const [, LHS, RHS] = inMatch
- return processExp(`(${LHS})=>{}`) + processExp(RHS)
+ return processExp(`(${LHS})=>{}`, true) + processExp(RHS, true)
}
}
let ret = ''
@@ -1867,36 +1865,38 @@ function stripTemplateString(str: string): string {
return ''
}
-function isImportUsed(local: string, sfc: SFCDescriptor): boolean {
+function isImportUsed(
+ local: string,
+ sfc: SFCDescriptor,
+ isTS: boolean
+): boolean {
return new RegExp(
// #4274 escape $ since it's a special char in regex
// (and is the only regex special char that is valid in identifiers)
`[^\\w$_]${local.replace(/\$/g, '\\$')}[^\\w$_]`
- ).test(resolveTemplateUsageCheckString(sfc))
+ ).test(resolveTemplateUsageCheckString(sfc, isTS))
}
/**
* Note: this comparison assumes the prev/next script are already identical,
- * and only checks the special case where