vue 2.7.6 → 2.7.9

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 (48) hide show
  1. package/README.md +1 -1
  2. package/dist/vue.common.dev.js +139 -67
  3. package/dist/vue.common.prod.js +3 -3
  4. package/dist/vue.esm.browser.js +137 -66
  5. package/dist/vue.esm.browser.min.js +3 -3
  6. package/dist/vue.esm.js +138 -66
  7. package/dist/vue.js +140 -67
  8. package/dist/vue.min.js +3 -3
  9. package/dist/vue.runtime.common.dev.js +112 -58
  10. package/dist/vue.runtime.common.prod.js +3 -3
  11. package/dist/vue.runtime.esm.js +111 -57
  12. package/dist/vue.runtime.js +113 -58
  13. package/dist/vue.runtime.min.js +3 -3
  14. package/package.json +2 -2
  15. package/packages/compiler-sfc/dist/compiler-sfc.js +56 -26
  16. package/packages/compiler-sfc/package.json +2 -3
  17. package/packages/compiler-sfc/src/compileTemplate.ts +1 -2
  18. package/packages/compiler-sfc/src/rewriteDefault.ts +6 -1
  19. package/packages/compiler-sfc/src/templateCompilerModules/utils.ts +8 -3
  20. package/packages/compiler-sfc/test/rewriteDefault.spec.ts +245 -0
  21. package/src/compiler/codegen/index.ts +31 -10
  22. package/src/core/instance/init.ts +1 -0
  23. package/src/core/instance/inject.ts +10 -5
  24. package/src/core/instance/lifecycle.ts +18 -10
  25. package/src/core/instance/proxy.ts +2 -2
  26. package/src/core/instance/render.ts +8 -2
  27. package/src/core/instance/state.ts +1 -1
  28. package/src/core/observer/index.ts +1 -1
  29. package/src/core/observer/scheduler.ts +10 -1
  30. package/src/core/observer/watcher.ts +14 -5
  31. package/src/core/vdom/modules/directives.ts +9 -1
  32. package/src/core/vdom/vnode.ts +1 -0
  33. package/src/types/component.ts +1 -0
  34. package/src/v3/apiInject.ts +17 -12
  35. package/src/v3/apiLifecycle.ts +16 -1
  36. package/src/v3/apiSetup.ts +38 -17
  37. package/src/v3/apiWatch.ts +2 -5
  38. package/src/v3/index.ts +1 -1
  39. package/src/v3/reactivity/effectScope.ts +5 -1
  40. package/types/index.d.ts +2 -2
  41. package/types/options.d.ts +24 -9
  42. package/types/v3-component-options.d.ts +3 -0
  43. package/types/v3-component-public-instance.d.ts +2 -4
  44. package/types/v3-define-component.d.ts +34 -34
  45. package/types/v3-generated.d.ts +11 -2
  46. package/types/v3-manual-apis.d.ts +2 -2
  47. package/types/v3-setup-context.d.ts +4 -0
  48. package/types/vue.d.ts +108 -31
@@ -144,8 +144,7 @@ function actuallyCompile(
144
144
  errors
145
145
  }
146
146
  } else {
147
- // transpile code with vue-template-es2015-compiler, which is a forked
148
- // version of Buble that applies ES2015 transforms + stripping `with` usage
147
+ // stripping `with` usage
149
148
  let code =
150
149
  `var __render__ = ${prefixIdentifiers(
151
150
  `function render(${isFunctional ? `_c,_vm` : ``}){${render}\n}`,
@@ -42,7 +42,12 @@ export function rewriteDefault(
42
42
  }).program.body
43
43
  ast.forEach(node => {
44
44
  if (node.type === 'ExportDefaultDeclaration') {
45
- s.overwrite(node.start!, node.declaration.start!, `const ${as} = `)
45
+ if (node.declaration.type === 'ClassDeclaration') {
46
+ s.overwrite(node.start!, node.declaration.id.start!, `class `)
47
+ s.append(`\nconst ${as} = ${node.declaration.id.name}`)
48
+ } else {
49
+ s.overwrite(node.start!, node.declaration.start!, `const ${as} = `)
50
+ }
46
51
  }
47
52
  if (node.type === 'ExportNamedDeclaration') {
48
53
  for (const specifier of node.specifiers) {
@@ -24,10 +24,15 @@ export function urlToRequire(
24
24
  // does not apply to absolute urls or urls that start with `@`
25
25
  // since they are aliases
26
26
  if (firstChar === '.' || firstChar === '~') {
27
+ // Allow for full hostnames provided in options.base
28
+ const base = parseUriParts(transformAssetUrlsOption.base)
29
+ const protocol = base.protocol || ''
30
+ const host = base.host ? protocol + '//' + base.host : ''
31
+ const basePath = base.path || '/'
27
32
  // when packaged in the browser, path will be using the posix-
28
33
  // only version provided by rollup-plugin-node-builtins.
29
- return `"${(path.posix || path).join(
30
- transformAssetUrlsOption.base,
34
+ return `"${host}${(path.posix || path).join(
35
+ basePath,
31
36
  uriParts.path + (uriParts.hash || '')
32
37
  )}"`
33
38
  }
