diff --git a/.eslintrc.js b/.eslintrc.js index caa5c7213ca..98f42a74b9a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -11,7 +11,7 @@ module.exports = { 'error', // we are only using this rule to check for unused arguments since TS // catches unused variables but not args. - { varsIgnorePattern: '.*', args: 'after-used', argsIgnorePattern: '^_' } + { varsIgnorePattern: '.*', args: 'none' } ], // most of the codebase are expected to be env agnostic 'no-restricted-globals': ['error', ...DOMGlobals, ...NodeGlobals], diff --git a/CHANGELOG.md b/CHANGELOG.md index 29e9398b057..b289346e282 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ +# [3.0.0-rc.12](https://github.com/vuejs/vue-next/compare/v3.0.0-rc.11...v3.0.0-rc.12) (2020-09-16) + + +### Bug Fixes + +* **reactivity:** effect shoud only recursively self trigger with explicit options ([3810de7](https://github.com/vuejs/vue-next/commit/3810de7d6bd0044177f043285228c2e988093883)), closes [#2125](https://github.com/vuejs/vue-next/issues/2125) +* **runtime-core:** ensure root stable fragments inherit elements for moving ([bebd44f](https://github.com/vuejs/vue-next/commit/bebd44f793ccd13bfdf90c7e45eac320a340650c)), closes [#2134](https://github.com/vuejs/vue-next/issues/2134) +* **runtime-core:** should still do full traverse of stable fragment children in dev + hmr ([dd40ad8](https://github.com/vuejs/vue-next/commit/dd40ad8fca47af0e1f0a963be2f48c23f7457952)) +* **runtime-core/async-component:** fix error component when there are no error handlers ([c7b4a37](https://github.com/vuejs/vue-next/commit/c7b4a379cf8627c79a01d61039d3e3b283477dc1)), closes [#2129](https://github.com/vuejs/vue-next/issues/2129) +* **types/tsx:** optional props from Mixin/Extends are treated as required ([#2048](https://github.com/vuejs/vue-next/issues/2048)) ([89e9ab8](https://github.com/vuejs/vue-next/commit/89e9ab8a2a387f26a370848db0b1ffb1d0ab9549)) + + +### Features + +* **compiler-sfc:** `additionalData` support for css preprocessors ([#2126](https://github.com/vuejs/vue-next/issues/2126)) ([066d514](https://github.com/vuejs/vue-next/commit/066d514d757fb7e8844104210d7d04cc11598fef)) + + + # [3.0.0-rc.11](https://github.com/vuejs/vue-next/compare/v3.0.0-rc.10...v3.0.0-rc.11) (2020-09-15) diff --git a/package.json b/package.json index 15608a2dd9e..d4c700cc635 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "private": true, - "version": "3.0.0-rc.11", + "version": "3.0.0-rc.12", "workspaces": [ "packages/*" ], diff --git a/packages/compiler-core/package.json b/packages/compiler-core/package.json index 8939293bae6..f0928920831 100644 --- a/packages/compiler-core/package.json +++ b/packages/compiler-core/package.json @@ -1,6 +1,6 @@ { "name": "@vue/compiler-core", - "version": "3.0.0-rc.11", + "version": "3.0.0-rc.12", "description": "@vue/compiler-core", "main": "index.js", "module": "dist/compiler-core.esm-bundler.js", @@ -31,7 +31,7 @@ }, "homepage": "https://github.com/vuejs/vue-next/tree/master/packages/compiler-core#readme", "dependencies": { - "@vue/shared": "3.0.0-rc.11", + "@vue/shared": "3.0.0-rc.12", "@babel/parser": "^7.11.5", "@babel/types": "^7.11.5", "estree-walker": "^2.0.1", diff --git a/packages/compiler-dom/package.json b/packages/compiler-dom/package.json index 97cf1e6db88..3c98116f0a3 100644 --- a/packages/compiler-dom/package.json +++ b/packages/compiler-dom/package.json @@ -1,6 +1,6 @@ { "name": "@vue/compiler-dom", - "version": "3.0.0-rc.11", + "version": "3.0.0-rc.12", "description": "@vue/compiler-dom", "main": "index.js", "module": "dist/compiler-dom.esm-bundler.js", @@ -36,7 +36,7 @@ }, "homepage": "https://github.com/vuejs/vue-next/tree/master/packages/compiler-dom#readme", "dependencies": { - "@vue/shared": "3.0.0-rc.11", - "@vue/compiler-core": "3.0.0-rc.11" + "@vue/shared": "3.0.0-rc.12", + "@vue/compiler-core": "3.0.0-rc.12" } } diff --git a/packages/compiler-sfc/__tests__/compileStyle.spec.ts b/packages/compiler-sfc/__tests__/compileStyle.spec.ts index 46a34463907..ce83747033b 100644 --- a/packages/compiler-sfc/__tests__/compileStyle.spec.ts +++ b/packages/compiler-sfc/__tests__/compileStyle.spec.ts @@ -337,7 +337,7 @@ describe('SFC style preprocessors', () => { ]) }) - test('scss respect user-defined options.additionalData', () => { + test('scss respect user-defined string options.additionalData', () => { const res = compileStyle({ preprocessOptions: { additionalData: ` @@ -358,4 +358,32 @@ describe('SFC style preprocessors', () => { expect(res.errors.length).toBe(0) }) + + test('scss respect user-defined function options.additionalData', () => { + const source = ` + .square { + @include square(100px); + } + ` + const filename = path.resolve(__dirname, './fixture/test.scss') + const res = compileStyle({ + preprocessOptions: { + additionalData: (s: string, f: string) => { + expect(s).toBe(source) + expect(f).toBe(filename) + return ` + @mixin square($size) { + width: $size; + height: $size; + }` + } + }, + source, + filename, + id: '', + preprocessLang: 'scss' + }) + + expect(res.errors.length).toBe(0) + }) }) diff --git a/packages/compiler-sfc/package.json b/packages/compiler-sfc/package.json index 3fcee9ceaef..9815e4fa716 100644 --- a/packages/compiler-sfc/package.json +++ b/packages/compiler-sfc/package.json @@ -1,6 +1,6 @@ { "name": "@vue/compiler-sfc", - "version": "3.0.0-rc.11", + "version": "3.0.0-rc.12", "description": "@vue/compiler-sfc", "main": "dist/compiler-sfc.cjs.js", "types": "dist/compiler-sfc.d.ts", @@ -32,15 +32,15 @@ }, "homepage": "https://github.com/vuejs/vue-next/tree/master/packages/compiler-sfc#readme", "peerDependencies": { - "vue": "3.0.0-rc.11" + "vue": "3.0.0-rc.12" }, "dependencies": { "@babel/parser": "^7.11.5", "@babel/types": "^7.11.5", - "@vue/compiler-core": "3.0.0-rc.11", - "@vue/compiler-dom": "3.0.0-rc.11", - "@vue/compiler-ssr": "3.0.0-rc.11", - "@vue/shared": "3.0.0-rc.11", + "@vue/compiler-core": "3.0.0-rc.12", + "@vue/compiler-dom": "3.0.0-rc.12", + "@vue/compiler-ssr": "3.0.0-rc.12", + "@vue/shared": "3.0.0-rc.12", "consolidate": "^0.16.0", "estree-walker": "^2.0.1", "hash-sum": "^2.0.0", diff --git a/packages/compiler-sfc/src/stylePreprocessors.ts b/packages/compiler-sfc/src/stylePreprocessors.ts index a6287dfc7e6..1a4e7b7c87f 100644 --- a/packages/compiler-sfc/src/stylePreprocessors.ts +++ b/packages/compiler-sfc/src/stylePreprocessors.ts @@ -1,12 +1,14 @@ import merge from 'merge-source-map' import { RawSourceMap } from 'source-map' import { SFCStyleCompileOptions } from './compileStyle' +import { isFunction } from '@vue/shared' export type StylePreprocessor = ( source: string, map: RawSourceMap | undefined, options: { [key: string]: any + additionalData?: string | ((source: string, filename: string) => string) filename: string }, customRequire: SFCStyleCompileOptions['preprocessCustomRequire'] @@ -24,7 +26,7 @@ const scss: StylePreprocessor = (source, map, options, load = require) => { const nodeSass = load('sass') const finalOptions = { ...options, - data: (options.additionalData || '') + source, + data: getSource(source, options.filename, options.additionalData), file: options.filename, outFile: options.filename, sourceMap: !!map @@ -66,7 +68,7 @@ const less: StylePreprocessor = (source, map, options, load = require) => { let result: any let error: Error | null = null nodeLess.render( - source, + getSource(source, options.filename, options.additionalData), { ...options, syncImport: true }, (err: Error | null, output: any) => { error = err @@ -117,6 +119,18 @@ const styl: StylePreprocessor = (source, map, options, load = require) => { } } +function getSource( + source: string, + filename: string, + additionalData?: string | ((source: string, filename: string) => string) +) { + if (!additionalData) return source + if (isFunction(additionalData)) { + return additionalData(source, filename) + } + return additionalData + source +} + export type PreprocessLang = 'less' | 'sass' | 'scss' | 'styl' | 'stylus' export const processors: Record = { diff --git a/packages/compiler-ssr/package.json b/packages/compiler-ssr/package.json index 1a8aa3a9b5c..887859e6dbc 100644 --- a/packages/compiler-ssr/package.json +++ b/packages/compiler-ssr/package.json @@ -1,6 +1,6 @@ { "name": "@vue/compiler-ssr", - "version": "3.0.0-rc.11", + "version": "3.0.0-rc.12", "description": "@vue/compiler-ssr", "main": "dist/compiler-ssr.cjs.js", "types": "dist/compiler-ssr.d.ts", @@ -28,7 +28,7 @@ }, "homepage": "https://github.com/vuejs/vue-next/tree/master/packages/compiler-ssr#readme", "dependencies": { - "@vue/shared": "3.0.0-rc.11", - "@vue/compiler-dom": "3.0.0-rc.11" + "@vue/shared": "3.0.0-rc.12", + "@vue/compiler-dom": "3.0.0-rc.12" } } diff --git a/packages/reactivity/package.json b/packages/reactivity/package.json index e3702b9afee..cc8983720a0 100644 --- a/packages/reactivity/package.json +++ b/packages/reactivity/package.json @@ -1,6 +1,6 @@ { "name": "@vue/reactivity", - "version": "3.0.0-rc.11", + "version": "3.0.0-rc.12", "description": "@vue/reactivity", "main": "index.js", "module": "dist/reactivity.esm-bundler.js", @@ -36,6 +36,6 @@ }, "homepage": "https://github.com/vuejs/vue-next/tree/master/packages/reactivity#readme", "dependencies": { - "@vue/shared": "3.0.0-rc.11" + "@vue/shared": "3.0.0-rc.12" } } diff --git a/packages/reactivity/src/effect.ts b/packages/reactivity/src/effect.ts index 495d6714939..2d2b4d2a1be 100644 --- a/packages/reactivity/src/effect.ts +++ b/packages/reactivity/src/effect.ts @@ -25,6 +25,7 @@ export interface ReactiveEffectOptions { onTrack?: (event: DebuggerEvent) => void onTrigger?: (event: DebuggerEvent) => void onStop?: () => void + allowRecurse?: boolean } export type DebuggerEvent = { @@ -178,7 +179,11 @@ export function trigger( const effects = new Set() const add = (effectsToAdd: Set | undefined) => { if (effectsToAdd) { - effectsToAdd.forEach(effect => effects.add(effect)) + effectsToAdd.forEach(effect => { + if (effect !== activeEffect || effect.options.allowRecurse) { + effects.add(effect) + } + }) } } diff --git a/packages/runtime-core/__tests__/apiAsyncComponent.spec.ts b/packages/runtime-core/__tests__/apiAsyncComponent.spec.ts index 0ba6079ab3d..af78ee7e0c9 100644 --- a/packages/runtime-core/__tests__/apiAsyncComponent.spec.ts +++ b/packages/runtime-core/__tests__/apiAsyncComponent.spec.ts @@ -206,6 +206,51 @@ describe('api: defineAsyncComponent', () => { expect(serializeInner(root)).toBe('resolved') }) + // #2129 + test('error with error component, without global handler', async () => { + let resolve: (comp: Component) => void + let reject: (e: Error) => void + const Foo = defineAsyncComponent({ + loader: () => + new Promise((_resolve, _reject) => { + resolve = _resolve as any + reject = _reject + }), + errorComponent: (props: { error: Error }) => props.error.message + }) + + const toggle = ref(true) + const root = nodeOps.createElement('div') + const app = createApp({ + render: () => (toggle.value ? h(Foo) : null) + }) + + app.mount(root) + expect(serializeInner(root)).toBe('') + + const err = new Error('errored out') + reject!(err) + await timeout() + expect(serializeInner(root)).toBe('errored out') + expect( + 'Unhandled error during execution of async component loader' + ).toHaveBeenWarned() + + toggle.value = false + await nextTick() + expect(serializeInner(root)).toBe('') + + // errored out on previous load, toggle and mock success this time + toggle.value = true + await nextTick() + expect(serializeInner(root)).toBe('') + + // should render this time + resolve!(() => 'resolved') + await timeout() + expect(serializeInner(root)).toBe('resolved') + }) + test('error with error + loading components', async () => { let resolve: (comp: Component) => void let reject: (e: Error) => void diff --git a/packages/runtime-core/__tests__/apiWatch.spec.ts b/packages/runtime-core/__tests__/apiWatch.spec.ts index 138a3e04f5d..7b64e50bd5f 100644 --- a/packages/runtime-core/__tests__/apiWatch.spec.ts +++ b/packages/runtime-core/__tests__/apiWatch.spec.ts @@ -779,4 +779,17 @@ describe('api: watch', () => { // should trigger now expect(sideEffect).toBe(2) }) + + // #2125 + test('watchEffect should not recursively trigger itself', async () => { + const spy = jest.fn() + const price = ref(10) + const history = ref([]) + watchEffect(() => { + history.value.push(price.value) + spy() + }) + await nextTick() + expect(spy).toHaveBeenCalledTimes(1) + }) }) diff --git a/packages/runtime-core/__tests__/rendererComponent.spec.ts b/packages/runtime-core/__tests__/rendererComponent.spec.ts index 243e4cbd0be..4253779d4cf 100644 --- a/packages/runtime-core/__tests__/rendererComponent.spec.ts +++ b/packages/runtime-core/__tests__/rendererComponent.spec.ts @@ -5,7 +5,10 @@ import { nodeOps, serializeInner, nextTick, - VNode + VNode, + provide, + inject, + Ref } from '@vue/runtime-test' describe('renderer: component', () => { @@ -104,4 +107,34 @@ describe('renderer: component', () => { ) expect(Comp1.updated).not.toHaveBeenCalled() }) + + // #2043 + test('component child synchronously updating parent state should trigger parent re-render', async () => { + const App = { + setup() { + const n = ref(0) + provide('foo', n) + return () => { + return [h('div', n.value), h(Child)] + } + } + } + + const Child = { + setup() { + const n = inject>('foo')! + n.value++ + + return () => { + return h('div', n.value) + } + } + } + + const root = nodeOps.createElement('div') + render(h(App), root) + expect(serializeInner(root)).toBe(`
0
1
`) + await nextTick() + expect(serializeInner(root)).toBe(`
1
1
`) + }) }) diff --git a/packages/runtime-core/package.json b/packages/runtime-core/package.json index 64b2dec3d11..78226ccd5fc 100644 --- a/packages/runtime-core/package.json +++ b/packages/runtime-core/package.json @@ -1,6 +1,6 @@ { "name": "@vue/runtime-core", - "version": "3.0.0-rc.11", + "version": "3.0.0-rc.12", "description": "@vue/runtime-core", "main": "index.js", "module": "dist/runtime-core.esm-bundler.js", @@ -32,7 +32,7 @@ }, "homepage": "https://github.com/vuejs/vue-next/tree/master/packages/runtime-core#readme", "dependencies": { - "@vue/shared": "3.0.0-rc.11", - "@vue/reactivity": "3.0.0-rc.11" + "@vue/shared": "3.0.0-rc.12", + "@vue/reactivity": "3.0.0-rc.12" } } diff --git a/packages/runtime-core/src/apiAsyncComponent.ts b/packages/runtime-core/src/apiAsyncComponent.ts index 3f668a46242..a4c46867442 100644 --- a/packages/runtime-core/src/apiAsyncComponent.ts +++ b/packages/runtime-core/src/apiAsyncComponent.ts @@ -117,7 +117,12 @@ export function defineAsyncComponent< const onError = (err: Error) => { pendingRequest = null - handleError(err, instance, ErrorCodes.ASYNC_COMPONENT_LOADER) + handleError( + err, + instance, + ErrorCodes.ASYNC_COMPONENT_LOADER, + !errorComponent /* do not throw in dev if user provided error component */ + ) } // suspense-controlled or SSR. @@ -152,7 +157,7 @@ export function defineAsyncComponent< if (timeout != null) { setTimeout(() => { - if (!loaded.value) { + if (!loaded.value && !error.value) { const err = new Error( `Async component timed out after ${timeout}ms.` ) diff --git a/packages/runtime-core/src/apiDefineComponent.ts b/packages/runtime-core/src/apiDefineComponent.ts index f3156332b45..ef08d3c6533 100644 --- a/packages/runtime-core/src/apiDefineComponent.ts +++ b/packages/runtime-core/src/apiDefineComponent.ts @@ -13,7 +13,11 @@ import { AllowedComponentProps, ComponentCustomProps } from './component' -import { ExtractPropTypes, ComponentPropsOptions } from './componentProps' +import { + ExtractPropTypes, + ComponentPropsOptions, + ExtractDefaultPropTypes +} from './componentProps' import { EmitsOptions } from './componentEmits' import { isFunction } from '@vue/shared' import { VNodeProps } from './vnode' @@ -37,11 +41,11 @@ export type DefineComponent< E extends EmitsOptions = Record, EE extends string = string, PP = PublicProps, - RequiredProps = Readonly>, - OptionalProps = Readonly> + Props = Readonly>, + Defaults = ExtractDefaultPropTypes > = ComponentPublicInstanceConstructor< CreateComponentPublicInstance< - OptionalProps, + Props, RawBindings, D, C, @@ -49,12 +53,14 @@ export type DefineComponent< Mixin, Extends, E, - PP & OptionalProps + PP & Props, + Defaults, + true > & - RequiredProps + Props > & ComponentOptionsBase< - RequiredProps, + Props, RawBindings, D, C, @@ -62,7 +68,8 @@ export type DefineComponent< Mixin, Extends, E, - EE + EE, + Defaults > & PP diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index 4d6291c9527..ff499d36cdc 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -42,7 +42,11 @@ import { WritableComputedOptions, toRaw } from '@vue/reactivity' -import { ComponentObjectPropsOptions, ExtractPropTypes } from './componentProps' +import { + ComponentObjectPropsOptions, + ExtractPropTypes, + ExtractDefaultPropTypes +} from './componentProps' import { EmitsOptions } from './componentEmits' import { Directive } from './directives' import { @@ -81,7 +85,8 @@ export interface ComponentOptionsBase< Mixin extends ComponentOptionsMixin, Extends extends ComponentOptionsMixin, E extends EmitsOptions, - EE extends string = string + EE extends string = string, + Defaults = {} > extends LegacyOptions, ComponentInternalOptions, @@ -148,6 +153,8 @@ export interface ComponentOptionsBase< __isFragment?: never __isTeleport?: never __isSuspense?: never + + __defaults?: Defaults } export type ComponentOptionsWithoutProps< @@ -159,8 +166,20 @@ export type ComponentOptionsWithoutProps< Mixin extends ComponentOptionsMixin = ComponentOptionsMixin, Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = EmitsOptions, - EE extends string = string -> = ComponentOptionsBase & { + EE extends string = string, + Defaults = {} +> = ComponentOptionsBase< + Props, + RawBindings, + D, + C, + M, + Mixin, + Extends, + E, + EE, + Defaults +> & { props?: undefined } & ThisType< CreateComponentPublicInstance< @@ -172,7 +191,9 @@ export type ComponentOptionsWithoutProps< Mixin, Extends, E, - Readonly + Readonly, + Defaults, + false > > @@ -187,7 +208,18 @@ export type ComponentOptionsWithArrayProps< E extends EmitsOptions = EmitsOptions, EE extends string = string, Props = Readonly<{ [key in PropNames]?: any }> -> = ComponentOptionsBase & { +> = ComponentOptionsBase< + Props, + RawBindings, + D, + C, + M, + Mixin, + Extends, + E, + EE, + {} +> & { props: PropNames[] } & ThisType< CreateComponentPublicInstance< @@ -212,8 +244,20 @@ export type ComponentOptionsWithObjectProps< Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = EmitsOptions, EE extends string = string, - Props = Readonly> -> = ComponentOptionsBase & { + Props = Readonly>, + Defaults = ExtractDefaultPropTypes +> = ComponentOptionsBase< + Props, + RawBindings, + D, + C, + M, + Mixin, + Extends, + E, + EE, + Defaults +> & { props: PropsOptions & ThisType } & ThisType< CreateComponentPublicInstance< @@ -224,7 +268,10 @@ export type ComponentOptionsWithObjectProps< M, Mixin, Extends, - E + E, + Props, + Defaults, + false > > @@ -261,6 +308,7 @@ export type ComponentOptionsMixin = ComponentOptionsBase< any, any, any, + any, any > @@ -347,20 +395,22 @@ interface LegacyOptions< delimiters?: [string, string] } -export type OptionTypesKeys = 'P' | 'B' | 'D' | 'C' | 'M' +export type OptionTypesKeys = 'P' | 'B' | 'D' | 'C' | 'M' | 'Defaults' export type OptionTypesType< P = {}, B = {}, D = {}, C extends ComputedOptions = {}, - M extends MethodOptions = {} + M extends MethodOptions = {}, + Defaults = {} > = { P: P B: B D: D C: C M: M + Defaults: Defaults } const enum OptionTypes { diff --git a/packages/runtime-core/src/componentProps.ts b/packages/runtime-core/src/componentProps.ts index a8bccd9a5af..0fde127a28f 100644 --- a/packages/runtime-core/src/componentProps.ts +++ b/packages/runtime-core/src/componentProps.ts @@ -63,18 +63,15 @@ type PropMethod = T extends (...args: any) => any // if i ? { new (): TConstructor; (): T; readonly prototype: TConstructor } // Create Function like constructor : never -type RequiredKeys = { - [K in keyof T]: T[K] extends - | { required: true } - | (MakeDefaultRequired extends true ? { default: any } : never) - ? K - : never +type RequiredKeys = { + [K in keyof T]: T[K] extends { required: true } | { default: any } ? K : never }[keyof T] -type OptionalKeys = Exclude< - keyof T, - RequiredKeys -> +type OptionalKeys = Exclude> + +type DefaultKeys = { + [K in keyof T]: T[K] extends { default: any } ? K : never +}[keyof T] type InferPropType = T extends null ? any // null & true would fail to infer @@ -86,12 +83,9 @@ type InferPropType = T extends null ? boolean : T extends Prop ? (unknown extends V ? D : V) : T -export type ExtractPropTypes< - O, - MakeDefaultRequired extends boolean = true -> = O extends object - ? { [K in RequiredKeys]: InferPropType } & - { [K in OptionalKeys]?: InferPropType } +export type ExtractPropTypes = O extends object + ? { [K in RequiredKeys]: InferPropType } & + { [K in OptionalKeys]?: InferPropType } : { [K in string]: any } const enum BooleanFlags { @@ -99,6 +93,11 @@ const enum BooleanFlags { shouldCastTrue } +// extract props which defined with default from prop options +export type ExtractDefaultPropTypes = O extends object + ? { [K in DefaultKeys]: InferPropType } + : {} + type NormalizedProp = | null | (PropOptions & { diff --git a/packages/runtime-core/src/componentPublicInstance.ts b/packages/runtime-core/src/componentPublicInstance.ts index 2a9fa747339..e0e239a7997 100644 --- a/packages/runtime-core/src/componentPublicInstance.ts +++ b/packages/runtime-core/src/componentPublicInstance.ts @@ -77,9 +77,11 @@ type MixinToOptionTypes = T extends ComponentOptionsBase< infer M, infer Mixin, infer Extends, - any + any, + any, + infer Defaults > - ? OptionTypesType

& + ? OptionTypesType

& IntersectionMixin & IntersectionMixin : never @@ -130,6 +132,8 @@ export type CreateComponentPublicInstance< Extends extends ComponentOptionsMixin = ComponentOptionsMixin, E extends EmitsOptions = {}, PublicProps = P, + Defaults = {}, + MakeDefaultsOptional extends boolean = false, PublicMixin = IntersectionMixin & IntersectionMixin, PublicP = UnwrapMixinsType & EnsureNonVoid

, PublicB = UnwrapMixinsType & EnsureNonVoid, @@ -137,7 +141,9 @@ export type CreateComponentPublicInstance< PublicC extends ComputedOptions = UnwrapMixinsType & EnsureNonVoid, PublicM extends MethodOptions = UnwrapMixinsType & - EnsureNonVoid + EnsureNonVoid, + PublicDefaults = UnwrapMixinsType & + EnsureNonVoid > = ComponentPublicInstance< PublicP, PublicB, @@ -146,7 +152,9 @@ export type CreateComponentPublicInstance< PublicM, E, PublicProps, - ComponentOptionsBase + PublicDefaults, + MakeDefaultsOptional, + ComponentOptionsBase > // public properties exposed on the proxy, which is used as the render context @@ -159,11 +167,15 @@ export type ComponentPublicInstance< M extends MethodOptions = {}, E extends EmitsOptions = {}, PublicProps = P, - Options = ComponentOptionsBase + Defaults = {}, + MakeDefaultsOptional extends boolean = false, + Options = ComponentOptionsBase > = { $: ComponentInternalInstance $data: D - $props: P & PublicProps + $props: MakeDefaultsOptional extends true + ? Partial & Omit

+ : P & PublicProps $attrs: Data $refs: Data $slots: Slots diff --git a/packages/runtime-core/src/components/Suspense.ts b/packages/runtime-core/src/components/Suspense.ts index 129e62c2f8f..16204b6d0e0 100644 --- a/packages/runtime-core/src/components/Suspense.ts +++ b/packages/runtime-core/src/components/Suspense.ts @@ -502,7 +502,7 @@ function createSuspenseBoundary( optimized } = suspense - // invoke @recede event + // invoke @fallback event const onFallback = vnode.props && vnode.props.onFallback if (isFunction(onFallback)) { onFallback() diff --git a/packages/runtime-core/src/errorHandling.ts b/packages/runtime-core/src/errorHandling.ts index a922e964e5d..1823f6b729c 100644 --- a/packages/runtime-core/src/errorHandling.ts +++ b/packages/runtime-core/src/errorHandling.ts @@ -99,7 +99,8 @@ export function callWithAsyncErrorHandling( export function handleError( err: unknown, instance: ComponentInternalInstance | null, - type: ErrorTypes + type: ErrorTypes, + throwInDev = true ) { const contextVNode = instance ? instance.vnode : null if (instance) { @@ -131,10 +132,15 @@ export function handleError( return } } - logError(err, type, contextVNode) + logError(err, type, contextVNode, throwInDev) } -function logError(err: unknown, type: ErrorTypes, contextVNode: VNode | null) { +function logError( + err: unknown, + type: ErrorTypes, + contextVNode: VNode | null, + throwInDev = true +) { if (__DEV__) { const info = ErrorTypeStrings[type] if (contextVNode) { @@ -144,8 +150,12 @@ function logError(err: unknown, type: ErrorTypes, contextVNode: VNode | null) { if (contextVNode) { popWarningContext() } - // crash in dev so it's more noticeable - throw err + // crash in dev by default so it's more noticeable + if (throwInDev) { + throw err + } else if (!__TEST__) { + console.error(err) + } } else { // recover in prod to reduce the impact on end-user console.error(err) diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts index bc6cedb517b..26c27d544e6 100644 --- a/packages/runtime-core/src/index.ts +++ b/packages/runtime-core/src/index.ts @@ -41,7 +41,7 @@ export { } from './apiLifecycle' export { provide, inject } from './apiInject' export { nextTick } from './scheduler' -export { defineComponent, DefineComponent } from './apiDefineComponent' +export { defineComponent } from './apiDefineComponent' export { defineAsyncComponent } from './apiAsyncComponent' // Advanced API ---------------------------------------------------------------- @@ -166,6 +166,7 @@ export { ComponentCustomProps, AllowedComponentProps } from './component' +export { DefineComponent } from './apiDefineComponent' export { ComponentOptions, ComponentOptionsMixin, @@ -174,8 +175,11 @@ export { ComponentOptionsWithArrayProps, ComponentCustomOptions, ComponentOptionsBase, - RenderFunction + RenderFunction, + MethodOptions, + ComputedOptions } from './componentOptions' +export { EmitsOptions, ObjectEmitsOptions } from './componentEmits' export { ComponentPublicInstance, ComponentCustomProperties @@ -195,7 +199,8 @@ export { PropType, ComponentPropsOptions, ComponentObjectPropsOptions, - ExtractPropTypes + ExtractPropTypes, + ExtractDefaultPropTypes } from './componentProps' export { Directive, diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index f38fc9da134..64d2d3c379f 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -44,7 +44,6 @@ import { flushPostFlushCbs, invalidateJob, flushPreFlushCbs, - SchedulerJob, SchedulerCb } from './scheduler' import { effect, stop, ReactiveEffectOptions, isRef } from '@vue/reactivity' @@ -261,7 +260,9 @@ export const enum MoveType { } const prodEffectOptions = { - scheduler: queueJob + scheduler: queueJob, + // #1801, #2043 component render effects should allow recursive updates + allowRecurse: true } function createDevEffectOptions( @@ -269,6 +270,7 @@ function createDevEffectOptions( ): ReactiveEffectOptions { return { scheduler: queueJob, + allowRecurse: true, onTrack: instance.rtc ? e => invokeArrayFns(instance.rtc!, e) : void 0, onTrigger: instance.rtg ? e => invokeArrayFns(instance.rtg!, e) : void 0 } @@ -1153,9 +1155,16 @@ function baseCreateRenderer( parentSuspense, isSVG ) - // #2080 if the stable fragment has a key, it's a