vue 2.7.9 → 2.7.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +11 -1
  2. package/dist/vue.common.dev.js +11622 -11589
  3. package/dist/vue.common.prod.js +3 -3
  4. package/dist/vue.esm.browser.js +11601 -11568
  5. package/dist/vue.esm.browser.min.js +3 -3
  6. package/dist/vue.esm.js +11751 -11718
  7. package/dist/vue.js +11665 -11632
  8. package/dist/vue.min.js +3 -3
  9. package/dist/vue.runtime.common.dev.js +8416 -8383
  10. package/dist/vue.runtime.common.prod.js +3 -3
  11. package/dist/vue.runtime.esm.js +8543 -8510
  12. package/dist/vue.runtime.js +8494 -8461
  13. package/dist/vue.runtime.min.js +3 -3
  14. package/dist/vue.runtime.mjs +76 -76
  15. package/package.json +5 -5
  16. package/packages/compiler-sfc/dist/compiler-sfc.d.ts +5 -0
  17. package/packages/compiler-sfc/dist/compiler-sfc.js +9650 -9648
  18. package/packages/compiler-sfc/node_modules/.bin/parser +2 -2
  19. package/packages/compiler-sfc/node_modules/.bin/sass +2 -2
  20. package/packages/compiler-sfc/package.json +2 -2
  21. package/packages/compiler-sfc/src/compileScript.ts +25 -21
  22. package/packages/compiler-sfc/src/index.ts +7 -0
  23. package/packages/compiler-sfc/src/parseComponent.ts +2 -2
  24. package/packages/compiler-sfc/src/stylePlugins/scoped.ts +9 -10
  25. package/packages/compiler-sfc/test/__snapshots__/compileScript.spec.ts.snap +1 -1
  26. package/src/core/instance/init.ts +7 -2
  27. package/src/core/instance/lifecycle.ts +9 -2
  28. package/src/core/instance/state.ts +2 -7
  29. package/src/core/observer/dep.ts +26 -6
  30. package/src/core/observer/index.ts +9 -10
  31. package/src/core/observer/scheduler.ts +2 -1
  32. package/src/shared/util.ts +7 -1
  33. package/src/v3/reactivity/reactive.ts +7 -2
  34. package/src/v3/reactivity/readonly.ts +5 -5
  35. package/types/options.d.ts +12 -5
  36. package/types/vnode.d.ts +11 -1
  37. package/types/vue.d.ts +5 -0
@@ -11,7 +11,7 @@ else
11
11
  export NODE_PATH="$NODE_PATH:/Users/evan/Vue/vue/node_modules/.pnpm/node_modules"
12
12
  fi
13
13
  if [ -x "$basedir/node" ]; then
14
- exec "$basedir/node" "$basedir/../../../../node_modules/.pnpm/@babel+parser@7.18.4/node_modules/@babel/parser/bin/babel-parser.js" "$@"
14
+ exec "$basedir/node" "$basedir/../../../../node_modules/.pnpm/@babel+parser@7.19.4/node_modules/@babel/parser/bin/babel-parser.js" "$@"
15
15
  else
16
- exec node "$basedir/../../../../node_modules/.pnpm/@babel+parser@7.18.4/node_modules/@babel/parser/bin/babel-parser.js" "$@"
16
+ exec node "$basedir/../../../../node_modules/.pnpm/@babel+parser@7.19.4/node_modules/@babel/parser/bin/babel-parser.js" "$@"
17
17
  fi
@@ -11,7 +11,7 @@ else
11
11
  export NODE_PATH="$NODE_PATH:/Users/evan/Vue/vue/node_modules/.pnpm/node_modules"
12
12
  fi
13
13
  if [ -x "$basedir/node" ]; then
14
- exec "$basedir/node" "$basedir/../../../../node_modules/.pnpm/sass@1.52.3/node_modules/sass/sass.js" "$@"
14
+ exec "$basedir/node" "$basedir/../../../../node_modules/.pnpm/sass@1.55.0/node_modules/sass/sass.js" "$@"
15
15
  else
