How to use cloneIfMounted method in Playwright Internal

Best JavaScript code snippet using playwright-internal

Run Playwright Internal automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

_v3_patch.js

Source: _v3_patch.js Github

copy
1const patchKeyedChildren = (c1, c2, container, parentAnchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized) => {
2    let i = 0;
3    const l2 = c2.length;
4    let e1 = c1.length - 1; // prev ending index
5    let e2 = l2 - 1; // next ending index
6
7    // [Mars] : 1. Compare the head and the tail first.
8
9    // 1. sync from start
10    // (a b) c
11    // (a b) d e
12    while (i <= e1 && i <= e2) {
13        const n1 = c1[i];
14        const n2 = (c2[i] = optimized ?
15            cloneIfMounted(c2[i]) :
16            normalizeVNode(c2[i]));
17        if (isSameVNodeType(n1, n2)) { // type and key are the same.
18            patch(n1, n2, container, null, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized);
19        } else {
20            break;
21        }
22        i++;
23    }
24
25    // 2. sync from end
26    // a (b c)
27    // d e (b c)
28    while (i <= e1 && i <= e2) {
29        const n1 = c1[e1];
30        const n2 = (c2[e2] = optimized ?
31            cloneIfMounted(c2[e2]) :
32            normalizeVNode(c2[e2]));
33        if (isSameVNodeType(n1, n2)) { // type and key are the same.
34            patch(n1, n2, container, null, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized);
35        } else {
36            break;
37        }
38        e1--;
39        e2--;
40    }
41
42    // [Mars] : 2. Compare the head and the tail first.
43
44    // 3. common sequence + mount
45    // (a b)
46    // (a b) c
47    // i = 2, e1 = 1, e2 = 2
48    // (a b)
49    // c (a b)
50    // i = 0, e1 = -1, e2 = 0
51    if (i > e1) {
52        if (i <= e2) {
53            const nextPos = e2 + 1;
54            const anchor = nextPos < l2 ? c2[nextPos].el : parentAnchor;
55            while (i <= e2) {
56                // mount new added vnodes not contained in oldChilds.
57                patch(null, (c2[i] = optimized ?
58                    cloneIfMounted(c2[i]) :
59                    normalizeVNode(c2[i])), container, anchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized);
60                i++;
61            }
62        }
63    }
64
65    // 4. common sequence + unmount
66    // (a b) c
67    // (a b)
68    // i = 2, e1 = 2, e2 = 1
69    // a (b c)
70    // (b c)
71    // i = 0, e1 = 0, e2 = -1
72    else if (i > e2) {
73        while (i <= e1) {
74            unmount(c1[i], parentComponent, parentSuspense, true);
75            i++;
76        }
77    }
78
79    // 5. unknown sequence
80    // [i ... e1 + 1]: a b [c d e] f g
81    // [i ... e2 + 1]: a b [e d c h] f g
82    // i = 2, e1 = 4, e2 = 5
83    else {
84        const s1 = i; // prev starting index
85        const s2 = i; // next starting index
86
87        // 5.1 build key:index map for newChildren
88        const keyToNewIndexMap = new Map(); // use hashMap, cause it's easy to search an index of a key.
89        for (i = s2; i <= e2; i++) {
90            const nextChild = (c2[i] = optimized ?
91                cloneIfMounted(c2[i]) :
92                normalizeVNode(c2[i]));
93            if (nextChild.key != null) {
94                if (keyToNewIndexMap.has(nextChild.key)) {
95                    warn$1(`Duplicate keys found during update:`, JSON.stringify(nextChild.key), `Make sure keys are unique.`);
96                }
97                keyToNewIndexMap.set(nextChild.key, i);
98            }
99        }
100
101        // 5.2 loop through old children left to be patched and try to patch
102        // matching nodes & remove nodes that are no longer present
103        let j;
104        let patched = 0;
105        const toBePatched = e2 - s2 + 1;
106        let moved = false;
107        // used to track whether any node has moved
108        let maxNewIndexSoFar = 0;
109        // works as Map<newIndex, oldIndex>
110        // Note that oldIndex is offset by +1
111        // and oldIndex = 0 is a special value indicating the new node has
112        // no corresponding old node.
113        // used for determining longest stable subsequence
114        const newIndexToOldIndexMap = new Array(toBePatched);
115        for (i = 0; i < toBePatched; i++)
116            newIndexToOldIndexMap[i] = 0;
117        for (i = s1; i <= e1; i++) {
118            const prevChild = c1[i];
119            if (patched >= toBePatched) {
120                // all new children have been patched so this can only be a removal
121                unmount(prevChild, parentComponent, parentSuspense, true);
122                continue;
123            }
124            let newIndex;
125            if (prevChild.key != null) {
126                newIndex = keyToNewIndexMap.get(prevChild.key);
127            } else {
128                // key-less node, try to locate a key-less node of the same type
129                for (j = s2; j <= e2; j++) {
130                    if (newIndexToOldIndexMap[j - s2] === 0 &&
131                        isSameVNodeType(prevChild, c2[j])) { // type and key are the same.
132                        newIndex = j;
133                        break;
134                    }
135                }
136            }
137            if (newIndex === undefined) {
138                unmount(prevChild, parentComponent, parentSuspense, true);
139            } else {
140                newIndexToOldIndexMap[newIndex - s2] = i + 1; // n:[h,c,d,e]  o:[c,d,e,h]  ->  newIndexToOldIndexMap: [4,1,2,3]
141             z   if (newIndex >= maxNewIndexSoFar) {
142                    maxNewIndexSoFar = newIndex;
143                } else {
144                    moved = true;
145                }
146                patch(prevChild, c2[newIndex], container, null, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized);
147                patched++;
148            }
149        }
150
151        // 5.3 move and mount
152        // generate longest stable subsequence only when nodes have moved
153        const increasingNewIndexSequence = moved ?
154            getSequence(newIndexToOldIndexMap) :
155            EMPTY_ARR;
156        j = increasingNewIndexSequence.length - 1;
157        // looping backwards so that we can use last patched node as anchor !!!!!!★★★
158        for (i = toBePatched - 1; i >= 0; i--) {
159            const nextIndex = s2 + i;
160            const nextChild = c2[nextIndex];
161            const anchor = nextIndex + 1 < l2 ? c2[nextIndex + 1].el : parentAnchor;
162            if (newIndexToOldIndexMap[i] === 0) {
163                // mount new
164                patch(null, nextChild, container, anchor, parentComponent, parentSuspense, isSVG, slotScopeIds, optimized);
165            } else if (moved) {
166                // move if:
167                // There is no stable subsequence (e.g. a reverse)
168                // OR current node is not among the stable sequence
169                if (j < 0 || i !== increasingNewIndexSequence[j]) {
170                    move(nextChild, container, anchor, 2 /* REORDER */ );
171                } else {
172                    // position is matched, no movement.
173                    j--;
174                }
175            }
176        }
177    }
178};
Full Screen

createApp.js

Source: createApp.js Github

