Vue3 更新日志 01(3.0.5 ~ 3.1.5)
文章目录
https://github.com/vuejs/vue-next/blob/master/CHANGELOG.md
前言
TIP
本系列文说明:会不定期的更新本地的 vue-next 仓库,本系列文章则是针对 git pull 后 的更新内容的分析和记录, 。
可参过链接跳转到对应的分析文章
更新内容:
很久没更新了,惨~~~~~~~~~
捡点重要的来看下吧,以后还是要保持每周拉一次代码比较好!!!
最初分析拉取的代码是: 3.0.4, 现在都 3.1.2 了 尴尬!!!
3.0.8 (2021-03-26)
Important
IMP: SFC style 中的
::v-slotted
和:slotted
🔗
TODO
Bug Fixes [0/44]
compiler: properly bail stringfication for nested slot elements (f74b16c)
compiler-core: allow unicode to appear in identifiers (#3443) (ebedccc), closes #3440
compiler-core: avoid generating useless createVNode helper (#2938) (7715c49), closes #2739
compiler-core: detect v-if branch root with comment as dev fragment (#2785) (4bf7ba1), closes #2780
compiler-core: fix the detection of forwarded slots with v-if or v-for (#3353) (602b58e), closes #3347
compiler-core: should not condense whitespace in RCDATA text mode (#3482) (b4b8215), closes #3479
compiler-dom: stringifyStatic should remove attribute bindings with null value (#3477) (ca6aa01), closes #3475
compiler-sfc: scope Id should not be attached to @keyframe breakpoint rules (#3308) (6cb9475), closes #3304
compiler-sfc: should not rewrite scope variable (#3449) (bbc5fe6), closes #3445
compiler-ssr: keep the order of imports expression for the fallback branch of SSR (#3448) (49f4072), closes #3447
component: prioritize registered component over implicit self-reference via filename (abd129d), closes #2827
hydration: handle camel-case tag name when performing match assertion (#3247) (9036f88), closes #3243
KeepAlive: adapt keepalive for ssr (#3259) (e8e9b00), closes #3255
reactivity: ensure computed can be wrapped by readonly (41e02f0), closes #3376
reactivity: ensure that shallow and normal proxies are tracked seperately (close #2843) (#2851) (22cc4a7)
reactivity: fix shallow readonly behavior for collections (#3003) (68de9f4), closes #3007
rumtime-core: custom dom props should be cloned when cloning a hoisted DOM (#3080) (5dbe834), closes #3072
runtime-core: cache props default values to avoid unnecessary watcher trigger (#3474) (44166b4), closes #3471
runtime-core: ensure only skip unflushed job (#3406) (bf34e33)
runtime-core: fix async component ref handling (#3191) (7562e72), closes #3188
runtime-core: fix erraneous emits warnings w/ mixins (60d777d), closes #2651
runtime-core: fix warning for absent props (#3363) (86ceef4), closes #3362
runtime-core: handle error in async setup (#2881) (d668d48)
runtime-core: handle error in async watchEffect (#3129) (eb1fae6)
runtime-core: should call chained mixins and extends (#3040) (b58bb16), closes #3038
runtime-core: should not cache property access during data() invocation (#3299) (6e88156), closes #3297
runtime-core: should not track deps in pre flush watcher callbacks (d5824b9), closes #2728
runtime-core: the select tag's multiple prop should be set before the children mounting (#3202) (2451dd8), closes #3199
runtime-dom: support mounting app to svg container (#2929) (8ffcde2), closes #2926
ssr: ensure async setup error handling work with suspense during ssr (2e71f07)
ssr: fix memory leak when vnode component render throws error (da944cb), closes #3100
ssr: properly update currentRenderingInstance state during ssr (8c3c14a), closes #2863
ssr: respect render function from extends/mixins in ssr (#3006) (0a583d5), closes #3004
ssr: watchEffect onInvalidate runner initialization (#3323) (e4b5fcc), closes #3322
ssr/hydration: handle ending empty text node (#3246) (420c8f4), closes #3245
teleport: targetAnchor should also be removed when unmounted (#2870) (21d1288)
Teleport: component with multi roots should be removed when unmounted (#3157) (7769513), closes #3156
Teleport: fallback to non-optimized mode when HRM performing updates (#3311) (9cb21d0), closes #3302
transition: toggling branches with in-out mode should be transitioned correctly (#3109) (67a0290), closes #3104
types: allow style to be an array in JSX (#2947) (13c9d2c)
types: union function prop (#3119) (3755e60), closes #3357
types: unwrap refs on public instance data (#3319) (2b588cf), closes #3315
types/jsx: llow tabindex to be a string (#3476) (e4a5712)
add display name for suspense component (#3312) (3b3a9a1)
DONE
Performance Improvements [1/1]
CLOSED: [2021-08-09 Mon 21:23]
support only attaching slot scope ids when necessary (02cbbb7)
SFC style 中使用
:slotted(h1) { color: blue; }
或
::v-slotted(h1) { color: blue; }
可以在当前组件中控制 slot 组件的样式。
https://codesandbox.io/s/damp-cdn-k9eed?file=/src/main.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
const url = process.env.VNEXT_PKG_RC + "/../compiler-sfc/dist/compiler-sfc.cjs.js"; const value = require(url.replace("stb-", "")); const { compileScript, parse, compileStyle } = value; function compileScoped(source, options) { const res = compileStyle({ source, filename: 'test.css', id: 'data-v-test', scoped: true, ...options }) return res.code } const src = `::v-slotted(h1) { color: red; } :slotted(h1) {font-size:12px;}` const code = compileScoped(src) console.log(code) return 0;
h1[data-v-test-s] { color: red; } h1[data-v-test-s] {font-size:12px;} 0
下面会检查 style 中是不是含
::v-slotted(...) {...}
或:slotted(...) {..}
指令1 2 3 4
// packages/compiler-sfc/src/parse.ts // check if the SFC uses :slotted const slottedRE = /(?:::v-|:)slotted\(/ descriptor.slotted = descriptor.styles.some(s => slottedRE.test(s.content))
根据上面的结果,在 parse SFC template 阶段给组件加上
scope-id-s
属性, 如:<div scope-id-s />
1 2 3 4 5
// packages/compiler-ssr/src/transforms/ssrTransformSlotOutlet.ts // inject slot scope id if current template uses :slotted if (context.scopeId && context.slotted !== false) { args.push(`"${context.scopeId}-s"`) }
3.0.7 (2021-08-08)
Important
DONE
Bug Fixes [6/6]
CLOSED: [2021-08-09 Mon 15:23]
✅ compiler-sfc: handle more edge cases in default rewrite (1dedc19)
处理 setup script 中更多语法情况:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
const url = process.env.VNEXT_PKG_RC + "/../compiler-sfc/dist/compiler-sfc.cjs.js"; const value = require(url.replace("stb-", "")); const { rewriteDefault } = value; const test = (hint, code) => { console.log('> ' + hint + '\n'); console.log(rewriteDefault(code, 'script')) } test('1. comments', `// export default\nexport default {}`) test('2. export default class', `export default class Foo {}`) test('3. export default class + commons', `// export default\nexport default class Foo {}`) test('4. export default class + comments 2', `export default {}\n` + `// export default class Foo {}`) test('5. export default class + comments 3', `/*\nexport default class Foo {}*/\n` + `export default class Bar {}`) console.log('------ end ------ '); return 0;
> 1. comments // export default const script = {} > 2. export default class class Foo {} const script = Foo > 3. export default class + commons // export default class Foo {} const script = Foo > 4. export default class + comments 2 const script = {} // export default class Foo {} > 5. export default class + comments 3 /* export default class Foo {}*/ const script = class Bar {} ------ end ------ 0
✅ deps: pin Rollup to 2.38 (34f354b), closes #3332
✅ runtime-core: properties in methods should be writable and enumerable in DEV (#3301) (e3568ba), closes #3300
1 2 3 4 5 6 7 8 9 10 11
3 packages/runtime-core/src/componentOptions.ts @@ -610,7 +610,8 @@ export function applyOptions( Object.defineProperty(ctx, key, { value: methodHandler.bind(publicThis), configurable: true, - enumerable: false + enumerable: true, + writable: true }) } else { ctx[key] = methodHandler.bind(publicThis)
✅ scheduler: ensure updates are always inserted in ascending id order (#3184) (45fae9d), closes #2768 #2829
View isn't updated in a weird case (combination of many factors, transition, injection & computed)
确保 updates 总是以升序被插入,那么在插入之前就得找到适当的 job 索引:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
// #2768 // Use binary-search to find a suitable position in the queue, // so that the queue maintains the increasing order of job's id, // which can prevent the job from being skipped and also can avoid repeated patching. function findInsertionIndex(job: SchedulerJob) { // the start index should be `flushIndex + 1` let start = flushIndex + 1 let end = queue.length const jobId = getId(job) while (start < end) { const middle = (start + end) >>> 1 const middleJobId = getId(queue[middle]) middleJobId < jobId ? (start = middle + 1) : (end = middle) } return start }
在 update 进入任务队列的时候保证所有 jobs 是以升序排列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
export function queueJob(job: SchedulerJob) { // the dedupe search uses the startIndex argument of Array.includes() // by default the search index includes the current job that is being run @@ -72,7 +91,12 @@ export function queueJob(job: SchedulerJob) { )) && job !== currentPreFlushParentJob ) { - queue.push(job) + const pos = findInsertionIndex(job) + if (pos > -1) { + queue.splice(pos, 0, job) + } else { + queue.push(job) + } queueFlush() } }
✅ v-show: v-show takes higher priority than style attribute (#3230) (5ad4036), closes #2757
✅ init devtools after feature flag checks (d0ea745)
DONE
Performance Improvements [1/1]
CLOSED: [2021-08-09 Mon 15:22]
✅ reactivity: only call Set.add if doesn't already have value (#3307) (9cd9883)
对于 Set key-value 都是值,所以当有这个 value 的时候再添加就没有什么意义了, Set 又是不重复集合。
1 2 3 4 5 6 7 8 9 10 11
packages/reactivity/src/collectionHandlers.ts @@ -76,8 +76,8 @@ function add(this: SetTypes, value: unknown) { const target = toRaw(this) const proto = getProto(target) const hadKey = proto.has.call(target, value) - target.add(value) if (!hadKey) { + target.add(value) trigger(target, TriggerOpTypes.ADD, value, value) } return this
3.0.6 (2021-02-24)
Important
DONE
Bug Fixes [25/25]
CLOSED: [2021-08-05 Thu 23:42]
✅ compiler-core: do not mark v-for as stable on const bindings (734c65b), closes vitejs/vite#1956
✅ compiler-dom: ensure global build filename matches the one defined in package.json (close #3181) (#3185) (96b6433)
✅ compiler-dom: fix cdn entries (fcb6c89), closes #3181 #3185
✅ compiler-sfc: compiler blank srcset (#3005) (9dc816d)
允许
<img src="./logo.png" srcset=""/>
的srcset
是个空值,编译后:1 2 3 4
_createVNode(\\"img\\", { src: \\"./logo.png\\", srcset: \\"\\" }),
✅ compiler-sfc: removeSpecifier issue when removing initial imports (script-setup) (#2729) (6d762a8)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
const url = process.env.VNEXT_PKG_RC + "/../compiler-sfc/dist/compiler-sfc.cjs.js"; const value = require(url.replace("stb-", "")); const parser = '/usr/local/lib/node_modules/@babel/parser/lib' const { parse: babelParse } = require(parser) const { compileScript, parse } = value; const src = `<script setup> import { defineProps, defineEmits, ref } from 'vue' defineProps(['foo']) defineEmits(['bar']) const r = ref(0) </script>` const { descriptor } = parse(src) const code = compileScript(descriptor, { id: 'xxxxx' }).content console.log('before babel > \n', code); babelParse(code, { sourceType: 'module', plugins: ['bigInt', 'optionalChaining', 'nullishCoalescingOperator', 'typescript'] }) console.log('after babel > \n', code); return 0;
before babel > import { ref } from 'vue' export default { props: ['foo'], emits: ['bar'], setup(__props, { expose }) { expose() const r = ref(0) return { r, ref, __isScriptSetup: true } } } after babel > import { ref } from 'vue' export default { props: ['foo'], emits: ['bar'], setup(__props, { expose }) { expose() const r = ref(0) return { r, ref, __isScriptSetup: true } } } 0
✅ compiler-sfc: the empty lang attribute should be treated as no lang specified (#3051) (6d5b623)
✅ compiler-sfc: transformAssetUrls.base should not affect known module requests (2ea9867)
✅ compiler-sfc: treat const reactive() bindings as mutable (03360ce)
const obj = reactive({})
编译成let
变量。✅ compiler-ssr: avoid duplicated asset imports merged from component slot client branch (c69f4ea), closes vitejs/vite#2034
root.imports
Set 改成了 Array,允许重复了.✅ devtools: send instance to devtools when it's mounted instead of created (4fecb27)
✅ docs: change reference to passed deadline (#2930) (de7f9d1)
✅ hmr: deep clone reused hoisted trees during dev (5a7a1b8), closes vitejs/vite#2022
开发过程中,对静态提升的组件树进行深拷贝。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
packages/runtime-core/src/vnode.ts @@ -459,7 +459,7 @@ export function cloneVNode<T, U>( ): VNode<T, U> { // This is intentionally NOT using spread or extend to avoid the runtime // key enumeration cost. - const { props, ref, patchFlag } = vnode + const { props, ref, patchFlag, children } = vnode const mergedProps = extraProps ? mergeProps(props || {}, extraProps) : props return { __v_isVNode: true, @@ -479,7 +479,10 @@ export function cloneVNode<T, U>( : normalizeRef(extraProps) : ref, scopeId: vnode.scopeId, - children: vnode.children, + children: + __DEV__ && patchFlag === PatchFlags.HOISTED && isArray(children) + ? (children as VNode[]).map(deepCloneVNode) + : children, target: vnode.target, targetAnchor: vnode.targetAnchor, staticCount: vnode.staticCount, @@ -513,6 +516,18 @@ export function cloneVNode<T, U>( } }
deep clone 函数:
1 2 3 4 5 6 7 8 9 10 11
/** * Dev only, for HMR of hoisted vnodes reused in v-for * https://github.com/vitejs/vite/issues/2022 */ function deepCloneVNode(vnode: VNode): VNode { const cloned = cloneVNode(vnode) if (isArray(vnode.children)) { cloned.children = (vnode.children as VNode[]).map(deepCloneVNode) } return cloned }
✅ runtime-core: align $parent/$root with the template ref when using expose (#3158) (f43a3b0)
expose 特性详解:Vue3 功能拆解⑪ expose options&api
✅ runtime-core: allow overriding properties other than props (#3105) (73117f6)
允许重写非组件 props 的属性,比如:原生 API
hasOwnProperty
1 2 3 4 5 6 7 8 9 10
packages/runtime-core/src/componentPublicInstance.ts @@ -368,7 +368,7 @@ export const PublicInstanceProxyHandlers: ProxyHandler<any> = { setupState[key] = value } else if (data !== EMPTY_OBJ && hasOwn(data, key)) { data[key] = value - } else if (key in instance.props) { + } else if (hasOwn(instance.props, key)) { __DEV__ && warn( `Attempting to mutate prop "${key}". Props are readonly.`,
测试:
1 2 3 4 5 6 7 8 9 10
packages/runtime-core/__tests__/componentProps.spec.ts @@ -295,6 +295,10 @@ describe('component props', () => { ;(instance!.proxy as any).foo = 2 }).toThrow(TypeError) expect(`Attempting to mutate prop "foo"`).toHaveBeenWarned() // should not throw when overriding properties other than props + expect(() => { + ;(instance!.proxy as any).hasOwnProperty = () => {} + }).not.toThrow(TypeError) })
✅ runtime-core: check the DEV_ROOT_FRAGMENT flag correctly in the dev environment (#2750) (347a879)
1 2 3 4 5 6 7 8 9 10 11
// to have comments along side the root element which makes it a fragment let root = result let setRoot: ((root: VNode) => void) | undefined = undefined - if (__DEV__ && result.patchFlag & PatchFlags.DEV_ROOT_FRAGMENT) { + if ( + __DEV__ && + result.patchFlag > 0 && + result.patchFlag & PatchFlags.DEV_ROOT_FRAGMENT + ) { ;[root, setRoot] = getChildRoot(result) }
✅ runtime-core: component methods should override global properties in DEV (#3074) (2587f36)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
packages/runtime-core/src/componentOptions.ts @@ -604,7 +604,17 @@ export function applyOptions( for (const key in methods) { const methodHandler = (methods as MethodOptions)[key] if (isFunction(methodHandler)) { - ctx[key] = methodHandler.bind(publicThis) + // In dev mode, we use the `createRenderContext` function to define methods to the proxy target, + // and those are read-only but reconfigurable, so it needs to be redefined here + if (__DEV__) { + Object.defineProperty(ctx, key, { + value: methodHandler.bind(publicThis), + configurable: true, + enumerable: false + }) + } else { + ctx[key] = methodHandler.bind(publicThis) + } if (__DEV__) { checkDuplicateProperties!(OptionTypes.METHODS, key) }
测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
const url = process.env.VNEXT_PKG_RC +'/../runtime-test/dist/runtime-test.cjs.js' const value = require(url.replace('stb-', '')) const { nodeOps, render, h, serializeInner: s, createApp } = value const Comp = { methods: { foo() { return 'foo' } }, render() { return this.foo() } } const app = createApp(Comp) app.config.globalProperties.foo = () => 'bar' const root = nodeOps.createElement('div') app.mount(root) console.log(s(root)) return 0
foo 0
✅ runtime-core: ensure app instance can be garbage collected after unmount (close #2907) (#2909) (60e05ef)
1 2 3 4 5 6 7 8 9
packages/runtime-core/src/apiCreateApp.ts @@ -272,6 +272,7 @@ export function createAppAPI<HostElement>( if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) { devtoolsUnmountApp(app) } + delete app._container.__vue_app__ } else if (__DEV__) { warn(`Cannot unmount an app that is not mounted.`) }
取消引用。
1 2 3 4 5 6 7 8 9 10 11 12
function unmount() { if (isMounted) { render(null, app._container) if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) { app._instance = null devtoolsUnmountApp(app) } delete app._container.__vue_app__ } else if (__DEV__) { warn(`Cannot unmount an app that is not mounted.`) } }
mount 里面保存的
__vue_ap__
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
function mount( rootContainer: HostElement, isHydrate?: boolean, isSVG?: boolean ): any { if (!isMounted) { // ... vnode.appContext = context // HMR root reload ... if (isHydrate && hydrate) { hydrate(vnode as VNode<Node, Element>, rootContainer as any) } else { render(vnode, rootContainer, isSVG) } isMounted = true app._container = rootContainer // for devtools and telemetry ;(rootContainer as any).__vue_app__ = app if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) { app._instance = vnode.component devtoolsInitApp(app, version) } return vnode.component!.proxy } // ... }
✅ runtime-core: instanceWatch should pass this.proxy to source as the first argument (#2753) (ec8fd10)
当 watch 一个函数的时候,将 instance.proxy 做为第一个参数传给这个函数。
测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
const url = process.env.VNEXT_PKG_RC +'/../runtime-test/dist/runtime-test.cjs.js' const value = require(url.replace('stb-', '')) const { nodeOps, render, h, serializeInner: s, createApp } = value let instance = null const source = (proxy) => console.log(instance && ( proxy === instance.proxy )) const Comp = { created() { instance = this this.$watch(source, () => {}) }, render() {} } const root = nodeOps.createElement('div') createApp(Comp).mount(root) return 0
false 0
修复:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
packages/runtime-core/src/apiWatch.ts @@ -181,7 +181,9 @@ function doWatch( } else if (isReactive(s)) { return traverse(s) } else if (isFunction(s)) { - return callWithErrorHandling(s, instance, ErrorCodes.WATCH_GETTER) + return callWithErrorHandling(s, instance, ErrorCodes.WATCH_GETTER, [ + instance && (instance.proxy as any) + ]) } else { __DEV__ && warnInvalidSource(s) } @@ -190,7 +192,9 @@ function doWatch( if (cb) { // getter with cb getter = () => - callWithErrorHandling(source, instance, ErrorCodes.WATCH_GETTER) + callWithErrorHandling(source, instance, ErrorCodes.WATCH_GETTER, [ + instance && (instance.proxy as any) + ]) } else { // no cb -> simple effect getter = () => {
✅ types: extract the correct props type for the DateConstructor (#2676) (48f0d29)
✅ ensure all published packages contan a LICENCE file (close #2650) (#2857) (6a48d23)
✅ remove superfluous spaces when normalizing class (#3083) (4b55142)
问题如下代码,正常应该忽略
undefind
,false
:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
const url = process.env.VNEXT_PKG_RC +'/../runtime-test/dist/runtime-test.cjs.js' const value = require(url.replace('stb-', '')) const { nodeOps, render, h, serializeInner: s } = value const Comp = { props: { foo: BigInt }, render() { return h('div', { class: ['foo', undefined, false, 'bar'] }, [this.foo]) } } const root = nodeOps.createElement('div') render(h(Comp, { foo: BigInt(BigInt(100000111)) + BigInt(2000000000) * BigInt(30000000) }), root) console.log(s(root)) return 0
<div class="foo bar">60000000100000111</div> 0
修复:
1 2 3 4 5 6 7 8 9 10 11 12 13
packages/shared/src/normalizeProp.ts @@ -62,7 +62,10 @@ export function normalizeClass(value: unknown): string { res = value } else if (isArray(value)) { for (let i = 0; i < value.length; i++) { - res += normalizeClass(value[i]) + ' ' + const normalized = normalizeClass(value[i]) + if (normalized) { + res += normalized + ' ' + } } } else if (isObject(value)) { for (const name in value) {
✅ runtime-dom: enable set form attr to null on form-elements (#2840) (#2849) (f262438)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
packages/runtime-dom/src/patchProp.ts @@ -3,7 +3,13 @@ import { patchStyle } from './modules/style' - // #1787 form as an attribute must be a string, while it accepts an Element as - // a prop - if (key === 'form' && typeof value === 'string') { + // #1787, #2840 the form property is readonly and can only be set as an + // attribute using a string value + if (key === 'form' && isFormTag(el.tagName)) { return false } packages/shared/src/domTagConfig.ts @@ -30,6 +30,11 @@ const SVG_TAGS = const VOID_TAGS = 'area,base,br,col,embed,hr,img,input,link,meta,param,source,track,wbr' + const FORM_TAGS = + 'button,datalist,fieldset,input,keygen,label,legend,meter,optgroup,option,' + + 'output,progress,select,textarea' export const isHTMLTag = /*#__PURE__*/ makeMap(HTML_TAGS) export const isSVGTag = /*#__PURE__*/ makeMap(SVG_TAGS) export const isVoidTag = /*#__PURE__*/ makeMap(VOID_TAGS) export const isFormTag = /*#__PURE__*/ makeMap(FORM_TAGS, true)
✅ toRef: ref created from union typed prop can't be used in watch (#3048) (4ca4666)
✅ should prefix ShadowRoot with window. (#2943) (97d6f1a)
通过 window 去使用 ShadowRoot,因为它不是 window 上可枚举的属性。
1 2 3 4 5 6 7 8 9
packages/runtime-dom/src/index.ts @@ -119,7 +119,7 @@ function normalizeContainer( } if ( __DEV__ && - container instanceof ShadowRoot && + container instanceof window.ShadowRoot && container.mode === 'closed' ) {
DONE
Features [5/5]
CLOSED: [2021-08-05 Thu 23:42]
✅ remove useless option in KeepAlive (#3170) (bd1240c)
删除了 KeepAlive 的
inheritRef: true
选项。✅ compiler-core: support BigInt in template (#2900) (c9f94fa)
将
BigInt
标记为全局变量。1 2 3 4 5 6 7 8 9
packages/shared/src/globalsWhitelist.ts @@ -3,6 +3,6 @@ import { makeMap } from './makeMap' const GLOBALS_WHITE_LISTED = 'Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,' + 'decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,' + - 'Object,Boolean,String,RegExp,Map,Set,JSON,Intl' + 'Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt' export const isGloballyWhitelisted = /*#__PURE__*/ makeMap(GLOBALS_WHITE_LISTED)
测试结果:
✅ runtime-core: improve render context warning (#2496) (288ae0a)
问题: 组件渲染期间去访问一个不存在的属性时候,报错信息:
Property ${JSON.stringify(key)} was accessed during render but is not defined on instance.
1 2 3 4 5 6 7 8 9 10
packages/runtime-core/src/componentPublicInstance.ts @@ -349,7 +349,7 @@ export const PublicInstanceProxyHandlers: ProxyHandler<any> = { )} must be accessed via $data because it starts with a reserved ` + `character ("$" or "_") and is not proxied on the render context.` ) - } else { + } else if (instance === currentRenderingInstance) { warn( `Property ${JSON.stringify(key)} was accessed during render ` + `but is not defined on instance.`
✅ runtime-core: props type support BigInt (#2891) (ffd5288)
修改代码:
1 2 3 4
const isSimpleType = /*#__PURE__*/ makeMap( - 'String,Number,Boolean,Function,Symbol' + 'String,Number,Boolean,Function,Symbol,BigInt' )
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
const url = process.env.VNEXT_PKG_RC +'/../runtime-test/dist/runtime-test.cjs.js' const value = require(url.replace('stb-', '')) const { nodeOps, render, h, serializeInner: s } = value const Comp = { props: { foo: BigInt }, render() { return h('div', [this.foo]) } } const root = nodeOps.createElement('div') render(h(Comp, { foo: BigInt(BigInt(100000111)) + BigInt(2000000000) * BigInt(30000000) }), root) console.log(s(root)) return 0
<div>60000000100000111</div> 0
DONE
Performance Improvements [1/1]
CLOSED: [2021-08-05 Thu 23:42]
✅ reactivity: should not track __isVue (#2940) (dd02cf3)
@@ -93,7 +96,7 @@ function createGetter(isReadonly = false, shallow = false) {
1 2 3 4 5 6 7 8 9 10 11 12
+ const isNonTrackableKeys = /*#__PURE__*/ makeMap(`__proto__,__v_isRef,__isVue`) if ( isSymbol(key) ? builtInSymbols.has(key as symbol) - : key === `__proto__` || key === `__v_isRef` + : isNonTrackableKeys(key) ) { return res } // 遇到 __isVue 也直接返回 Reflect.get 的结果,不往下 track 了。
3.0.5 (2020-12-30)
vue-next/CHANGELOG.md at master · vuejs/vue-next
TIP
Note: this release contains a type-only change that requires TypeScript 4.0+, which may cause build issues in projects still using TS 3.x.
只包含一些类型的变更。
DONE
Bug Fixes [9/9]
CLOSED: [2021-08-05 Thu 23:44]
✅ compiler-core: fix missing createVNode import on nested v-for (ad4d391), closes #2718
✅ compiler-sfc: should keep template nodes with no content (#2468) (5b9b37f), closes #2463
1 2 3 4 5 6 7 8 9 10
-> packages/compiler-sfc/src/parse.ts if (node.type !== NodeTypes.ELEMENT) { return } - if (!node.children.length && !hasSrc(node)) { + if (!node.children.length && !hasSrc(node) && node.tag !== 'template') { return } switch (node.tag) {
✅ compiler-sfc: support transforming asset urls with full base url. (#2477) (db786b1)
针对相对路径而言,当提供了 base 选项的时候,会使用这个值去拼接,如:
{ transformAssetUrls: { base: 'https://www.cheng92.com' } }
<img src="./vue/img/test.png" />
会被编译成:createVNode('img', { src: 'https://www.cheng92.com/vue/img/test.png' })
✅ runtime-core: component mount anchor memory leak (#2459) (3867bb4), closes #2458
✅ runtime-core: skip patchBlockChildren if n1.dynamicChildren is null (#2717) (c59897c), closes #2715 #2485
这个问题原因是,一开始 HelloWorld 的 dynamicChildren 是 null。
当点击 ADD 按钮的时候增加了一项数据,会进入 mountChildren -> patchBlockChildren
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
const patchBlockChildren: PatchBlockChildrenFn = ( oldChildren, newChildren, fallbackContainer, parentComponent, parentSuspense, isSVG, slotScopeIds ) => { for (let i = 0; i < newChildren.length; i++) { const oldVNode = oldChildren[i] // dynamicChildren const newVNode = newChildren[i] // ... } }
而
dynamicChildren
在初始化的时候是个null
值, 一开始就访问了dynamicChildren[i]
所以导致报错。修复代码(c59897c),加个判断条件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
if ( patchFlag > 0 && patchFlag & PatchFlags.STABLE_FRAGMENT && - dynamicChildren && + dynamicChildren && + n1.dynamicChildren ) { // a stable fragment (template root or <template v-for>) doesn't need to // patch children order, but it may contain dynamicChildren. patchBlockChildren( - n1.dynamicChildren!, + n1.dynamicChildren, dynamicChildren, container, parentComponent, parentSuspense, isSVG, slotScopeIds )
❌
runtime-dom: support mounting app on ShadowRoot(#2447) (b2189ba), closes #2399>3.2 中已经没有
__isShadowRoot
相关的代码了。✅ ssr: properly handle ssr empty slot and fallback (88f6b33)
✅ transition: ensure manual style manipulation in transition leave hooks work (cbaa380), closes #2720
在 onLeave hook 中增加
1 2
forceReflow() addTransitionClass(el, leaveActiveClass)
去强制渲染,触发
leaveActiveClass
。✅ transition: ensure styles from *-leave-active trigger transition (#2716) (3f8f9b6), closes #2712
DONE
Features [1/1]
CLOSED: [2021-08-05 Thu 23:44]
✅ devtools: send instance (3626ff0)
将组件实例给开发工具。
1 2 3 4 5 6 7 8 9 10 11 12 13
function createDevtoolsComponentHook(hook: DevtoolsHooks) { return (component: ComponentInternalInstance) => { if (!devtools) return devtools.emit( hook, component.appContext.app, component.uid, - component.parent ? component.parent.uid : undefined + component.parent ? component.parent.uid : undefined, + component ) } }
v-show 也是通过 el.style.display 来实现的,这里意思是如果 style 属性中也有 display 的话,在 runtime-dom/src/modules/style.ts 中 patch 的时候应该 v-show 的优先级更高。