16
- exec node "$basedir/../../../../node_modules/.pnpm/sass@1.52.3/node_modules/sass/sass.js" "$@"
16
+ exec node "$basedir/../../../../node_modules/.pnpm/sass@1.55.0/node_modules/sass/sass.js" "$@"
17
17
  fi
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vue/compiler-sfc",
3
- "version": "2.7.9",
3
+ "version": "2.7.11",
4
4
  "description": "compiler-sfc for Vue 2",
5
5
  "main": "dist/compiler-sfc.js",
6
6
  "types": "dist/compiler-sfc.d.ts",
@@ -13,7 +13,7 @@
13
13
  "source-map": "^0.6.1"
14
14
  },
15
15
  "devDependencies": {
16
- "@babel/types": "^7.18.4",
16
+ "@babel/types": "^7.19.4",
17
17
  "@types/estree": "^0.0.48",
18
18
  "@types/hash-sum": "^1.0.0",
19
19
  "@types/lru-cache": "^5.1.1",
@@ -284,11 +284,9 @@ export function compileScript(
284
284
  userImportAlias[imported] = local
285
285
  }
286
286
 
287
- // template usage check is only needed in non-inline mode, so we can skip
288
- // the work if inlineTemplate is true.
289
287
  let isUsedInTemplate = true
290
- if (isTS && sfc.template && !sfc.template.src && !sfc.template.lang) {
291
- isUsedInTemplate = isImportUsed(local, sfc)
288
+ if (sfc.template && !sfc.template.src && !sfc.template.lang) {
289
+ isUsedInTemplate = isImportUsed(local, sfc, isTS)
292
290
  }
293
291
 
294
292
  userImports[local] = {
@@ -782,7 +780,7 @@ export function compileScript(
782
780
  if (node.trailingComments && node.trailingComments.length > 0) {
783
781
  const lastCommentNode =
784
782
  node.trailingComments[node.trailingComments.length - 1]
785
- end = lastCommentNode.end + startOffset
783
+ end = lastCommentNode.end! + startOffset
786
784
  }
787
785
  // locate the end of whitespace between this statement and the next
788
786
  while (end <= source.length) {
@@ -1584,14 +1582,18 @@ function extractEventNames(
1584
1582
  ) {
1585
1583
  const typeNode = eventName.typeAnnotation.typeAnnotation
1586
1584
  if (typeNode.type === 'TSLiteralType') {
1587
- if (typeNode.literal.type !== 'UnaryExpression') {
1585
+ if (
1586
+ typeNode.literal.type !== 'UnaryExpression' &&
1587
+ typeNode.literal.type !== 'TemplateLiteral'
1588
+ ) {
1588
1589
  emits.add(String(typeNode.literal.value))
1589
1590
  }
1590
1591
  } else if (typeNode.type === 'TSUnionType') {
1591
1592
  for (const t of typeNode.types) {
1592
1593
  if (
1593
1594
  t.type === 'TSLiteralType' &&
1594
- t.literal.type !== 'UnaryExpression'
1595
+ t.literal.type !== 'UnaryExpression' &&
1596
+ t.literal.type !== 'TemplateLiteral'
1595
1597
  ) {
1596
1598
  emits.add(String(t.literal.value))
1597
1599
  }
@@ -1782,7 +1784,7 @@ function getObjectOrArrayExpressionKeys(value: Node): string[] {
1782
1784
 
1783
1785
  const templateUsageCheckCache = new LRU<string, string>(512)
1784
1786
 
1785
- function resolveTemplateUsageCheckString(sfc: SFCDescriptor) {
1787
+ function resolveTemplateUsageCheckString(sfc: SFCDescriptor, isTS: boolean) {
1786
1788
  const { content } = sfc.template!
1787
1789
  const cached = templateUsageCheckCache.get(content)
1788
1790
  if (cached) {
@@ -1809,7 +1811,7 @@ function resolveTemplateUsageCheckString(sfc: SFCDescriptor) {
1809
1811
  code += `,v${capitalize(camelize(baseName))}`
1810
1812
  }
1811
1813
  if (value) {
1812
- code += `,${processExp(value, baseName)}`
1814
+ code += `,${processExp(value, isTS, baseName)}`
1813
1815
  }
1814
1816
  }
1815
1817
  }
@@ -1817,7 +1819,7 @@ function resolveTemplateUsageCheckString(sfc: SFCDescriptor) {
1817
1819
  chars(text) {
1818
1820
  const res = parseText(text)
1819
1821
  if (res) {
1820
- code += `,${processExp(res.expression)}`
1822
+ code += `,${processExp(res.expression, isTS)}`
1821
1823
  }
1822
1824
  }
1823
1825
  })
@@ -1829,8 +1831,8 @@ function resolveTemplateUsageCheckString(sfc: SFCDescriptor) {
1829
1831
 
1830
1832
  const forAliasRE = /([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/
1831
1833
 
1832
- function processExp(exp: string, dir?: string): string {
1833
- if (/ as\s+\w|<.*>|:/.test(exp)) {
1834
+ function processExp(exp: string, isTS: boolean, dir?: string): string {
1835
+ if (isTS && / as\s+\w|<.*>|:/.test(exp)) {
1834
1836
  if (dir === 'slot') {
1835
1837
  exp = `(${exp})=>{}`
1836
1838
  } else if (dir === 'on') {
@@ -1839,7 +1841,7 @@ function processExp(exp: string, dir?: string): string {
1839
1841
  const inMatch = exp.match(forAliasRE)
1840
1842
  if (inMatch) {
1841
1843
  const [, LHS, RHS] = inMatch
1842
- return processExp(`(${LHS})=>{}`) + processExp(RHS)
1844
+ return processExp(`(${LHS})=>{}`, true) + processExp(RHS, true)
1843
1845
  }
1844
1846
  }
1845
1847
  let ret = ''
@@ -1867,36 +1869,38 @@ function stripTemplateString(str: string): string {
1867
1869
  return ''
1868
1870
  }
1869
1871
 
1870
- function isImportUsed(local: string, sfc: SFCDescriptor): boolean {
1872
+ function isImportUsed(
1873
+ local: string,
1874
+ sfc: SFCDescriptor,
1875
+ isTS: boolean
1876
+ ): boolean {
1871
1877
  return new RegExp(
1872
1878
  // #4274 escape $ since it's a special char in regex
1873
1879
  // (and is the only regex special char that is valid in identifiers)
1874
1880
  `[^\\w$_]${local.replace(/\$/g, '\\$')}[^\\w$_]`
1875
- ).test(resolveTemplateUsageCheckString(sfc))
1881
+ ).test(resolveTemplateUsageCheckString(sfc, isTS))
1876
1882
  }
1877
1883
 
1878
1884
  /**
1879
1885
  * Note: this comparison assumes the prev/next script are already identical,
1880
- * and only checks the special case where <script setup lang="ts"> unused import
1886
+ * and only checks the special case where <script setup> unused import
1881
1887
  * pruning result changes due to template changes.
1882
1888
  */
1883
1889
  export function hmrShouldReload(
1884
1890
  prevImports: Record<string, ImportBinding>,
1885
1891
  next: SFCDescriptor
1886
1892
  ): boolean {
1887
- if (
1888
- !next.scriptSetup ||
1889
- (next.scriptSetup.lang !== 'ts' && next.scriptSetup.lang !== 'tsx')
1890
- ) {
1893
+ if (!next.scriptSetup) {
1891
1894
  return false
1892
1895
  }
1893
1896
 
1897
+ const isTS = next.scriptSetup.lang === 'ts' || next.scriptSetup.lang === 'tsx'
1894
1898
  // for each previous import, check if its used status remain the same based on
1895
1899
  // the next descriptor's template
1896
1900
  for (const key in prevImports) {
1897
1901
  // if an import was previous unused, but now is used, we need to force
1898
1902
  // reload so that the script now includes that import.
1899
- if (!prevImports[key].isUsedInTemplate && isImportUsed(key, next)) {
1903
+ if (!prevImports[key].isUsedInTemplate && isImportUsed(key, next, isTS)) {
1900
1904
  return true
1901
1905
  }
1902
1906
  }
@@ -6,6 +6,13 @@ export { compileScript } from './compileScript'
6
6
  export { generateCodeFrame } from 'compiler/codeframe'
7
7
  export { rewriteDefault } from './rewriteDefault'
8
8
 
9
+ // For backwards compat only. Some existing tools like
10
+ // fork-ts-checker-webpack-plugin relies on its presence for differentiating
11
+ // between Vue 2 and Vue 3.
12
+ // ref #12719
13
+ // ref https://github.com/TypeStrong/fork-ts-checker-webpack-plugin/issues/765
14
+ export { parseComponent } from './parseComponent'
15
+
9
16
  // types
10
17
  export { SFCParseOptions } from './parse'
11
18
  export { CompilerOptions, WarningMessage } from 'types/compiler'
@@ -179,11 +179,11 @@ export function parseComponent(
179
179
  let text = source.slice(currentBlock.start, currentBlock.end)
180
180
  if (
181
181
  options.deindent === true ||
182
- // by default, deindent unless it's script with default lang or ts
182
+ // by default, deindent unless it's script with default lang or (j/t)sx?
183
183
  (options.deindent !== false &&
184
184
  !(
185
185
  currentBlock.type === 'script' &&
186
- (!currentBlock.lang || currentBlock.lang === 'ts')
186
+ (!currentBlock.lang || /^(j|t)sx?$/.test(currentBlock.lang))
187
187
  ))
188
188
  ) {
189
189
  text = deindent(text)
@@ -1,6 +1,5 @@
1
1
  import { PluginCreator, Rule, AtRule } from 'postcss'
2
2
  import selectorParser from 'postcss-selector-parser'
3
- import { warn } from '../warn'
4
3
 
5
4
  const animationNameRE = /^(-\w+-)?animation-name$/
6
5
  const animationRE = /^(-\w+-)?animation$/
@@ -94,10 +93,10 @@ function rewriteSelector(
94
93
  ) {
95
94
  n.value = ' '
96
95
  n.spaces.before = n.spaces.after = ''
97
- warn(
98
- `the >>> and /deep/ combinators have been deprecated. ` +
99
- `Use :deep() instead.`
100
- )
96
+ // warn(
97
+ // `the >>> and /deep/ combinators have been deprecated. ` +
98
+ // `Use :deep() instead.`
99
+ // )
101
100
  return false
102
101
  }
103
102
 
@@ -126,12 +125,12 @@ function rewriteSelector(
126
125
  }
127
126
  selector.removeChild(n)
128
127
  } else {
129
- // DEPRECATED usage
128
+ // DEPRECATED usage in v3
130
129
  // .foo ::v-deep .bar -> .foo[xxxxxxx] .bar
131
- warn(
132
- `::v-deep usage as a combinator has ` +
133
- `been deprecated. Use :deep(<inner-selector>) instead.`
134
- )
130
+ // warn(
131
+ // `::v-deep usage as a combinator has ` +
132
+ // `been deprecated. Use :deep(<inner-selector>) instead.`
133
+ // )
135
134
  const prev = selector.at(selector.index(n) - 1)
136
135
  if (prev && isSpaceCombinator(prev)) {
137
136
  selector.removeChild(prev)
@@ -20,7 +20,7 @@ exports[`SFC analyze <script> bindings > auto name inference > do not overwrite
20
20
  export default /*#__PURE__*/Object.assign(__default__, {
21
21
  setup(__props) {
22
22
  const a = 1
23
- return { a, defineComponent }
23
+ return { a }
24
24
  }
25
25
 
26
26
  })"
@@ -1,6 +1,6 @@
1
1
  import config from '../config'
2
2
  import { initProxy } from './proxy'
3
- import { initState } from './state'
3
+ import { initProps, initState } from './state'
4
4
  import { initRender } from './render'
5
5
  import { initEvents } from './events'
6
6
  import { mark, measure } from '../util/perf'
@@ -10,6 +10,7 @@ import { extend, mergeOptions, formatComponentName } from '../util/index'
10
10
  import type { Component } from 'types/component'
11
11
  import type { InternalComponentOptions } from 'types/options'
12
12
  import { EffectScope } from 'v3/reactivity/effectScope'
13
+ import { initSetup } from '../../v3/apiSetup'
13
14
 
14
15
  let uid = 0
15
16
 
@@ -59,8 +60,12 @@ export function initMixin(Vue: typeof Component) {
59
60
  initLifecycle(vm)
60
61
  initEvents(vm)
61
62
  initRender(vm)
62
- callHook(vm, 'beforeCreate', undefined, false /* setContext */)
63
+
64
+ const opts = vm.$options
63
65
  initInjections(vm) // resolve injections before data/props
66
+ initProps(vm, opts.props)
67
+ initSetup(vm)
68
+ callHook(vm, 'beforeCreate', undefined, false /* setContext */)
64
69
  initState(vm)
65
70
  initProvide(vm) // resolve provide after data/props
66
71
  callHook(vm, 'created')
@@ -83,8 +83,15 @@ export function lifecycleMixin(Vue: typeof Component) {
83
83
  vm.$el.__vue__ = vm
84
84
  }
85
85
  // if parent is an HOC, update its $el as well
86
- if (vm.$vnode && vm.$parent && vm.$vnode === vm.$parent._vnode) {
87
- vm.$parent.$el = vm.$el
86
+ let wrapper: Component | undefined = vm
87
+ while (
88
+ wrapper &&
89
+ wrapper.$vnode &&
90
+ wrapper.$parent &&
91
+ wrapper.$vnode === wrapper.$parent._vnode
92
+ ) {
93
+ wrapper.$parent.$el = wrapper.$el
94
+ wrapper = wrapper.$parent
88
95
  }
89
96
  // updated hook is called by the scheduler to ensure that children are
90
97
  // updated in a parent's updated hook.
@@ -2,7 +2,6 @@ import config from '../config'
2
2
  import Watcher from '../observer/watcher'
3
3
  import Dep, { pushTarget, popTarget } from '../observer/dep'
4
4
  import { isUpdatingChildComponent } from './lifecycle'
5
- import { initSetup } from 'v3/apiSetup'
6
5
 
7
6
  import {
8
7
  set,
@@ -51,11 +50,6 @@ export function proxy(target: Object, sourceKey: string, key: string) {
51
50
 
52
51
  export function initState(vm: Component) {
53
52
  const opts = vm.$options
54
- if (opts.props) initProps(vm, opts.props)
55
-
56
- // Composition API
57
- initSetup(vm)
58
-
59
53
  if (opts.methods) initMethods(vm, opts.methods)
60
54
  if (opts.data) {
61
55
  initData(vm)
@@ -69,7 +63,8 @@ export function initState(vm: Component) {
69
63
  }
70
64
  }
71
65
 
72
- function initProps(vm: Component, propsOptions: Object) {
66
+ export function initProps(vm: Component, propsOptions: Object | undefined) {
67
+ if (!propsOptions) return
73
68
  const propsData = vm.$options.propsData || {}
74
69
  const props = (vm._props = shallowReactive({}))
75
70
  // cache prop keys so that future props updates can iterate using Array
@@ -1,9 +1,19 @@
1
- import { remove } from '../util/index'
2
1
  import config from '../config'
3
2
  import { DebuggerOptions, DebuggerEventExtraInfo } from 'v3'
4
3
 
5
4
  let uid = 0
6
5
 
6
+ const pendingCleanupDeps: Dep[] = []
7
+
8
+ export const cleanupDeps = () => {
9
+ for (let i = 0; i < pendingCleanupDeps.length; i++) {
10
+ const dep = pendingCleanupDeps[i]
11
+ dep.subs = dep.subs.filter(s => s)
12
+ dep._pending = false
13
+ }
14
+ pendingCleanupDeps.length = 0
15
+ }
16
+
7
17
  /**
8
18
  * @internal
9
19
  */
@@ -21,7 +31,9 @@ export interface DepTarget extends DebuggerOptions {
21
31
  export default class Dep {
22
32
  static target?: DepTarget | null
23
33
  id: number
24
- subs: Array<DepTarget>
34
+ subs: Array<DepTarget | null>
35
+ // pending subs cleanup
36
+ _pending = false
25
37
 
26
38
  constructor() {
27
39
  this.id = uid++
@@ -33,7 +45,15 @@ export default class Dep {
33
45
  }
34
46
 
35
47
  removeSub(sub: DepTarget) {
36
- remove(this.subs, sub)
48
+ // #12696 deps with massive amount of subscribers are extremely slow to
49
+ // clean up in Chromium
50
+ // to workaround this, we unset the sub for now, and clear them on
51
+ // next scheduler flush.
52
+ this.subs[this.subs.indexOf(sub)] = null
53
+ if (!this._pending) {
54
+ this._pending = true
55
+ pendingCleanupDeps.push(this)
56
+ }
37
57
  }
38
58
 
39
59
  depend(info?: DebuggerEventExtraInfo) {
@@ -50,7 +70,7 @@ export default class Dep {
50
70
 
51
71
  notify(info?: DebuggerEventExtraInfo) {
52
72
  // stabilize the subscriber list first
53
- const subs = this.subs.slice()
73
+ const subs = this.subs.filter(s => s) as DepTarget[]
54
74
  if (__DEV__ && !config.async) {
55
75
  // subs aren't sorted in scheduler if not running async
56
76
  // we need to sort them now to make sure they fire in correct
@@ -58,15 +78,15 @@ export default class Dep {
58
78
  subs.sort((a, b) => a.id - b.id)
59
79
  }
60
80
  for (let i = 0, l = subs.length; i < l; i++) {
81
+ const sub = subs[i]
61
82
  if (__DEV__ && info) {
62
- const sub = subs[i]
63
83
  sub.onTrigger &&
64
84
  sub.onTrigger({
65
85
  effect: subs[i],
66
86
  ...info
67
87
  })
68
88
  }
69
- subs[i].update()
89
+ sub.update()
70
90
  }
71
91
  }
72
92
  }
@@ -7,7 +7,6 @@ import {
7
7
  hasOwn,
8
8
  isArray,
9
9
  hasProto,
10
- isObject,
11
10
  isPlainObject,
12
11
  isPrimitive,
13
12
  isUndef,
@@ -17,6 +16,7 @@ import {
17
16
  noop
18
17
  } from '../util/index'
19
18
  import { isReadonly, isRef, TrackOpTypes, TriggerOpTypes } from '../../v3'
19
+ import { rawMap } from '../../v3/reactivity/reactive'
20
20
 
21
21
  const arrayKeys = Object.getOwnPropertyNames(arrayMethods)
22
22
 
@@ -107,22 +107,21 @@ export function observe(
107
107
  shallow?: boolean,
108
108
  ssrMockReactivity?: boolean
109
109
  ): Observer | void {
110
- if (!isObject(value) || isRef(value) || value instanceof VNode) {
111
- return
110
+ if (value && hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
111
+ return value.__ob__
112
112
  }
113
- let ob: Observer | void
114
- if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
115
- ob = value.__ob__
116
- } else if (
113
+ if (
117
114
  shouldObserve &&
118
115
  (ssrMockReactivity || !isServerRendering()) &&
119
116
  (isArray(value) || isPlainObject(value)) &&
120
117
  Object.isExtensible(value) &&
121
- !value.__v_skip /* ReactiveFlags.SKIP */
118
+ !value.__v_skip /* ReactiveFlags.SKIP */ &&
119
+ !rawMap.has(value) &&
120
+ !isRef(value) &&
121
+ !(value instanceof VNode)
122
122
  ) {
123
- ob = new Observer(value, shallow, ssrMockReactivity)
123
+ return new Observer(value, shallow, ssrMockReactivity)
124
124
  }
125
- return ob
126
125
  }
127
126
 
128
127
  /**
@@ -1,6 +1,6 @@
1
1
  import type Watcher from './watcher'
2
2
  import config from '../config'
3
- import Dep from './dep'
3
+ import Dep, { cleanupDeps } from './dep'
4
4
  import { callHook, activateChildComponent } from '../instance/lifecycle'
5
5
 
6
6
  import { warn, nextTick, devtools, inBrowser, isIE } from '../util/index'
@@ -121,6 +121,7 @@ function flushSchedulerQueue() {
121
121
  // call component updated and activated hooks
122
122
  callActivatedHooks(activatedQueue)
123
123
  callUpdatedHooks(updatedQueue)
124
+ cleanupDeps()
124
125
 
125
126
  // devtool hook
126
127
  /* istanbul ignore if */
@@ -133,7 +133,13 @@ export const isReservedAttribute = makeMap('key,ref,slot,slot-scope,is')
133
133
  * Remove an item from an array.
134
134
  */
135
135
  export function remove(arr: Array<any>, item: any): Array<any> | void {
136
- if (arr.length) {
136
+ const len = arr.length
137
+ if (len) {
138
+ // fast path for the only / last item
139
+ if (item === arr[len - 1]) {
140
+ arr.length = len - 1
141
+ return
142
+ }
137
143
  const index = arr.indexOf(item)
138
144
  if (index > -1) {
139
145
  return arr.splice(index, 1)
@@ -5,10 +5,13 @@ import {
5
5
  isPrimitive,
6
6
  warn,
7
7
  toRawType,
8
- isServerRendering
8
+ isServerRendering,
9
+ isObject
9
10
  } from 'core/util'
10
11
  import type { Ref, UnwrapRefSimple, RawSymbol } from './ref'
11
12
 
13
+ export const rawMap = new WeakMap()
14
+
12
15
  export const enum ReactiveFlags {
13
16
  SKIP = '__v_skip',
14
17
  IS_READONLY = '__v_isReadonly',
@@ -119,7 +122,9 @@ export function toRaw<T>(observed: T): T {
119
122
  export function markRaw<T extends object>(
120
123
  value: T
121
124
  ): T & { [RawSymbol]?: true } {
122
- def(value, ReactiveFlags.SKIP, true)
125
+ if (isObject(value)) {
126
+ rawMap.set(value, true)
127
+ }
123
128
  return value
124
129
  }
125
130
 
@@ -32,8 +32,8 @@ export type DeepReadonly<T> = T extends Builtin
32
32
  ? { readonly [K in keyof T]: DeepReadonly<T[K]> }
33
33
  : Readonly<T>
34
34
 
35
- const rawToReadonlyFlag = `__v_rawToReadonly`
36
- const rawToShallowReadonlyFlag = `__v_rawToShallowReadonly`
35
+ const rawToReadonlyMap = new WeakMap()
36
+ const rawToShallowReadonlyMap = new WeakMap()
37
37
 
38
38
  export function readonly<T extends object>(
39
39
  target: T
@@ -63,14 +63,14 @@ function createReadonly(target: any, shallow: boolean) {
63
63
  }
64
64
 
65
65
  // already has a readonly proxy
66
- const existingFlag = shallow ? rawToShallowReadonlyFlag : rawToReadonlyFlag
67
- const existingProxy = target[existingFlag]
66
+ const map = shallow ? rawToShallowReadonlyMap : rawToReadonlyMap
67
+ const existingProxy = map.get(target)
68
68
  if (existingProxy) {
69
69
  return existingProxy
70
70
  }
71
71
 
72
72
  const proxy = Object.create(Object.getPrototypeOf(target))
73
- def(target, existingFlag, proxy)
73
+ map.set(target, proxy)
74
74
 
75
75
  def(proxy, ReactiveFlags.IS_READONLY, true)
76
76
  def(proxy, ReactiveFlags.RAW, target)
@@ -4,6 +4,7 @@ import { SetupContext } from './v3-setup-context'
4
4
  import { DebuggerEvent } from './v3-generated'
5
5
  import { DefineComponent } from './v3-define-component'
6
6
  import { ComponentOptionsMixin } from './v3-component-options'
7
+ import { ObjectDirective, FunctionDirective } from './v3-directive'
7
8
 
8
9
  type Constructor = {
9
10
  new (...args: any[]): any
@@ -95,8 +96,8 @@ export type ThisTypedComponentOptionsWithArrayProps<
95
96
  Computed,
96
97
  PropNames extends string,
97
98
  SetupBindings,
98
- Mixin,
99
- Extends
99
+ Mixin extends ComponentOptionsMixin,
100
+ Extends extends ComponentOptionsMixin
100
101
  > = object &
101
102
  ComponentOptions<
102
103
  V,
@@ -132,8 +133,8 @@ export type ThisTypedComponentOptionsWithRecordProps<
132
133
  Computed,
133
134
  Props,
134
135
  SetupBindings,
135
- Mixin,
136
- Extends
136
+ Mixin extends ComponentOptionsMixin,
137
+ Extends extends ComponentOptionsMixin
137
138
  > = object &
138
139
  ComponentOptions<
139
140
  V,
@@ -180,7 +181,7 @@ export interface ComponentOptions<
180
181
  propsData?: object
181
182
  computed?: Accessors<Computed>
182
183
  methods?: Methods
183
- watch?: Record<string, WatchOptionsWithHandler<any> | WatchHandler<any>>
184
+ watch?: Record<string, WatchOptionsWithHandler<any> | WatchHandler<any> | Array<WatchOptionsWithHandler<any> | WatchHandler<any>>>
184
185
 
185
186
  setup?: (
186
187
  this: void,
@@ -318,6 +319,9 @@ export interface DirectiveBinding extends Readonly<VNodeDirective> {
318
319
  readonly modifiers: { [key: string]: boolean }
319
320
  }
320
321
 
322
+ /**
323
+ * @deprecated use {@link FunctionDirective} instead
324
+ */
321
325
  export type DirectiveFunction = (
322
326
  el: HTMLElement,
323
327
  binding: DirectiveBinding,
@@ -325,6 +329,9 @@ export type DirectiveFunction = (
325
329
  oldVnode: VNode
326
330
  ) => void
327
331
 
332
+ /**
333
+ * @deprecated use {@link ObjectDirective} instead
334
+ */
328
335
  export interface DirectiveOptions {
329
336
  bind?: DirectiveFunction
330
337
  inserted?: DirectiveFunction
package/types/vnode.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import { Vue } from './vue'
2
2
  import { DirectiveFunction, DirectiveOptions } from './options'
3
+ import { Ref } from './v3-generated'
4
+ import { ComponentPublicInstance } from './v3-component-public-instance'
3
5
 
4
6
  /**
5
7
  * For extending allowed non-declared props on components in TSX
@@ -65,11 +67,19 @@ export interface VNodeComponentOptions {
65
67
  tag?: string
66
68
  }
67
69
 
70
+ export type VNodeRef =
71
+ | string
72
+ | Ref
73
+ | ((
74
+ ref: Element | ComponentPublicInstance | null,
75
+ refs: Record<string, any>
76
+ ) => void)
77
+
68
78
  export interface VNodeData {
69
79
  key?: string | number
70
80
  slot?: string
71
81
  scopedSlots?: { [key: string]: ScopedSlot | undefined }
72
- ref?: string
82
+ ref?: VNodeRef
73
83
  refInFor?: boolean
74
84
  tag?: string
75
85
  staticClass?: string
package/types/vue.d.ts CHANGED
@@ -22,6 +22,7 @@ import {
22
22
  ExtractComputedReturns,
23
23
  ComponentOptionsMixin
24
24
  } from './v3-component-options'
25
+ import { Directive, ObjectDirective } from './v3-directive'
25
26
 
26
27
  export interface CreateElement {
27
28
  (
@@ -338,6 +339,10 @@ export interface VueConstructor<V extends Vue = Vue> {
338
339
  id: string,
339
340
  definition?: DirectiveOptions | DirectiveFunction
340
341
  ): DirectiveOptions
342
+ directive(
343
+ id: string,
344
+ definition?: Directive
345
+ ): ObjectDirective
341
346
  filter(id: string, definition?: Function): Function
342
347
 
343
348
  component(id: string): VueConstructor