copy
1
2
3
4
5let uid$1 = 0;
6function createAppContext() {
7    return {
8        app: null,
9        config: {
10            isNativeTag: NO,
11            performance: false,
12            globalProperties: {},
13            optionMergeStrategies: {},
14            isCustomElement: NO,
15            errorHandler: undefined,
16            warnHandler: undefined
17        },
18        mixins: [],
19        components: {},
20        directives: {},
21        provides: Object.create(null)
22    };
23}
24
25
26 // TODO:  入口
27const createApp = ((...args) => {
28    const app = ensureRenderer().createApp(...args);
29    {
30        injectNativeTagCheck(app);
31    }
32    const { mount } = app;
33    app.mount = (containerOrSelector) => { // 改写了原来的mount
34        const container = normalizeContainer(containerOrSelector);
35        if (!container)
36            return;
37        const component = app._component;
38        if (!isFunction(component) && !component.render && !component.template) {
39            component.template = container.innerHTML;
40        }
41        // clear content before mounting
42        container.innerHTML = '';
43        const proxy = mount(container);
44        container.removeAttribute('v-cloak');
45        container.setAttribute('data-v-app', '');
46        return proxy;
47    };
48    return app;
49});
50    function normalizeContainer(container) {
51        if (isString(container)) {
52            const res = document.querySelector(container);
53            if ( !res) {
54                warn(`Failed to mount app: mount target selector returned null.`);
55            }
56            return res;
57        }
58        return container;
59    }
60/**
61 * createRenderer(options) => baseCreateRenderer(options)
62 *      baseCreateRenderer(...) => {render, hydrate, createApp: createAppAPI(render, hydrate)}
63 * 
64 */
65
66function createAppAPI(render, hydrate) {
67    return function createApp(rootComponent, rootProps = null) {
68        if (rootProps != null && !isObject(rootProps)) {
69             warn(`root props passed to app.mount() must be an object.`);
70            rootProps = null;
71        }
72        const context = createAppContext();
73        const installedPlugins = new Set();
74        let isMounted = false;
75        const app = (context.app = {
76            _uid: uid$1++,
77            _component: rootComponent,
78            _props: rootProps,
79            _container: null,
80            _context: context,
81            version,
82            get config() {
83                return context.config;
84            },
85            set config(v) {
86                {
87                    warn(`app.config cannot be replaced. Modify individual options instead.`);
88                }
89            },
90            use(plugin, ...options) {
91                if (installedPlugins.has(plugin)) {
92                     warn(`Plugin has already been applied to target app.`);
93                }
94                else if (plugin && isFunction(plugin.install)) {
95                    installedPlugins.add(plugin);
96                    plugin.install(app, ...options);
97                }
98                else if (isFunction(plugin)) {
99                    installedPlugins.add(plugin);
100                    plugin(app, ...options);
101                }
102                else {
103                    warn(`A plugin must either be a function or an object with an "install" ` +
104                        `function.`);
105                }
106                return app;
107            },
108            mixin(mixin) {
109                {
110                    if (!context.mixins.includes(mixin)) {
111                        context.mixins.push(mixin);
112                    }
113                    else {
114                        warn('Mixin has already been applied to target app' +
115                            (mixin.name ? `: ${mixin.name}` : ''));
116                    }
117                }
118                return app;
119            },
120            component(name, component) {
121                {
122                    validateComponentName(name, context.config);
123                }
124                if (!component) {
125                    return context.components[name];
126                }
127                if ( context.components[name]) {
128                    warn(`Component "${name}" has already been registered in target app.`);
129                }
130                context.components[name] = component;
131                return app;
132            },
133            directive(name, directive) {
134                {
135                    validateDirectiveName(name);
136                }
137                if (!directive) {
138                    return context.directives[name];
139                }
140                if ( context.directives[name]) {
141                    warn(`Directive "${name}" has already been registered in target app.`);
142                }
143                context.directives[name] = directive;
144                return app;
145            },
146            mount(rootContainer, isHydrate) {
147                if (!isMounted) {
148                    const vnode = createVNode(rootComponent, rootProps);
149                    // store app context on the root VNode.
150                    // this will be set on the root instance on initial mount.
151                    vnode.appContext = context;
152                    // HMR root reload
153                    {
154                        context.reload = () => {
155                            render(cloneVNode(vnode), rootContainer);
156                        };
157                    }
158                    if (isHydrate && hydrate) {
159                        hydrate(vnode, rootContainer);
160                    }
161                    else {
162                        render(vnode, rootContainer);
163                    }
164                    isMounted = true;
165                    app._container = rootContainer;
166                    rootContainer.__vue_app__ = app;
167                    {
168                        devtoolsInitApp(app, version);
169                    }
170                    return vnode.component.proxy;
171                }
172                else {
173                    warn(`App has already been mounted.\n` +
174                        `If you want to remount the same app, move your app creation logic ` +
175                        `into a factory function and create fresh app instances for each ` +
176                        `mount - e.g. \`const createMyApp = () => createApp(App)\``);
177                }
178            },
179            unmount() {
180                if (isMounted) {
181                    render(null, app._container);
182                    {
183                        devtoolsUnmountApp(app);
184                    }
185                }
186                else {
187                    warn(`Cannot unmount an app that is not mounted.`);
188                }
189            },
190            provide(key, value) {
191                if ( key in context.provides) {
192                    warn(`App already provides property with key "${String(key)}". ` +
193                        `It will be overwritten with the new value.`);
194                }
195                // TypeScript doesn't allow symbols as index type
196                // https://github.com/Microsoft/TypeScript/issues/24587
197                context.provides[key] = value;
198                return app;
199            }
200        });
201        return app;
202    };
203}
204
205
206
207
208// implementation
209function baseCreateRenderer(options, createHydrationFns) {
210    const { insert: hostInsert, remove: hostRemove, patchProp: hostPatchProp, forcePatchProp: hostForcePatchProp, createElement: hostCreateElement, createText: hostCreateText, createComment: hostCreateComment, setText: hostSetText, setElementText: hostSetElementText, parentNode: hostParentNode, nextSibling: hostNextSibling, setScopeId: hostSetScopeId = NOOP, cloneNode: hostCloneNode, insertStaticContent: hostInsertStaticContent } = options;
211    // Note: functions inside this closure should use `const xxx = () => {}`
212    // style in order to prevent being inlined by minifiers.
213    const patch = (n1, n2, container, anchor = null, parentComponent = null, parentSuspense = null, isSVG = false, optimized = false) => {
214        // patching & not same type, unmount old tree
215        if (n1 && !isSameVNodeType(n1, n2)) {
216            anchor = getNextHostNode(n1);
217            unmount(n1, parentComponent, parentSuspense, true);
218            n1 = null;
219        }
220        if (n2.patchFlag === -2 /* BAIL */) {
221            optimized = false;
222            n2.dynamicChildren = null;
223        }
224        const { type, ref, shapeFlag } = n2;
225        switch (type) {
226            case Text:
227                processText(n1, n2, container, anchor);
228                break;
229            case Comment:
230                processCommentNode(n1, n2, container, anchor);
231                break;
232            case Static:
233                if (n1 == null) {
234                    mountStaticNode(n2, container, anchor, isSVG);
235                }
236                else {
237                    patchStaticNode(n1, n2, container, isSVG);
238                }
239                break;
240            case Fragment:
241                processFragment(n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized);
242                break;
243            default:
244                if (shapeFlag & 1 /* ELEMENT */) {
245                    processElement(n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized);
246                }
247                else if (shapeFlag & 6 /* COMPONENT */) {
248                    processComponent(n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized);
249                }
250                else if (shapeFlag & 64 /* TELEPORT */) {
251                    type.process(n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized, internals);
252                }
253                else if ( shapeFlag & 128 /* SUSPENSE */) {
254                    type.process(n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized, internals);
255                }
256                else {
257                    warn('Invalid VNode type:', type, `(${typeof type})`);
258                }
259        }
260        // set ref
261        if (ref != null && parentComponent) {
262            setRef(ref, n1 && n1.ref, parentComponent, parentSuspense, n2);
263        }
264    };
265    const processText = (n1, n2, container, anchor) => {
266        if (n1 == null) {
267            hostInsert((n2.el = hostCreateText(n2.children)), container, anchor);
268        }
269        else {
270            const el = (n2.el = n1.el);
271            if (n2.children !== n1.children) {
272                hostSetText(el, n2.children);
273            }
274        }
275    };
276    const processCommentNode = (n1, n2, container, anchor) => {
277        if (n1 == null) {
278            hostInsert((n2.el = hostCreateComment(n2.children || '')), container, anchor);
279        }
280        else {
281            // there's no support for dynamic comments
282            n2.el = n1.el;
283        }
284    };
285    const mountStaticNode = (n2, container, anchor, isSVG) => {
286        [n2.el, n2.anchor] = hostInsertStaticContent(n2.children, container, anchor, isSVG);
287    };
288    /**
289     * Dev / HMR only
290     */
291    const patchStaticNode = (n1, n2, container, isSVG) => {
292        // static nodes are only patched during dev for HMR
293        if (n2.children !== n1.children) {
294            const anchor = hostNextSibling(n1.anchor);
295            // remove existing
296            removeStaticNode(n1);
297            [n2.el, n2.anchor] = hostInsertStaticContent(n2.children, container, anchor, isSVG);
298        }
299        else {
300            n2.el = n1.el;
301            n2.anchor = n1.anchor;
302        }
303    };
304    /**
305     * Dev / HMR only
306     */
307    const moveStaticNode = (vnode, container, anchor) => {
308        let cur = vnode.el;
309        const end = vnode.anchor;
310        while (cur && cur !== end) {
311            const next = hostNextSibling(cur);
312            hostInsert(cur, container, anchor);
313            cur = next;
314        }
315        hostInsert(end, container, anchor);
316    };
317    /**
318     * Dev / HMR only
319     */
320    const removeStaticNode = (vnode) => {
321        let cur = vnode.el;
322        while (cur && cur !== vnode.anchor) {
323            const next = hostNextSibling(cur);
324            hostRemove(cur);
325            cur = next;
326        }
327        hostRemove(vnode.anchor);
328    };
329    const processElement = (n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized) => {
330        isSVG = isSVG || n2.type === 'svg';
331        if (n1 == null) {
332            mountElement(n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized);
333        }
334        else {
335            patchElement(n1, n2, parentComponent, parentSuspense, isSVG, optimized);
336        }
337    };
338    const mountElement = (vnode, container, anchor, parentComponent, parentSuspense, isSVG, optimized) => {
339        let el;
340        let vnodeHook;
341        const { type, props, shapeFlag, transition, scopeId, patchFlag, dirs } = vnode;
342        {
343            el = vnode.el = hostCreateElement(vnode.type, isSVG, props && props.is);
344            // mount children first, since some props may rely on child content
345            // being already rendered, e.g. `<select value>`
346            if (shapeFlag & 8 /* TEXT_CHILDREN */) {
347                hostSetElementText(el, vnode.children);
348            }
349            else if (shapeFlag & 16 /* ARRAY_CHILDREN */) {
350                mountChildren(vnode.children, el, null, parentComponent, parentSuspense, isSVG && type !== 'foreignObject', optimized || !!vnode.dynamicChildren);
351            }
352            if (dirs) {
353                invokeDirectiveHook(vnode, null, parentComponent, 'created');
354            }
355            // props
356            if (props) {
357                for (const key in props) {
358                    if (!isReservedProp(key)) {
359                        hostPatchProp(el, key, null, props[key], isSVG, vnode.children, parentComponent, parentSuspense, unmountChildren);
360                    }
361                }
362                if ((vnodeHook = props.onVnodeBeforeMount)) {
363                    invokeVNodeHook(vnodeHook, parentComponent, vnode);
364                }
365            }
366            // scopeId
367            setScopeId(el, scopeId, vnode, parentComponent);
368        }
369        {
370            Object.defineProperty(el, '__vnode', {
371                value: vnode,
372                enumerable: false
373            });
374            Object.defineProperty(el, '__vueParentComponent', {
375                value: parentComponent,
376                enumerable: false
377            });
378        }
379        if (dirs) {
380            invokeDirectiveHook(vnode, null, parentComponent, 'beforeMount');
381        }
382        // #1583 For inside suspense + suspense not resolved case, enter hook should call when suspense resolved
383        // #1689 For inside suspense + suspense resolved case, just call it
384        const needCallTransitionHooks = (!parentSuspense || (parentSuspense && !parentSuspense.pendingBranch)) &&
385            transition &&
386            !transition.persisted;
387        if (needCallTransitionHooks) {
388            transition.beforeEnter(el);
389        }
390        hostInsert(el, container, anchor);
391        if ((vnodeHook = props && props.onVnodeMounted) ||
392            needCallTransitionHooks ||
393            dirs) {
394            queuePostRenderEffect(() => {
395                vnodeHook && invokeVNodeHook(vnodeHook, parentComponent, vnode);
396                needCallTransitionHooks && transition.enter(el);
397                dirs && invokeDirectiveHook(vnode, null, parentComponent, 'mounted');
398            }, parentSuspense);
399        }
400    };
401    const setScopeId = (el, scopeId, vnode, parentComponent) => {
402        if (scopeId) {
403            hostSetScopeId(el, scopeId);
404        }
405        if (parentComponent) {
406            const treeOwnerId = parentComponent.type.__scopeId;
407            // vnode's own scopeId and the current patched component's scopeId is
408            // different - this is a slot content node.
409            if (treeOwnerId && treeOwnerId !== scopeId) {
410                hostSetScopeId(el, treeOwnerId + '-s');
411            }
412            let subTree = parentComponent.subTree;
413            if ( subTree.type === Fragment) {
414                subTree =
415                    filterSingleRoot(subTree.children) || subTree;
416            }
417            if (vnode === subTree) {
418                setScopeId(el, parentComponent.vnode.scopeId, parentComponent.vnode, parentComponent.parent);
419            }
420        }
421    };
422    const mountChildren = (children, container, anchor, parentComponent, parentSuspense, isSVG, optimized, start = 0) => {
423        for (let i = start; i < children.length; i++) {
424            const child = (children[i] = optimized
425                ? cloneIfMounted(children[i])
426                : normalizeVNode(children[i]));
427            patch(null, child, container, anchor, parentComponent, parentSuspense, isSVG, optimized);
428        }
429    };
430    const patchElement = (n1, n2, parentComponent, parentSuspense, isSVG, optimized) => {
431        const el = (n2.el = n1.el);
432        let { patchFlag, dynamicChildren, dirs } = n2;
433        // #1426 take the old vnode's patch flag into account since user may clone a
434        // compiler-generated vnode, which de-opts to FULL_PROPS
435        patchFlag |= n1.patchFlag & 16 /* FULL_PROPS */;
436        const oldProps = n1.props || EMPTY_OBJ;
437        const newProps = n2.props || EMPTY_OBJ;
438        let vnodeHook;
439        if ((vnodeHook = newProps.onVnodeBeforeUpdate)) {
440            invokeVNodeHook(vnodeHook, parentComponent, n2, n1);
441        }
442        if (dirs) {
443            invokeDirectiveHook(n2, n1, parentComponent, 'beforeUpdate');
444        }
445        if ( isHmrUpdating) {
446            // HMR updated, force full diff
447            patchFlag = 0;
448            optimized = false;
449            dynamicChildren = null;
450        }
451        if (patchFlag > 0) {
452            // the presence of a patchFlag means this element's render code was
453            // generated by the compiler and can take the fast path.
454            // in this path old node and new node are guaranteed to have the same shape
455            // (i.e. at the exact same position in the source template)
456            if (patchFlag & 16 /* FULL_PROPS */) {
457                // element props contain dynamic keys, full diff needed
458                patchProps(el, n2, oldProps, newProps, parentComponent, parentSuspense, isSVG);
459            }
460            else {
461                // class
462                // this flag is matched when the element has dynamic class bindings.
463                if (patchFlag & 2 /* CLASS */) {
464                    if (oldProps.class !== newProps.class) {
465                        hostPatchProp(el, 'class', null, newProps.class, isSVG);
466                    }
467                }
468                // style
469                // this flag is matched when the element has dynamic style bindings
470                if (patchFlag & 4 /* STYLE */) {
471                    hostPatchProp(el, 'style', oldProps.style, newProps.style, isSVG);
472                }
473                // props
474                // This flag is matched when the element has dynamic prop/attr bindings
475                // other than class and style. The keys of dynamic prop/attrs are saved for
476                // faster iteration.
477                // Note dynamic keys like :[foo]="bar" will cause this optimization to
478                // bail out and go through a full diff because we need to unset the old key
479                if (patchFlag & 8 /* PROPS */) {
480                    // if the flag is present then dynamicProps must be non-null
481                    const propsToUpdate = n2.dynamicProps;
482                    for (let i = 0; i < propsToUpdate.length; i++) {
483                        const key = propsToUpdate[i];
484                        const prev = oldProps[key];
485                        const next = newProps[key];
486                        if (next !== prev ||
487                            (hostForcePatchProp && hostForcePatchProp(el, key))) {
488                            hostPatchProp(el, key, prev, next, isSVG, n1.children, parentComponent, parentSuspense, unmountChildren);
489                        }
490                    }
491                }
492            }
493            // text
494            // This flag is matched when the element has only dynamic text children.
495            if (patchFlag & 1 /* TEXT */) {
496                if (n1.children !== n2.children) {
497                    hostSetElementText(el, n2.children);
498                }
499            }
500        }
501        else if (!optimized && dynamicChildren == null) {
502            // unoptimized, full diff
503            patchProps(el, n2, oldProps, newProps, parentComponent, parentSuspense, isSVG);
504        }
505        const areChildrenSVG = isSVG && n2.type !== 'foreignObject';
506        if (dynamicChildren) {
507            patchBlockChildren(n1.dynamicChildren, dynamicChildren, el, parentComponent, parentSuspense, areChildrenSVG);
508            if ( parentComponent && parentComponent.type.__hmrId) {
509                traverseStaticChildren(n1, n2);
510            }
511        }
512        else if (!optimized) {
513            // full diff
514            patchChildren(n1, n2, el, null, parentComponent, parentSuspense, areChildrenSVG);
515        }
516        if ((vnodeHook = newProps.onVnodeUpdated) || dirs) {
517            queuePostRenderEffect(() => {
518                vnodeHook && invokeVNodeHook(vnodeHook, parentComponent, n2, n1);
519                dirs && invokeDirectiveHook(n2, n1, parentComponent, 'updated');
520            }, parentSuspense);
521        }
522    };
523    // The fast path for blocks.
524    const patchBlockChildren = (oldChildren, newChildren, fallbackContainer, parentComponent, parentSuspense, isSVG) => {
525        for (let i = 0; i < newChildren.length; i++) {
526            const oldVNode = oldChildren[i];
527            const newVNode = newChildren[i];
528            // Determine the container (parent element) for the patch.
529            const container = 
530            // - In the case of a Fragment, we need to provide the actual parent
531            // of the Fragment itself so it can move its children.
532            oldVNode.type === Fragment ||
533                // - In the case of different nodes, there is going to be a replacement
534                // which also requires the correct parent container
535                !isSameVNodeType(oldVNode, newVNode) ||
536                // - In the case of a component, it could contain anything.
537                oldVNode.shapeFlag & 6 /* COMPONENT */ ||
538                oldVNode.shapeFlag & 64 /* TELEPORT */
539                ? hostParentNode(oldVNode.el)
540                : // In other cases, the parent container is not actually used so we
541                    // just pass the block element here to avoid a DOM parentNode call.
542                    fallbackContainer;
543            patch(oldVNode, newVNode, container, null, parentComponent, parentSuspense, isSVG, true);
544        }
545    };
546    const patchProps = (el, vnode, oldProps, newProps, parentComponent, parentSuspense, isSVG) => {
547        if (oldProps !== newProps) {
548            for (const key in newProps) {
549                if (isReservedProp(key))
550                    continue;
551                const next = newProps[key];
552                const prev = oldProps[key];
553                if (next !== prev ||
554                    (hostForcePatchProp && hostForcePatchProp(el, key))) {
555                    hostPatchProp(el, key, prev, next, isSVG, vnode.children, parentComponent, parentSuspense, unmountChildren);
556                }
557            }
558            if (oldProps !== EMPTY_OBJ) {
559                for (const key in oldProps) {
560                    if (!isReservedProp(key) && !(key in newProps)) {
561                        hostPatchProp(el, key, oldProps[key], null, isSVG, vnode.children, parentComponent, parentSuspense, unmountChildren);
562                    }
563                }
564            }
565        }
566    };
567    const processFragment = (n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized) => {
568        const fragmentStartAnchor = (n2.el = n1 ? n1.el : hostCreateText(''));
569        const fragmentEndAnchor = (n2.anchor = n1 ? n1.anchor : hostCreateText(''));
570        let { patchFlag, dynamicChildren } = n2;
571        if (patchFlag > 0) {
572            optimized = true;
573        }
574        if ( isHmrUpdating) {
575            // HMR updated, force full diff
576            patchFlag = 0;
577            optimized = false;
578            dynamicChildren = null;
579        }
580        if (n1 == null) {
581            hostInsert(fragmentStartAnchor, container, anchor);
582            hostInsert(fragmentEndAnchor, container, anchor);
583            // a fragment can only have array children
584            // since they are either generated by the compiler, or implicitly created
585            // from arrays.
586            mountChildren(n2.children, container, fragmentEndAnchor, parentComponent, parentSuspense, isSVG, optimized);
587        }
588        else {
589            if (patchFlag > 0 &&
590                patchFlag & 64 /* STABLE_FRAGMENT */ &&
591                dynamicChildren) {
592                // a stable fragment (template root or <template v-for>) doesn't need to
593                // patch children order, but it may contain dynamicChildren.
594                patchBlockChildren(n1.dynamicChildren, dynamicChildren, container, parentComponent, parentSuspense, isSVG);
595                if ( parentComponent && parentComponent.type.__hmrId) {
596                    traverseStaticChildren(n1, n2);
597                }
598                else if (
599                // #2080 if the stable fragment has a key, it's a <template v-for> that may
600                //  get moved around. Make sure all root level vnodes inherit el.
601                // #2134 or if it's a component root, it may also get moved around
602                // as the component is being moved.
603                n2.key != null ||
604                    (parentComponent && n2 === parentComponent.subTree)) {
605                    traverseStaticChildren(n1, n2, true /* shallow */);
606                }
607            }
608            else {
609                // keyed / unkeyed, or manual fragments.
610                // for keyed & unkeyed, since they are compiler generated from v-for,
611                // each child is guaranteed to be a block so the fragment will never
612                // have dynamicChildren.
613                patchChildren(n1, n2, container, fragmentEndAnchor, parentComponent, parentSuspense, isSVG, optimized);
614            }
615        }
616    };
617    const processComponent = (n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized) => {
618        if (n1 == null) {
619            if (n2.shapeFlag & 512 /* COMPONENT_KEPT_ALIVE */) {
620                parentComponent.ctx.activate(n2, container, anchor, isSVG, optimized);
621            }
622            else {
623                mountComponent(n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized);
624            }
625        }
626        else {
627            updateComponent(n1, n2, optimized);
628        }
629    };
630    const mountComponent = (initialVNode, container, anchor, parentComponent, parentSuspense, isSVG, optimized) => {
631        const instance = (initialVNode.component = createComponentInstance(initialVNode, parentComponent, parentSuspense));
632        if ( instance.type.__hmrId) {
633            registerHMR(instance);
634        }
635        {
636            pushWarningContext(initialVNode);
637            startMeasure(instance, `mount`);
638        }
639        // inject renderer internals for keepAlive
640        if (isKeepAlive(initialVNode)) {
641            instance.ctx.renderer = internals;
642        }
643        // resolve props and slots for setup context
644        {
645            startMeasure(instance, `init`);
646        }
647        setupComponent(instance);
648        {
649            endMeasure(instance, `init`);
650        }
651        // setup() is async. This component relies on async logic to be resolved
652        // before proceeding
653        if ( instance.asyncDep) {
654            parentSuspense && parentSuspense.registerDep(instance, setupRenderEffect);
655            // Give it a placeholder if this is not hydration
656            // TODO handle self-defined fallback
657            if (!initialVNode.el) {
658                const placeholder = (instance.subTree = createVNode(Comment));
659                processCommentNode(null, placeholder, container, anchor);
660            }
661            return;
662        }
663        setupRenderEffect(instance, initialVNode, container, anchor, parentSuspense, isSVG, optimized);
664        {
665            popWarningContext();
666            endMeasure(instance, `mount`);
667        }
668    };
669    const updateComponent = (n1, n2, optimized) => {
670        const instance = (n2.component = n1.component);
671        if (shouldUpdateComponent(n1, n2, optimized)) {
672            if (
673                instance.asyncDep &&
674                !instance.asyncResolved) {
675                // async & still pending - just update props and slots
676                // since the component's reactive effect for render isn't set-up yet
677                {
678                    pushWarningContext(n2);
679                }
680                updateComponentPreRender(instance, n2, optimized);
681                {
682                    popWarningContext();
683                }
684                return;
685            }
686            else {
687                // normal update
688                instance.next = n2;
689                // in case the child component is also queued, remove it to avoid
690                // double updating the same child component in the same flush.
691                invalidateJob(instance.update);
692                // instance.update is the reactive effect runner.
693                instance.update();
694            }
695        }
696        else {
697            // no update needed. just copy over properties
698            n2.component = n1.component;
699            n2.el = n1.el;
700            instance.vnode = n2;
701        }
702    };
703    const setupRenderEffect = (instance, initialVNode, container, anchor, parentSuspense, isSVG, optimized) => {
704        // create reactive effect for rendering
705        instance.update = effect(function componentEffect() {
706            if (!instance.isMounted) {
707                let vnodeHook;
708                const { el, props } = initialVNode;
709                const { bm, m, parent } = instance;
710                // beforeMount hook
711                if (bm) {
712                    invokeArrayFns(bm);
713                }
714                // onVnodeBeforeMount
715                if ((vnodeHook = props && props.onVnodeBeforeMount)) {
716                    invokeVNodeHook(vnodeHook, parent, initialVNode);
717                }
718                // render
719                {
720                    startMeasure(instance, `render`);
721                }
722                const subTree = (instance.subTree = renderComponentRoot(instance));
723                {
724                    endMeasure(instance, `render`);
725                }
726                if (el && hydrateNode) {
727                    {
728                        startMeasure(instance, `hydrate`);
729                    }
730                    // vnode has adopted host node - perform hydration instead of mount.
731                    hydrateNode(initialVNode.el, subTree, instance, parentSuspense);
732                    {
733                        endMeasure(instance, `hydrate`);
734                    }
735                }
736                else {
737                    {
738                        startMeasure(instance, `patch`);
739                    }
740                    patch(null, subTree, container, anchor, instance, parentSuspense, isSVG);
741                    {
742                        endMeasure(instance, `patch`);
743                    }
744                    initialVNode.el = subTree.el;
745                }
746                // mounted hook
747                if (m) {
748                    queuePostRenderEffect(m, parentSuspense);
749                }
750                // onVnodeMounted
751                if ((vnodeHook = props && props.onVnodeMounted)) {
752                    queuePostRenderEffect(() => {
753                        invokeVNodeHook(vnodeHook, parent, initialVNode);
754                    }, parentSuspense);
755                }
756                // activated hook for keep-alive roots.
757                // #1742 activated hook must be accessed after first render
758                // since the hook may be injected by a child keep-alive
759                const { a } = instance;
760                if (a &&
761                    initialVNode.shapeFlag & 256 /* COMPONENT_SHOULD_KEEP_ALIVE */) {
762                    queuePostRenderEffect(a, parentSuspense);
763                }
764                instance.isMounted = true;
765            }
766            else {
767                // updateComponent
768                // This is triggered by mutation of component's own state (next: null)
769                // OR parent calling processComponent (next: VNode)
770                let { next, bu, u, parent, vnode } = instance;
771                let originNext = next;
772                let vnodeHook;
773                {
774                    pushWarningContext(next || instance.vnode);
775                }
776                if (next) {
777                    updateComponentPreRender(instance, next, optimized);
778                }
779                else {
780                    next = vnode;
781                }
782                next.el = vnode.el;
783                // beforeUpdate hook
784                if (bu) {
785                    invokeArrayFns(bu);
786                }
787                // onVnodeBeforeUpdate
788                if ((vnodeHook = next.props && next.props.onVnodeBeforeUpdate)) {
789                    invokeVNodeHook(vnodeHook, parent, next, vnode);
790                }
791                // render
792                {
793                    startMeasure(instance, `render`);
794                }
795                const nextTree = renderComponentRoot(instance);
796                {
797                    endMeasure(instance, `render`);
798                }
799                const prevTree = instance.subTree;
800                instance.subTree = nextTree;
801                // reset refs
802                // only needed if previous patch had refs
803                if (instance.refs !== EMPTY_OBJ) {
804                    instance.refs = {};
805                }
806                {
807                    startMeasure(instance, `patch`);
808                }
809                patch(prevTree, nextTree, 
810                // parent may have changed if it's in a teleport
811                hostParentNode(prevTree.el), 
812                // anchor may have changed if it's in a fragment
813                getNextHostNode(prevTree), instance, parentSuspense, isSVG);
814                {
815                    endMeasure(instance, `patch`);
816                }
817                next.el = nextTree.el;
818                if (originNext === null) {
819                    // self-triggered update. In case of HOC, update parent component
820                    // vnode el. HOC is indicated by parent instance's subTree pointing
821                    // to child component's vnode
822                    updateHOCHostEl(instance, nextTree.el);
823                }
824                // updated hook
825                if (u) {
826                    queuePostRenderEffect(u, parentSuspense);
827                }
828                // onVnodeUpdated
829                if ((vnodeHook = next.props && next.props.onVnodeUpdated)) {
830                    queuePostRenderEffect(() => {
831                        invokeVNodeHook(vnodeHook, parent, next, vnode);
832                    }, parentSuspense);
833                }
834                {
835                    devtoolsComponentUpdated(instance);
836                }
837                {
838                    popWarningContext();
839                }
840            }
841        },  createDevEffectOptions(instance) );
842    };
843    const updateComponentPreRender = (instance, nextVNode, optimized) => {
844        nextVNode.component = instance;
845        const prevProps = instance.vnode.props;
846        instance.vnode = nextVNode;
847        instance.next = null;
848        updateProps(instance, nextVNode.props, prevProps, optimized);
849        updateSlots(instance, nextVNode.children);
850        // props update may have triggered pre-flush watchers.
851        // flush them before the render update.
852        flushPreFlushCbs(undefined, instance.update);
853    };
854    const patchChildren = (n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized = false) => {
855        const c1 = n1 && n1.children;
856        const prevShapeFlag = n1 ? n1.shapeFlag : 0;
857        const c2 = n2.children;
858        const { patchFlag, shapeFlag } = n2;
859        // fast path
860        if (patchFlag > 0) {
861            if (patchFlag & 128 /* KEYED_FRAGMENT */) {
862                // this could be either fully-keyed or mixed (some keyed some not)
863                // presence of patchFlag means children are guaranteed to be arrays
864                patchKeyedChildren(c1, c2, container, anchor, parentComponent, parentSuspense, isSVG, optimized);
865                return;
866            }
867            else if (patchFlag & 256 /* UNKEYED_FRAGMENT */) {
868                // unkeyed
869                patchUnkeyedChildren(c1, c2, container, anchor, parentComponent, parentSuspense, isSVG, optimized);
870                return;
871            }
872        }
873        // children has 3 possibilities: text, array or no children.
874        if (shapeFlag & 8 /* TEXT_CHILDREN */) {
875            // text children fast path
876            if (prevShapeFlag & 16 /* ARRAY_CHILDREN */) {
877                unmountChildren(c1, parentComponent, parentSuspense);
878            }
879            if (c2 !== c1) {
880                hostSetElementText(container, c2);
881            }
882        }
883        else {
884            if (prevShapeFlag & 16 /* ARRAY_CHILDREN */) {
885                // prev children was array
886                if (shapeFlag & 16 /* ARRAY_CHILDREN */) {
887                    // two arrays, cannot assume anything, do full diff
888                    patchKeyedChildren(c1, c2, container, anchor, parentComponent, parentSuspense, isSVG, optimized);
889                }
890                else {
891                    // no new children, just unmount old
892                    unmountChildren(c1, parentComponent, parentSuspense, true);
893                }
894            }
895            else {
896                // prev children was text OR null
897                // new children is array OR null
898                if (prevShapeFlag & 8 /* TEXT_CHILDREN */) {
899                    hostSetElementText(container, '');
900                }
901                // mount new if array
902                if (shapeFlag & 16 /* ARRAY_CHILDREN */) {
903                    mountChildren(c2, container, anchor, parentComponent, parentSuspense, isSVG, optimized);
904                }
905            }
906        }
907    };
908    const patchUnkeyedChildren = (c1, c2, container, anchor, parentComponent, parentSuspense, isSVG, optimized) => {
909        c1 = c1 || EMPTY_ARR;
910        c2 = c2 || EMPTY_ARR;
911        const oldLength = c1.length;
912        const newLength = c2.length;
913        const commonLength = Math.min(oldLength, newLength);
914        let i;
915        for (i = 0; i < commonLength; i++) {
916            const nextChild = (c2[i] = optimized
917                ? cloneIfMounted(c2[i])
918                : normalizeVNode(c2[i]));
919            patch(c1[i], nextChild, container, null, parentComponent, parentSuspense, isSVG, optimized);
920        }
921        if (oldLength > newLength) {
922            // remove old
923            unmountChildren(c1, parentComponent, parentSuspense, true, commonLength);
924        }
925        else {
926            // mount new
927            mountChildren(c2, container, anchor, parentComponent, parentSuspense, isSVG, optimized, commonLength);
928        }
929    };
930    // can be all-keyed or mixed
931    const patchKeyedChildren = (c1, c2, container, parentAnchor, parentComponent, parentSuspense, isSVG, optimized) => {
932        let i = 0;
933        const l2 = c2.length;
934        let e1 = c1.length - 1; // prev ending index
935        let e2 = l2 - 1; // next ending index
936        // 1. sync from start
937        // (a b) c
938        // (a b) d e
939        while (i <= e1 && i <= e2) {
940            const n1 = c1[i];
941            const n2 = (c2[i] = optimized
942                ? cloneIfMounted(c2[i])
943                : normalizeVNode(c2[i]));
944            if (isSameVNodeType(n1, n2)) {
945                patch(n1, n2, container, null, parentComponent, parentSuspense, isSVG, optimized);
946            }
947            else {
948                break;
949            }
950            i++;
951        }
952        // 2. sync from end
953        // a (b c)
954        // d e (b c)
955        while (i <= e1 && i <= e2) {
956            const n1 = c1[e1];
957            const n2 = (c2[e2] = optimized
958                ? cloneIfMounted(c2[e2])
959                : normalizeVNode(c2[e2]));
960            if (isSameVNodeType(n1, n2)) {
961                patch(n1, n2, container, null, parentComponent, parentSuspense, isSVG, optimized);
962            }
963            else {
964                break;
965            }
966            e1--;
967            e2--;
968        }
969        // 3. common sequence + mount
970        // (a b)
971        // (a b) c
972        // i = 2, e1 = 1, e2 = 2
973        // (a b)
974        // c (a b)
975        // i = 0, e1 = -1, e2 = 0
976        if (i > e1) {
977            if (i <= e2) {
978                const nextPos = e2 + 1;
979                const anchor = nextPos < l2 ? c2[nextPos].el : parentAnchor;
980                while (i <= e2) {
981                    patch(null, (c2[i] = optimized
982                        ? cloneIfMounted(c2[i])
983                        : normalizeVNode(c2[i])), container, anchor, parentComponent, parentSuspense, isSVG);
984                    i++;
985                }
986            }
987        }
988        // 4. common sequence + unmount
989        // (a b) c
990        // (a b)
991        // i = 2, e1 = 2, e2 = 1
992        // a (b c)
993        // (b c)
994        // i = 0, e1 = 0, e2 = -1
995        else if (i > e2) {
996            while (i <= e1) {
997                unmount(c1[i], parentComponent, parentSuspense, true);
998                i++;
999            }
1000        }
1001        // 5. unknown sequence
1002        // [i ... e1 + 1]: a b [c d e] f g
1003        // [i ... e2 + 1]: a b [e d c h] f g
1004        // i = 2, e1 = 4, e2 = 5
1005        else {
1006            const s1 = i; // prev starting index
1007            const s2 = i; // next starting index
1008            // 5.1 build key:index map for newChildren
1009            const keyToNewIndexMap = new Map();
1010            for (i = s2; i <= e2; i++) {
1011                const nextChild = (c2[i] = optimized
1012                    ? cloneIfMounted(c2[i])
1013                    : normalizeVNode(c2[i]));
1014                if (nextChild.key != null) {
1015                    if ( keyToNewIndexMap.has(nextChild.key)) {
1016                        warn(`Duplicate keys found during update:`, JSON.stringify(nextChild.key), `Make sure keys are unique.`);
1017                    }
1018                    keyToNewIndexMap.set(nextChild.key, i);
1019                }
1020            }
1021            // 5.2 loop through old children left to be patched and try to patch
1022            // matching nodes & remove nodes that are no longer present
1023            let j;
1024            let patched = 0;
1025            const toBePatched = e2 - s2 + 1;
1026            let moved = false;
1027            // used to track whether any node has moved
1028            let maxNewIndexSoFar = 0;
1029            // works as Map<newIndex, oldIndex>
1030            // Note that oldIndex is offset by +1
1031            // and oldIndex = 0 is a special value indicating the new node has
1032            // no corresponding old node.
1033            // used for determining longest stable subsequence
1034            const newIndexToOldIndexMap = new Array(toBePatched);
1035            for (i = 0; i < toBePatched; i++)
1036                newIndexToOldIndexMap[i] = 0;
1037            for (i = s1; i <= e1; i++) {
1038                const prevChild = c1[i];
1039                if (patched >= toBePatched) {
1040                    // all new children have been patched so this can only be a removal
1041                    unmount(prevChild, parentComponent, parentSuspense, true);
1042                    continue;
1043                }
1044                let newIndex;
1045                if (prevChild.key != null) {
1046                    newIndex = keyToNewIndexMap.get(prevChild.key);
1047                }
1048                else {
1049                    // key-less node, try to locate a key-less node of the same type
1050                    for (j = s2; j <= e2; j++) {
1051                        if (newIndexToOldIndexMap[j - s2] === 0 &&
1052                            isSameVNodeType(prevChild, c2[j])) {
1053                            newIndex = j;
1054                            break;
1055                        }
1056                    }
1057                }
1058                if (newIndex === undefined) {
1059                    unmount(prevChild, parentComponent, parentSuspense, true);
1060                }
1061                else {
1062                    newIndexToOldIndexMap[newIndex - s2] = i + 1;
1063                    if (newIndex >= maxNewIndexSoFar) {
1064                        maxNewIndexSoFar = newIndex;
1065                    }
1066                    else {
1067                        moved = true;
1068                    }
1069                    patch(prevChild, c2[newIndex], container, null, parentComponent, parentSuspense, isSVG, optimized);
1070                    patched++;
1071                }
1072            }
1073            // 5.3 move and mount
1074            // generate longest stable subsequence only when nodes have moved
1075            const increasingNewIndexSequence = moved
1076                ? getSequence(newIndexToOldIndexMap)
1077                : EMPTY_ARR;
1078            j = increasingNewIndexSequence.length - 1;
1079            // looping backwards so that we can use last patched node as anchor
1080            for (i = toBePatched - 1; i >= 0; i--) {
1081                const nextIndex = s2 + i;
1082                const nextChild = c2[nextIndex];
1083                const anchor = nextIndex + 1 < l2 ? c2[nextIndex + 1].el : parentAnchor;
1084                if (newIndexToOldIndexMap[i] === 0) {
1085                    // mount new
1086                    patch(null, nextChild, container, anchor, parentComponent, parentSuspense, isSVG);
1087                }
1088                else if (moved) {
1089                    // move if:
1090                    // There is no stable subsequence (e.g. a reverse)
1091                    // OR current node is not among the stable sequence
1092                    if (j < 0 || i !== increasingNewIndexSequence[j]) {
1093                        move(nextChild, container, anchor, 2 /* REORDER */);
1094                    }
1095                    else {
1096                        j--;
1097                    }
1098                }
1099            }
1100        }
1101    };
1102    const move = (vnode, container, anchor, moveType, parentSuspense = null) => {
1103        const { el, type, transition, children, shapeFlag } = vnode;
1104        if (shapeFlag & 6 /* COMPONENT */) {
1105            move(vnode.component.subTree, container, anchor, moveType);
1106            return;
1107        }
1108        if ( shapeFlag & 128 /* SUSPENSE */) {
1109            vnode.suspense.move(container, anchor, moveType);
1110            return;
1111        }
1112        if (shapeFlag & 64 /* TELEPORT */) {
1113            type.move(vnode, container, anchor, internals);
1114            return;
1115        }
1116        if (type === Fragment) {
1117            hostInsert(el, container, anchor);
1118            for (let i = 0; i < children.length; i++) {
1119                move(children[i], container, anchor, moveType);
1120            }
1121            hostInsert(vnode.anchor, container, anchor);
1122            return;
1123        }
1124        // static node move can only happen when force updating HMR
1125        if ( type === Static) {
1126            moveStaticNode(vnode, container, anchor);
1127            return;
1128        }
1129        // single nodes
1130        const needTransition = moveType !== 2 /* REORDER */ &&
1131            shapeFlag & 1 /* ELEMENT */ &&
1132            transition;
1133        if (needTransition) {
1134            if (moveType === 0 /* ENTER */) {
1135                transition.beforeEnter(el);
1136                hostInsert(el, container, anchor);
1137                queuePostRenderEffect(() => transition.enter(el), parentSuspense);
1138            }
1139            else {
1140                const { leave, delayLeave, afterLeave } = transition;
1141                const remove = () => hostInsert(el, container, anchor);
1142                const performLeave = () => {
1143                    leave(el, () => {
1144                        remove();
1145                        afterLeave && afterLeave();
1146                    });
1147                };
1148                if (delayLeave) {
1149                    delayLeave(el, remove, performLeave);
1150                }
1151                else {
1152                    performLeave();
1153                }
1154            }
1155        }
1156        else {
1157            hostInsert(el, container, anchor);
1158        }
1159    };
1160    const unmount = (vnode, parentComponent, parentSuspense, doRemove = false) => {
1161        const { type, props, ref, children, dynamicChildren, shapeFlag, patchFlag, dirs } = vnode;
1162        // unset ref
1163        if (ref != null && parentComponent) {
1164            setRef(ref, null, parentComponent, parentSuspense, null);
1165        }
1166        if (shapeFlag & 256 /* COMPONENT_SHOULD_KEEP_ALIVE */) {
1167            parentComponent.ctx.deactivate(vnode);
1168            return;
1169        }
1170        const shouldInvokeDirs = shapeFlag & 1 /* ELEMENT */ && dirs;
1171        let vnodeHook;
1172        if ((vnodeHook = props && props.onVnodeBeforeUnmount)) {
1173            invokeVNodeHook(vnodeHook, parentComponent, vnode);
1174        }
1175        if (shapeFlag & 6 /* COMPONENT */) {
1176            unmountComponent(vnode.component, parentSuspense, doRemove);
1177        }
1178        else {
1179            if ( shapeFlag & 128 /* SUSPENSE */) {
1180                vnode.suspense.unmount(parentSuspense, doRemove);
1181                return;
1182            }
1183            if (shouldInvokeDirs) {
1184                invokeDirectiveHook(vnode, null, parentComponent, 'beforeUnmount');
1185            }
1186            if (dynamicChildren &&
1187                // #1153: fast path should not be taken for non-stable (v-for) fragments
1188                (type !== Fragment ||
1189                    (patchFlag > 0 && patchFlag & 64 /* STABLE_FRAGMENT */))) {
1190                // fast path for block nodes: only need to unmount dynamic children.
1191                unmountChildren(dynamicChildren, parentComponent, parentSuspense);
1192            }
1193            else if (shapeFlag & 16 /* ARRAY_CHILDREN */) {
1194                unmountChildren(children, parentComponent, parentSuspense);
1195            }
1196            // an unmounted teleport should always remove its children
1197            if (shapeFlag & 64 /* TELEPORT */) {
1198                vnode.type.remove(vnode, internals);
1199            }
1200            if (doRemove) {
1201                remove(vnode);
1202            }
1203        }
1204        if ((vnodeHook = props && props.onVnodeUnmounted) || shouldInvokeDirs) {
1205            queuePostRenderEffect(() => {
1206                vnodeHook && invokeVNodeHook(vnodeHook, parentComponent, vnode);
1207                shouldInvokeDirs &&
1208                    invokeDirectiveHook(vnode, null, parentComponent, 'unmounted');
1209            }, parentSuspense);
1210        }
1211    };
1212    const remove = vnode => {
1213        const { type, el, anchor, transition } = vnode;
1214        if (type === Fragment) {
1215            removeFragment(el, anchor);
1216            return;
1217        }
1218        if ( type === Static) {
1219            removeStaticNode(vnode);
1220            return;
1221        }
1222        const performRemove = () => {
1223            hostRemove(el);
1224            if (transition && !transition.persisted && transition.afterLeave) {
1225                transition.afterLeave();
1226            }
1227        };
1228        if (vnode.shapeFlag & 1 /* ELEMENT */ &&
1229            transition &&
1230            !transition.persisted) {
1231            const { leave, delayLeave } = transition;
1232            const performLeave = () => leave(el, performRemove);
1233            if (delayLeave) {
1234                delayLeave(vnode.el, performRemove, performLeave);
1235            }
1236            else {
1237                performLeave();
1238            }
1239        }
1240        else {
1241            performRemove();
1242        }
1243    };
1244    const removeFragment = (cur, end) => {
1245        // For fragments, directly remove all contained DOM nodes.
1246        // (fragment child nodes cannot have transition)
1247        let next;
1248        while (cur !== end) {
1249            next = hostNextSibling(cur);
1250            hostRemove(cur);
1251            cur = next;
1252        }
1253        hostRemove(end);
1254    };
1255    const unmountComponent = (instance, parentSuspense, doRemove) => {
1256        if ( instance.type.__hmrId) {
1257            unregisterHMR(instance);
1258        }
1259        const { bum, effects, update, subTree, um } = instance;
1260        // beforeUnmount hook
1261        if (bum) {
1262            invokeArrayFns(bum);
1263        }
1264        if (effects) {
1265            for (let i = 0; i < effects.length; i++) {
1266                stop(effects[i]);
1267            }
1268        }
1269        // update may be null if a component is unmounted before its async
1270        // setup has resolved.
1271        if (update) {
1272            stop(update);
1273            unmount(subTree, instance, parentSuspense, doRemove);
1274        }
1275        // unmounted hook
1276        if (um) {
1277            queuePostRenderEffect(um, parentSuspense);
1278        }
1279        queuePostRenderEffect(() => {
1280            instance.isUnmounted = true;
1281        }, parentSuspense);
1282        // A component with async dep inside a pending suspense is unmounted before
1283        // its async dep resolves. This should remove the dep from the suspense, and
1284        // cause the suspense to resolve immediately if that was the last dep.
1285        if (
1286            parentSuspense &&
1287            parentSuspense.pendingBranch &&
1288            !parentSuspense.isUnmounted &&
1289            instance.asyncDep &&
1290            !instance.asyncResolved &&
1291            instance.suspenseId === parentSuspense.pendingId) {
1292            parentSuspense.deps--;
1293            if (parentSuspense.deps === 0) {
1294                parentSuspense.resolve();
1295            }
1296        }
1297        {
1298            devtoolsComponentRemoved(instance);
1299        }
1300    };
1301    const unmountChildren = (children, parentComponent, parentSuspense, doRemove = false, start = 0) => {
1302        for (let i = start; i < children.length; i++) {
1303            unmount(children[i], parentComponent, parentSuspense, doRemove);
1304        }
1305    };
1306    const getNextHostNode = vnode => {
1307        if (vnode.shapeFlag & 6 /* COMPONENT */) {
1308            return getNextHostNode(vnode.component.subTree);
1309        }
1310        if ( vnode.shapeFlag & 128 /* SUSPENSE */) {
1311            return vnode.suspense.next();
1312        }
1313        return hostNextSibling((vnode.anchor || vnode.el));
1314    };
1315    /**
1316     * #1156
1317     * When a component is HMR-enabled, we need to make sure that all static nodes
1318     * inside a block also inherit the DOM element from the previous tree so that
1319     * HMR updates (which are full updates) can retrieve the element for patching.
1320     *
1321     * #2080
1322     * Inside keyed `template` fragment static children, if a fragment is moved,
1323     * the children will always moved so that need inherit el form previous nodes
1324     * to ensure correct moved position.
1325     */
1326    const traverseStaticChildren = (n1, n2, shallow = false) => {
1327        const ch1 = n1.children;
1328        const ch2 = n2.children;
1329        if (isArray(ch1) && isArray(ch2)) {
1330            for (let i = 0; i < ch1.length; i++) {
1331                // this is only called in the optimized path so array children are
1332                // guaranteed to be vnodes
1333                const c1 = ch1[i];
1334                const c2 = (ch2[i] = cloneIfMounted(ch2[i]));
1335                if (c2.shapeFlag & 1 /* ELEMENT */ && !c2.dynamicChildren) {
1336                    if (c2.patchFlag <= 0 || c2.patchFlag === 32 /* HYDRATE_EVENTS */) {
1337                        c2.el = c1.el;
1338                    }
1339                    if (!shallow)
1340                        traverseStaticChildren(c1, c2);
1341                }
1342                if ( c2.type === Comment) {
1343                    c2.el = c1.el;
1344                }
1345            }
1346        }
1347    };
1348    const render = (vnode, container) => {
1349        if (vnode == null) {
1350            if (container._vnode) {
1351                unmount(container._vnode, null, null, true);
1352            }
1353        }
1354        else {
1355            patch(container._vnode || null, vnode, container);
1356        }
1357        flushPostFlushCbs();
1358        container._vnode = vnode;
1359    };
1360    const internals = {
1361        p: patch,
1362        um: unmount,
1363        m: move,
1364        r: remove,
1365        mt: mountComponent,
1366        mc: mountChildren,
1367        pc: patchChildren,
1368        pbc: patchBlockChildren,
1369        n: getNextHostNode,
1370        o: options
1371    };
1372    let hydrate;
1373    let hydrateNode;
1374    if (createHydrationFns) {
1375        [hydrate, hydrateNode] = createHydrationFns(internals);
1376    }
1377    return {
1378        render,
1379        hydrate,
1380        createApp: createAppAPI(render, hydrate)
1381    };
1382}
Full Screen