@@ -64,7 +69,7 @@ function parseUriParts(urlString: string): UrlWithStringQuery {
64
69
  // @see https://nodejs.org/api/url.html#url_url_parse_urlstring_parsequerystring_slashesdenotehost
65
70
  if ('string' === typeof urlString) {
66
71
  // check is an uri
67
- return uriParse(urlString) // take apart the uri
72
+ return uriParse(urlString, false, true) // take apart the uri
68
73
  }
69
74
  }
70
75
  return returnValue
@@ -0,0 +1,245 @@
1
+ import { rewriteDefault } from '../src'
2
+
3
+ describe('compiler sfc: rewriteDefault', () => {
4
+ test('without export default', () => {
5
+ expect(rewriteDefault(`export a = {}`, 'script')).toMatchInlineSnapshot(`
6
+ "export a = {}
7
+ const script = {}"
8
+ `)
9
+ })
10
+
11
+ test('rewrite export default', () => {
12
+ expect(
13
+ rewriteDefault(`export default {}`, 'script')
14
+ ).toMatchInlineSnapshot(`"const script = {}"`)
15
+ })
16
+
17
+ test('rewrite export named default', () => {
18
+ expect(
19
+ rewriteDefault(
20
+ `const a = 1 \n export { a as b, a as default, a as c}`,
21
+ 'script'
22
+ )
23
+ ).toMatchInlineSnapshot(`
24
+ "const a = 1
25
+ export { a as b, a as c}
26
+ const script = a"
27
+ `)
28
+
29
+ expect(
30
+ rewriteDefault(
31
+ `const a = 1 \n export { a as b, a as default , a as c}`,
32
+ 'script'
33
+ )
34
+ ).toMatchInlineSnapshot(`
35
+ "const a = 1
36
+ export { a as b, a as c}
37
+ const script = a"
38
+ `)
39
+ })
40
+
41
+ test('w/ comments', async () => {
42
+ expect(rewriteDefault(`// export default\nexport default {}`, 'script'))
43
+ .toMatchInlineSnapshot(`
44
+ "// export default
45
+ const script = {}"
46
+ `)
47
+ })
48
+
49
+ test('export named default multiline', () => {
50
+ expect(
51
+ rewriteDefault(`let App = {}\n export {\nApp as default\n}`, '_sfc_main')
52
+ ).toMatchInlineSnapshot(`
53
+ "let App = {}
54
+ export {
55
+
56
+ }
57
+ const _sfc_main = App"
58
+ `)
59
+ })
60
+
61
+ test('export named default multiline /w comments', () => {
62
+ expect(
63
+ rewriteDefault(
64
+ `const a = 1 \n export {\n a as b,\n a as default,\n a as c}\n` +
65
+ `// export { myFunction as default }`,
66
+ 'script'
67
+ )
68
+ ).toMatchInlineSnapshot(`
69
+ "const a = 1
70
+ export {
71
+ a as b,
72
+
73
+ a as c}
74
+ // export { myFunction as default }
75
+ const script = a"
76
+ `)
77
+
78
+ expect(
79
+ rewriteDefault(
80
+ `const a = 1 \n export {\n a as b,\n a as default ,\n a as c}\n` +
81
+ `// export { myFunction as default }`,
82
+ 'script'
83
+ )
84
+ ).toMatchInlineSnapshot(`
85
+ "const a = 1
86
+ export {
87
+ a as b,
88
+
89
+ a as c}
90
+ // export { myFunction as default }
91
+ const script = a"
92
+ `)
93
+ })
94
+
95
+ test(`export { default } from '...'`, async () => {
96
+ expect(
97
+ rewriteDefault(`export { default, foo } from './index.js'`, 'script')
98
+ ).toMatchInlineSnapshot(`
99
+ "import { default as __VUE_DEFAULT__ } from './index.js'
100
+ export { foo } from './index.js'
101
+ const script = __VUE_DEFAULT__"
102
+ `)
103
+
104
+ expect(
105
+ rewriteDefault(`export { default , foo } from './index.js'`, 'script')
106
+ ).toMatchInlineSnapshot(`
107
+ "import { default as __VUE_DEFAULT__ } from './index.js'
108
+ export { foo } from './index.js'
109
+ const script = __VUE_DEFAULT__"
110
+ `)
111
+
112
+ expect(
113
+ rewriteDefault(`export { foo, default } from './index.js'`, 'script')
114
+ ).toMatchInlineSnapshot(`
115
+ "import { default as __VUE_DEFAULT__ } from './index.js'
116
+ export { foo, } from './index.js'
117
+ const script = __VUE_DEFAULT__"
118
+ `)
119
+
120
+ expect(
121
+ rewriteDefault(
122
+ `export { foo as default, bar } from './index.js'`,
123
+ 'script'
124
+ )
125
+ ).toMatchInlineSnapshot(`
126
+ "import { foo } from './index.js'
127
+ export { bar } from './index.js'
128
+ const script = foo"
129
+ `)
130
+
131
+ expect(
132
+ rewriteDefault(
133
+ `export { foo as default , bar } from './index.js'`,
134
+ 'script'
135
+ )
136
+ ).toMatchInlineSnapshot(`
137
+ "import { foo } from './index.js'
138
+ export { bar } from './index.js'
139
+ const script = foo"
140
+ `)
141
+
142
+ expect(
143
+ rewriteDefault(
144
+ `export { bar, foo as default } from './index.js'`,
145
+ 'script'
146
+ )
147
+ ).toMatchInlineSnapshot(`
148
+ "import { foo } from './index.js'
149
+ export { bar, } from './index.js'
150
+ const script = foo"
151
+ `)
152
+ })
153
+
154
+ test('export default class', async () => {
155
+ expect(rewriteDefault(`export default class Foo {}`, 'script'))
156
+ .toMatchInlineSnapshot(`
157
+ "class Foo {}
158
+ const script = Foo"
159
+ `)
160
+ })
161
+
162
+ test('export default class w/ comments', async () => {
163
+ expect(
164
+ rewriteDefault(`// export default\nexport default class Foo {}`, 'script')
165
+ ).toMatchInlineSnapshot(`
166
+ "// export default
167
+ class Foo {}
168
+ const script = Foo"
169
+ `)
170
+ })
171
+
172
+ test('export default class w/ comments 2', async () => {
173
+ expect(
174
+ rewriteDefault(
175
+ `export default {}\n` + `// export default class Foo {}`,
176
+ 'script'
177
+ )
178
+ ).toMatchInlineSnapshot(`
179
+ "const script = {}
180
+ // export default class Foo {}"
181
+ `)
182
+ })
183
+
184
+ test('export default class w/ comments 3', async () => {
185
+ expect(
186
+ rewriteDefault(
187
+ `/*\nexport default class Foo {}*/\n` + `export default class Bar {}`,
188
+ 'script'
189
+ )
190
+ ).toMatchInlineSnapshot(`
191
+ "/*
192
+ export default class Foo {}*/
193
+ class Bar {}
194
+ const script = Bar"
195
+ `)
196
+ })
197
+
198
+ test('@Component\nexport default class', async () => {
199
+ expect(rewriteDefault(`@Component\nexport default class Foo {}`, 'script'))
200
+ .toMatchInlineSnapshot(`
201
+ "@Component
202
+ class Foo {}
203
+ const script = Foo"
204
+ `)
205
+ })
206
+
207
+ test('@Component\nexport default class w/ comments', async () => {
208
+ expect(
209
+ rewriteDefault(`// export default\n@Component\nexport default class Foo {}`, 'script')
210
+ ).toMatchInlineSnapshot(`
211
+ "// export default
212
+ @Component
213
+ class Foo {}
214
+ const script = Foo"
215
+ `)
216
+ })
217
+
218
+ test('@Component\nexport default class w/ comments 2', async () => {
219
+ expect(
220
+ rewriteDefault(
221
+ `export default {}\n` + `// @Component\n// export default class Foo {}`,
222
+ 'script'
223
+ )
224
+ ).toMatchInlineSnapshot(`
225
+ "const script = {}
226
+ // @Component
227
+ // export default class Foo {}"
228
+ `)
229
+ })
230
+
231
+ test('@Component\nexport default class w/ comments 3', async () => {
232
+ expect(
233
+ rewriteDefault(
234
+ `/*\n@Component\nexport default class Foo {}*/\n` + `export default class Bar {}`,
235
+ 'script'
236
+ )
237
+ ).toMatchInlineSnapshot(`
238
+ "/*
239
+ @Component
240
+ export default class Foo {}*/
241
+ class Bar {}
242
+ const script = Bar"
243
+ `)
244
+ })
245
+ })
@@ -13,7 +13,7 @@ import {
13
13
  ASTText,
14
14
  CompilerOptions
15
15
  } from 'types/compiler'