vnode.js

Source: vnode.js Github

copy
1import { isClassComponent } from './component.js'
2import {
3  isArray,
4  isFunction,
5  isString,
6  isObject,
7  EMPTY_ARR,
8  extend,
9  normalizeClass,
10  normalizeStyle,
11  isOn
12} from '../shared/index.js'
13import { isProxy } from '../reactivity/index.js'
14import {
15  currentRenderingInstance,
16  currentScopeId
17} from './componentRenderContext.js'
18
19const isSuspense = type => type.__isSuspense
20const isTeleport = type => type.__isTeleport
21
22export const Fragment = Symbol('Fragment')
23export const Text = Symbol('Text')
24export const Comment = Symbol('Comment')
25export const Static = Symbol('Static')
26export { createBaseVNode as createElementVNode }
27
28export const blockStack = []
29export let currentBlock = null
30
31export function openBlock (disableTracking = false) {
32  blockStack.push((currentBlock = disableTracking ? null : []))
33}
34export function closeBlock () {
35  blockStack.pop()
36  currentBlock = blockStack[blockStack.length - 1] || null
37}
38
39export let isBlockTreeEnabled = 1
40
41export function setBlockTracking (value) {
42  isBlockTreeEnabled += value
43}
44export function setupBlock (vnode) {
45  vnode.dynamicChildren =
46    isBlockTreeEnabled > 0 ? currentBlock || EMPTY_ARR : null
47  closeBlock()
48  if (isBlockTreeEnabled > 0 && currentBlock) {
49    currentBlock.push(vnode)
50  }
51  return vnode
52}
53export function createElementBlock (
54  type,
55  props,
56  children,
57  patchFlag,
58  dynamicProps,
59  shapeFlag
60) {
61  return setupBlock(
62    createBaseVNode(
63      type,
64      props,
65      children,
66      patchFlag,
67      dynamicProps,
68      shapeFlag,
69      true
70    )
71  )
72}
73export function createBlock (type, props, children, patchFlag, dynamicProps) {
74  return setupBlock(
75    createVNode(type, props, children, patchFlag, dynamicProps, true)
76  )
77}
78export function isVNode (value) {
79  return value ? value.__v_isVNode === true : false
80}
81export function isSameVNodeType (n1, n2) {
82  return n1.type === n2.type && n1.key === n2.key
83}
84
85export const createVNode = _createVNode
86
87export const InternalObjectKey = `__vInternal`
88const normalizeKey = ({ key }) => (key != null ? key : null)
89const normalizeRef = ({ ref, ref_key, ref_for }) => {
90  return ref != null
91    ? isString(ref) || isRef(ref) || isFunction(ref)
92      ? { i: currentRenderingInstance, r: ref, k: ref_key, f: !!ref_for }
93      : ref
94    : null
95}
96
97export function createBaseVNode (
98  type,
99  props = null,
100  children = null,
101  patchFlag = 0,
102  dynamicProps = null,
103  shapeFlag = type === Fragment ? 0 : 1,
104  isBlockNode = false,
105  needFullChildrenNormalization = false
106) {
107  const vnode = {
108    __v_isVNode: true,
109    __v_skip: true,
110    type,
111    props,
112    key: props && normalizeKey(props), //props没有key属性返回nul
113    ref: props && normalizeRef(props), //props没有ref属性返回null
114    scopeId: currentScopeId,
115    slotScopeIds: null,
116    children,
117    component: null,
118    suspense: null,
119    ssContent: null,
120    ssFallback: null,
121    dirs: null,
122    transition: null,
123    el: null,
124    anchor: null,
125    target: null,
126    targetAnchor: null,
127    staticCount: 0,
128    shapeFlag,
129    patchFlag,
130    dynamicProps,
131    dynamicChildren: null,
132    appContext: null
133  }
134  if (needFullChildrenNormalization) {
135    normalizeChildren(vnode, children)
136    if (shapeFlag & 128) {
137      type.normalize(vnode)
138    }
139  } else if (children) {
140    vnode.shapeFlag |= isString(children) ? 8 : 16
141  }
142
143  if (
144    isBlockTreeEnabled > 0 &&
145    !isBlockNode &&
146    currentBlock &&
147    (vnode.patchFlag > 0 || shapeFlag & 6) &&
148    vnode.patchFlag !== 32
149  ) {
150    currentBlock.push(vnode)
151  }
152  return vnode
153}
154function _createVNode (
155  type,
156  props = null,
157  children = null,
158  patchFlag = 0,
159  dynamicProps = null,
160  isBlockNode = false
161) {
162  // 初始化
163  // type:{template,setup}
164
165  if (!type) {
166    type = Comment
167  }
168  // 是否是 vnode
169  if (isVNode(type)) {
170    // 是 vnode,克隆vnode
171    const cloned = cloneVNode(type, props, true)
172    if (children) {
173      // 有 children
174      normalizeChildren(cloned, children)
175    }
176    return cloned
177  }
178  // 是否是 函数 ,并且有 ’__vccOpts‘
179  if (isClassComponent(type)) {
180    type = type.__vccOpts
181  }
182
183  // 处理 props
184  // 规范化class & style
185  if (props) {
186    // 如果是proxy或有’__vInternal‘ 克隆对象
187    props = guardReactiveProps(props)
188    // 获取 css
189    let { class: klass, style } = props
190    // 拼接 class
191    if (klass && !isString(klass)) {
192      // 返回值 字符串 'classA classB classC'
193      props.class = normalizeClass(klass)
194    }
195    if (isObject(style)) {
196      if (isProxy(style) && !isArray(style)) {
197        // style 是 proxy 且不是数组
198        // 复制 style
199        style = extend({}, style)
200      }
201      props.style = normalizeStyle(style)
202    }
203  }
204  const shapeFlag = isString(type)
205    ? 1 /* ELEMENT 标签  */
206    : isSuspense(type)
207    ? 128 /* SUSPENSE 异步组件? */
208    : isTeleport(type)
209    ? 64 /* TELEPORT 可以挂载到任意节点上的组件 */
210    : isObject(type)
211    ? 4 /* STATEFUL_COMPONENT 有状态组件 */
212    : isFunction(type)
213    ? 2 /* FUNCTIONAL_COMPONENT 函数组件 */
214    : 0
215  return createBaseVNode(
216    type,
217    props,
218    children,
219    patchFlag,
220    dynamicProps,
221    shapeFlag,
222    isBlockNode,
223    true
224  )
225}
226export function guardReactiveProps (props) {
227  if (!props) return null
228  return isProxy(props) || InternalObjectKey in props
229    ? extend({}, props)
230    : props
231}
232export function cloneVNode (vnode, extraProps, mergeRef = false) {
233  const { props, ref, patchFlag, children } = vnode
234  const mergedProps = extraProps ? mergeProps(props || {}, extraProps) : props
235  const cloned = {
236    __v_isVNode: true,
237    __v_skip: true,
238    type: vnode.type,
239    props: mergedProps,
240    key: mergedProps && normalizeKey(mergedProps),
241    ref:
242      extraProps && extraProps.ref
243        ? mergeRef && ref
244          ? isArray(ref)
245            ? ref.concat(normalizeRef(extraProps))
246            : [ref, normalizeRef(extraProps)]
247          : normalizeRef(extraProps)
248        : ref,
249    scopeId: vnode.scopeId,
250    slotScopeIds: vnode.slotScopeIds,
251    children: children,
252    target: vnode.target,
253    targetAnchor: vnode.targetAnchor,
254    staticCount: vnode.staticCount,
255    shapeFlag: vnode.shapeFlag,
256    patchFlag:
257      extraProps && vnode.type !== Fragment
258        ? patchFlag === -1
259          ? 16
260          : patchFlag | 16
261        : patchFlag,
262    dynamicProps: vnode.dynamicProps,
263    dynamicChildren: vnode.dynamicChildren,
264    appContext: vnode.appContext,
265    dirs: vnode.dirs,
266    transition: vnode.transition,
267    component: vnode.component,
268    suspense: vnode.suspense,
269    ssContent: vnode.ssContent && cloneVNode(vnode.ssContent),
270    ssFallback: vnode.ssFallback && cloneVNode(vnode.ssFallback),
271    el: vnode.el,
272    anchor: vnode.anchor
273  }
274  return cloned
275}
276export function deepCloneVNode (vnode) {
277  const cloned = cloneVNode(vnode)
278  if (isArray(vnode.children)) {
279    cloned.children = vnode.children.map(deepCloneVNode)
280  }
281  return cloned
282}
283export function createTextVNode (text = ' ', flag = 0) {
284  return createVNode(Text, null, text, flag)
285}
286export function createStaticVNode (content, numberOfNodes) {
287  const vnode = createVNode(Static, null, content)
288  vnode.staticCount = numberOfNodes
289  return vnode
290}
291export function createCommentVNode (text = '', asBlock = false) {
292  return asBlock
293    ? (openBlock(), createBlock(Comment, null, text))
294    : createVNode(Comment, null, text)
295}
296export function normalizeVNode (child) {
297  if (child == null || typeof child === 'boolean') {
298    return createVNode(Comment)
299  } else if (isArray(child)) {
300    return createVNode(Fragment, null, child.slice())
301  } else if (typeof child === 'object') {
302    return cloneIfMounted(child)
303  } else {
304    return createVNode(Text, null, String(child))
305  }
306}
307export function cloneIfMounted (child) {
308  return child.el === null || child.memo ? child : cloneVNode(child)
309}
310export function normalizeChildren (vnode, children) {
311  let type = 0
312  const { shapeFlag } = vnode
313  if (children == null) {
314    children = null
315  } else if (isArray(children)) {
316    type = 16
317  } else if (typeof children === 'object') {
318    if (shapeFlag & (1 | 64)) {
319      const slot = children.default
320      if (slot) {
321        slot._c && (slot._d = false)
322        normalizeChildren(vnode, slot())
323        slot._c && (slot._d = true)
324      }
325      return
326    } else {
327      type = 32
328      const slotFlag = children._
329      if (!slotFlag && !(InternalObjectKey in children)) {
330        children._ctx = currentRenderingInstance
331      } else if (slotFlag === 3 && currentRenderingInstance) {
332        if (currentRenderingInstance.slots._ === 1) {
333          children._ = 1
334        } else {
335          children._ = 2
336          vnode.patchFlag |= 1024
337        }
338      }
339    }
340  } else if (isFunction(children)) {
341    children = { default: children, _ctx: currentRenderingInstance }
342    type = 32
343  } else {
344    children = String(children)
345    if (shapeFlag & 64) {
346      type = 16
347      children = [createTextVNode(children)]
348    } else {
349      type = 8
350    }
351  }
352  vnode.children = children
353  vnode.shapeFlag |= type
354}
355export function mergeProps (...args) {
356  const ret = {}
357  for (let i = 0; i < args.length; i++) {
358    const toMerge = args[i]
359    for (const key in toMerge) {
360      if (key === 'class') {
361        if (ret.class !== toMerge.class) {
362          ret.class = normalizeClass([ret.class, toMerge.class])
363        }
364      } else if (key === 'style') {
365        ret.style = normalizeStyle([ret.style, toMerge.style])
366      } else if (isOn(key)) {
367        const existing = ret[key]
368        const incoming = toMerge[key]
369        if (
370          incoming &&
371          existing !== incoming &&
372          !(isArray(existing) && existing.includes(incoming))
373        ) {
374          ret[key] = existing ? [].concat(existing, incoming) : incoming
375        }
376      } else if (key !== '') {
377        ret[key] = toMerge[key]
378      }
379    }
380  }
381  return ret
382}
383export function invokeVNodeHook (hook, instance, vnode, prevVNode = null) {
384  hook(vnode, prevVNode)
385}
386
Full Screen

Accelerate Your Automation Test Cycles With LambdaTest

Leverage LambdaTest’s cloud-based platform to execute your automation tests in parallel and trim down your test execution time significantly. Your first 100 automation testing minutes are on us.

Try LambdaTest

Run JavaScript Tests on LambdaTest Cloud Grid

Execute automation tests with Playwright Internal on a cloud-based Grid of 3000+ real browsers and operating systems for both web and mobile applications.

Test now for Free
LambdaTestX

We use cookies to give you the best experience. Cookies help to provide a more personalized experience and relevant advertising for you, and web analytics for us. Learn More in our Cookies policy, Privacy & Terms of service

Allow Cookie
Sarah

I hope you find the best code examples for your project.

If you want to accelerate automated browser testing, try LambdaTest. Your first 100 automation testing minutes are FREE.

Sarah Elson (Product & Growth Lead)