16
- import { BindingMetadata } from 'sfc/types'
16
+ import { BindingMetadata, BindingTypes } from 'sfc/types'
17
17
 
18
18
  type TransformFunction = (el: ASTElement, code: string) => string
19
19
  type DataGenFunction = (el: ASTElement) => string
@@ -95,18 +95,16 @@ export function genElement(el: ASTElement, state: CodegenState): string {
95
95
  code = genComponent(el.component, el, state)
96
96
  } else {
97
97
  let data
98
- if (!el.plain || (el.pre && state.maybeComponent(el))) {
98
+ const maybeComponent = state.maybeComponent(el)
99
+ if (!el.plain || (el.pre && maybeComponent)) {
99
100
  data = genData(el, state)
100
101
  }
101
102
 
102
103
  let tag: string | undefined
103
104
  // check if this is a component in <script setup>
104
105
  const bindings = state.options.bindings
105
- if (bindings && bindings.__isScriptSetup !== false) {
106
- tag =
107
- checkBindingType(bindings, el.tag) ||
108
- checkBindingType(bindings, camelize(el.tag)) ||
109
- checkBindingType(bindings, capitalize(camelize(el.tag)))
106
+ if (maybeComponent && bindings && bindings.__isScriptSetup !== false) {
107
+ tag = checkBindingType(bindings, el.tag)
110
108
  }
111
109
  if (!tag) tag = `'${el.tag}'`
112
110
 
@@ -126,9 +124,32 @@ export function genElement(el: ASTElement, state: CodegenState): string {
126
124
  }
127
125
 
128
126
  function checkBindingType(bindings: BindingMetadata, key: string) {
129
- const type = bindings[key]
130
- if (type && type.startsWith('setup')) {
131
- return key
127
+ const camelName = camelize(key)
128
+ const PascalName = capitalize(camelName)
129
+ const checkType = (type) => {
130
+ if (bindings[key] === type) {
131
+ return key
132
+ }
133
+ if (bindings[camelName] === type) {
134
+ return camelName
135
+ }
136
+ if (bindings[PascalName] === type) {
137
+ return PascalName
138
+ }
139
+ }
140
+ const fromConst =
141
+ checkType(BindingTypes.SETUP_CONST) ||
142
+ checkType(BindingTypes.SETUP_REACTIVE_CONST)
143
+ if (fromConst) {
144
+ return fromConst
145
+ }
146
+
147
+ const fromMaybeRef =
148
+ checkType(BindingTypes.SETUP_LET) ||
149
+ checkType(BindingTypes.SETUP_REF) ||
150
+ checkType(BindingTypes.SETUP_MAYBE_REF)
151
+ if (fromMaybeRef) {
152
+ return fromMaybeRef
132
153
  }
133
154
  }
134
155
 
@@ -34,6 +34,7 @@ export function initMixin(Vue: typeof Component) {
34
34
  vm.__v_skip = true
35
35
  // effect scope
36
36
  vm._scope = new EffectScope(true /* detached */)
37
+ vm._scope._vm = true
37
38
  // merge options
38
39
  if (options && options._isComponent) {
39
40
  // optimize internal component instantiation
@@ -1,8 +1,7 @@
1
1
  import { warn, hasSymbol, isFunction, isObject } from '../util/index'
2
2
  import { defineReactive, toggleObserving } from '../observer/index'
3
3
  import type { Component } from 'types/component'
4
- import { provide } from 'v3/apiInject'
5
- import { setCurrentInstance } from '../../v3/currentInstance'
4
+ import { resolveProvided } from 'v3/apiInject'
6
5
 
7
6
  export function initProvide(vm: Component) {
8
7
  const provideOption = vm.$options.provide
@@ -13,12 +12,18 @@ export function initProvide(vm: Component) {
13
12
  if (!isObject(provided)) {
14
13
  return
15
14
  }
15
+ const source = resolveProvided(vm)
16
+ // IE9 doesn't support Object.getOwnPropertyDescriptors so we have to
17
+ // iterate the keys ourselves.
16
18
  const keys = hasSymbol ? Reflect.ownKeys(provided) : Object.keys(provided)
17
- setCurrentInstance(vm)
18
19
  for (let i = 0; i < keys.length; i++) {
19
- provide(keys[i], provided[keys[i]])
20
+ const key = keys[i]
21
+ Object.defineProperty(
22
+ source,
23
+ key,
24
+ Object.getOwnPropertyDescriptor(provided, key)!
25
+ )
20
26
  }
21
- setCurrentInstance()
22
27
  }
23
28
  }
24
29
 
@@ -18,7 +18,7 @@ import {
18
18
  invokeWithErrorHandling
19
19
  } from '../util/index'
20
20
  import { currentInstance, setCurrentInstance } from 'v3/currentInstance'
21
- import { syncSetupAttrs } from 'v3/apiSetup'
21
+ import { syncSetupProxy } from 'v3/apiSetup'
22
22
 
23
23
  export let activeInstance: any = null
24
24
  export let isUpdatingChildComponent: boolean = false
@@ -288,11 +288,12 @@ export function updateChildComponent(
288
288
  // force update if attrs are accessed and has changed since it may be
289
289
  // passed to a child component.
290
290
  if (
291
- syncSetupAttrs(
291
+ syncSetupProxy(
292
292
  vm._attrsProxy,
293
293
  attrs,
294
294
  (prevVNode.data && prevVNode.data.attrs) || emptyObject,
295
- vm
295
+ vm,
296
+ '$attrs'
296
297
  )
297
298
  ) {
298
299
  needsForceUpdate = true
@@ -300,7 +301,20 @@ export function updateChildComponent(
300
301
  }
301
302
  vm.$attrs = attrs
302
303
 
303
- vm.$listeners = listeners || emptyObject
304
+ // update listeners
305
+ listeners = listeners || emptyObject
306
+ const prevListeners = vm.$options._parentListeners
307
+ if (vm._listenersProxy) {
308
+ syncSetupProxy(
309
+ vm._listenersProxy,
310
+ listeners,
311
+ prevListeners || emptyObject,
312
+ vm,
313
+ '$listeners'
314
+ )
315
+ }
316
+ vm.$listeners = vm.$options._parentListeners = listeners
317
+ updateComponentListeners(vm, listeners, prevListeners)
304
318
 
305
319
  // update props
306
320
  if (propsData && vm.$options.props) {
@@ -317,12 +331,6 @@ export function updateChildComponent(
317
331
  vm.$options.propsData = propsData
318
332
  }
319
333
 
320
- // update listeners
321
- listeners = listeners || emptyObject
322
- const oldListeners = vm.$options._parentListeners
323
- vm.$options._parentListeners = listeners
324
- updateComponentListeners(vm, listeners, oldListeners)
325
-
326
334
  // resolve slots + force update if has children
327
335
  if (needsForceUpdate) {
328
336
  vm.$slots = resolveSlots(renderChildren, parentVnode.context)
@@ -19,7 +19,7 @@ if (__DEV__) {
19
19
  'referenced during render. Make sure that this property is reactive, ' +
20
20
  'either in the data option, or for class-based components, by ' +
21
21
  'initializing the property. ' +
22
- 'See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.',
22
+ 'See: https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.',
23
23
  target
24
24
  )
25
25
  }
@@ -29,7 +29,7 @@ if (__DEV__) {
29
29
  `Property "${key}" must be accessed with "$data.${key}" because ` +
30
30
  'properties starting with "$" or "_" are not proxied in the Vue instance to ' +
31
31
  'prevent conflicts with Vue internals. ' +
32
- 'See: https://vuejs.org/v2/api/#data',
32
+ 'See: https://v2.vuejs.org/v2/api/#data',
33
33
  target
34
34
  )
35
35
  }
@@ -25,7 +25,13 @@ export function initRender(vm: Component) {
25
25
  const parentVnode = (vm.$vnode = options._parentVnode!) // the placeholder node in parent tree
26
26
  const renderContext = parentVnode && (parentVnode.context as Component)
27
27
  vm.$slots = resolveSlots(options._renderChildren, renderContext)
28
- vm.$scopedSlots = emptyObject
28
+ vm.$scopedSlots = parentVnode
29
+ ? normalizeScopedSlots(
30
+ vm.$parent!,
31
+ parentVnode.data!.scopedSlots,
32
+ vm.$slots
33
+ )
34
+ : emptyObject
29
35
  // bind the createElement fn to this instance
30
36
  // so that we get proper render context inside it.
31
37
  // args order: tag, data, children, normalizationType, alwaysNormalize
@@ -98,7 +104,7 @@ export function renderMixin(Vue: typeof Component) {
98
104
  const vm: Component = this
99
105
  const { render, _parentVnode } = vm.$options
100
106
 
101
- if (_parentVnode) {
107
+ if (_parentVnode && vm._isMounted) {
102
108
  vm.$scopedSlots = normalizeScopedSlots(
103
109
  vm.$parent!,
104
110
  _parentVnode.data!.scopedSlots,
@@ -127,7 +127,7 @@ function initData(vm: Component) {
127
127
  __DEV__ &&
128
128
  warn(
129
129
  'data functions should return an object:\n' +
130
- 'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',
130
+ 'https://v2.vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',
131
131
  vm
132
132
  )
133
133
  }
@@ -191,7 +191,7 @@ export function defineReactive(
191
191
  } else if (getter) {
192
192
  // #7981: for accessor properties without setter
193
193
  return
194
- } else if (isRef(value) && !isRef(newVal)) {
194
+ } else if (!shallow && isRef(value) && !isRef(newVal)) {
195
195
  value.value = newVal
196
196
  return
197
197
  } else {
@@ -59,6 +59,15 @@ if (inBrowser && !isIE) {
59
59
  }
60
60
  }
61
61
 
62
+ const sortCompareFn = (a: Watcher, b: Watcher): number => {
63
+ if (a.post) {
64
+ if (!b.post) return 1
65
+ } else if (b.post) {
66
+ return -1
67
+ }
68
+ return a.id - b.id
69
+ }
70
+
62
71
  /**
63
72
  * Flush both queues and run the watchers.
64
73
  */
@@ -75,7 +84,7 @@ function flushSchedulerQueue() {
75
84
  // user watchers are created before the render watcher)
76
85
  // 3. If a component is destroyed during a parent component's watcher run,
77
86
  // its watchers can be skipped.
78
- queue.sort((a, b) => a.id - b.id)
87
+ queue.sort(sortCompareFn)
79
88
 
80
89
  // do not cache length because more watchers might be pushed
81
90
  // as we run existing watchers
@@ -58,6 +58,7 @@ export default class Watcher implements DepTarget {
58
58
  noRecurse?: boolean
59
59
  getter: Function
60
60
  value: any
61
+ post: boolean
61
62
 
62
63
  // dev only
63
64
  onTrack?: ((event: DebuggerEvent) => void) | undefined
@@ -70,11 +71,18 @@ export default class Watcher implements DepTarget {
70
71
  options?: WatcherOptions | null,
71
72
  isRenderWatcher?: boolean
72
73
  ) {
73
- recordEffectScope(this, activeEffectScope || (vm ? vm._scope : undefined))
74
- if ((this.vm = vm)) {
75
- if (isRenderWatcher) {
76
- vm._watcher = this
77
- }
74
+ recordEffectScope(
75
+ this,
76
+ // if the active effect scope is manually created (not a component scope),
77
+ // prioritize it
78
+ activeEffectScope && !activeEffectScope._vm
79
+ ? activeEffectScope
80
+ : vm
81
+ ? vm._scope
82
+ : undefined
83
+ )
84
+ if ((this.vm = vm) && isRenderWatcher) {
85
+ vm._watcher = this
78
86
  }
79
87
  // options
80
88
  if (options) {
@@ -93,6 +101,7 @@ export default class Watcher implements DepTarget {
93
101
  this.cb = cb
94
102
  this.id = ++uid // uid for batching
95
103
  this.active = true
104
+ this.post = false
96
105
  this.dirty = this.lazy // for lazy watchers
97
106
  this.deps = []
98
107
  this.newDeps = []
@@ -103,7 +103,15 @@ function normalizeDirectives(
103
103
  }
104
104
  res[getRawDirName(dir)] = dir
105
105
  if (vm._setupState && vm._setupState.__sfc) {
106
- dir.def = dir.def || resolveAsset(vm, '_setupState', 'v-' + dir.name)
106
+ const setupDef = dir.def || resolveAsset(vm, '_setupState', 'v-' + dir.name)
107
+ if (typeof setupDef === 'function') {
108
+ dir.def = {
109
+ bind: setupDef,
110
+ update: setupDef,
111
+ }
112
+ } else {
113
+ dir.def = setupDef
114
+ }
107
115
  }
108
116
  dir.def = dir.def || resolveAsset(vm.$options, 'directives', dir.name, true)
109
117
  }
@@ -33,6 +33,7 @@ export default class VNode {
33
33
  fnOptions?: ComponentOptions | null // for SSR caching
34
34
  devtoolsMeta?: Object | null // used to store functional render context for devtools
35
35
  fnScopeId?: string | null // functional scope id support
36
+ isComponentRootElement?: boolean | null // for SSR directives
36
37
 
37
38
  constructor(
38
39
  tag?: string,
@@ -111,6 +111,7 @@ export declare class Component {
111
111
  _setupProxy?: Record<string, any>
112
112
  _setupContext?: SetupContext
113
113
  _attrsProxy?: Record<string, any>
114
+ _listenersProxy?: Record<string, Function | Function[]>
114
115
  _slotsProxy?: Record<string, () => VNode[]>
115
116
  _preWatchers?: Watcher[]
116
117
 
@@ -1,5 +1,6 @@
1
1
  import { isFunction, warn } from 'core/util'
2
2
  import { currentInstance } from './currentInstance'
3
+ import type { Component } from 'types/component'
3
4
 
4
5
  export interface InjectionKey<T> extends Symbol {}
5
6
 
@@ -9,19 +10,23 @@ export function provide<T>(key: InjectionKey<T> | string | number, value: T) {
9
10
  warn(`provide() can only be used inside setup().`)
10
11
  }
11
12
  } else {
12
- let provides = currentInstance._provided
13
- // by default an instance inherits its parent's provides object
14
- // but when it needs to provide values of its own, it creates its
15
- // own provides object using parent provides object as prototype.
16
- // this way in `inject` we can simply look up injections from direct
17
- // parent and let the prototype chain do the work.
18
- const parentProvides =
19
- currentInstance.$parent && currentInstance.$parent._provided
20
- if (parentProvides === provides) {
21
- provides = currentInstance._provided = Object.create(parentProvides)
22
- }
23
13
  // TS doesn't allow symbol as index type
24
- provides[key as string] = value
14
+ resolveProvided(currentInstance)[key as string] = value
15
+ }
16
+ }
17
+
18
+ export function resolveProvided(vm: Component): Record<string, any> {
19
+ // by default an instance inherits its parent's provides object
20
+ // but when it needs to provide values of its own, it creates its
21
+ // own provides object using parent provides object as prototype.
22
+ // this way in `inject` we can simply look up injections from direct
23
+ // parent and let the prototype chain do the work.
24
+ const existing = vm._provided
25
+ const parentProvides = vm.$parent && vm.$parent._provided
26
+ if (parentProvides === existing) {
27
+ return (vm._provided = Object.create(parentProvides))
28
+ } else {
29
+ return existing
25
30
  }
26
31
  }
27
32