diff --git a/bin/vds.js b/bin/vds.js index 614ef2e3256617..72852a8fc6199b 100755 --- a/bin/vds.js +++ b/bin/vds.js @@ -1,2 +1,5 @@ #!/usr/bin/env node -require('../lib/server') +const { createServer } = require('../lib/server') + +// TODO pass cli args +createServer() diff --git a/lib/hmrWatcher.js b/lib/hmrWatcher.js index 47abf74874fb15..e3d3290f594d87 100644 --- a/lib/hmrWatcher.js +++ b/lib/hmrWatcher.js @@ -8,12 +8,12 @@ exports.createFileWatcher = (notify) => { ignored: [/node_modules/] }) - fileWatcher.on('change', (file) => { + fileWatcher.on('change', async (file) => { const resourcePath = '/' + path.relative(process.cwd(), file) if (file.endsWith('.vue')) { // check which part of the file changed - const [descriptor, prevDescriptor] = parseSFC(file) + const [descriptor, prevDescriptor] = await parseSFC(file) if (!prevDescriptor) { // the file has never been accessed yet return diff --git a/lib/moduleMiddleware.js b/lib/moduleMiddleware.js index 5838c7031da2d6..73f8a4fb53cc13 100644 --- a/lib/moduleMiddleware.js +++ b/lib/moduleMiddleware.js @@ -1,23 +1,24 @@ -const fs = require('fs') const path = require('path') -const { sendJS } = require('./utils') +const resolve = require('resolve-cwd') +const { sendJSStream } = require('./utils') exports.moduleMiddleware = (id, res) => { let modulePath - // try node resolve first + // TODO support custom imports map e.g. for snowpack web_modules + + // fallback to node resolve try { - modulePath = require.resolve(id) + modulePath = resolve(id) + if (id === 'vue') { + modulePath = path.join( + path.dirname(modulePath), + 'dist/vue.runtime.esm-browser.js' + ) + } } catch (e) { res.setStatus(404) res.end() } - // TODO resolve snowpack web_modules - - if (id === 'vue') { - // modulePath = path.relative(modulePath, 'dist/vue.runtime.esm-browser.js') - modulePath = path.resolve(__dirname, 'vue.js') - } - - sendJS(res, fs.readFileSync(modulePath)) + sendJSStream(res, modulePath) } diff --git a/lib/parseSFC.js b/lib/parseSFC.js index abcc1abead2245..d98cc6d98c81c2 100644 --- a/lib/parseSFC.js +++ b/lib/parseSFC.js @@ -1,10 +1,10 @@ -const fs = require('fs') +const fs = require('fs').promises const { parse } = require('@vue/compiler-sfc') const cache = new Map() -exports.parseSFC = (filename, saveCache = false) => { - const content = fs.readFileSync(filename, 'utf-8') +exports.parseSFC = async (filename, saveCache = false) => { + const content = await fs.readFile(filename, 'utf-8') const { descriptor, errors } = parse(content, { filename }) diff --git a/lib/server.js b/lib/server.js index 62292969bd700d..22fac9574dedab 100644 --- a/lib/server.js +++ b/lib/server.js @@ -1,4 +1,4 @@ -const fs = require('fs') +const fs = require('fs').promises const path = require('path') const http = require('http') const url = require('url') @@ -10,44 +10,77 @@ const { createFileWatcher } = require('./hmrWatcher') const { sendJS } = require('./utils') const { rewrite } = require('./moduleRewriter') -const hmrClientCode = fs.readFileSync(path.resolve(__dirname, './hmrClient.js')) - -const server = http.createServer((req, res) => { - const pathname = url.parse(req.url).pathname - if (pathname === '/__hmrClient') { - return sendJS(res, hmrClientCode) - } else if (pathname.startsWith('/__modules/')) { - return moduleMiddleware(pathname.replace('/__modules/', ''), res) - } else if (pathname.endsWith('.vue')) { - return vue(req, res) - } else if (pathname.endsWith('.js')) { - const filename = path.join(process.cwd(), pathname.slice(1)) - if (fs.existsSync(filename)) { - const content = rewrite(fs.readFileSync(filename, 'utf-8')) - return sendJS(res, content) +exports.createServer = async ({ port = 3000 } = {}) => { + const hmrClientCode = await fs.readFile( + path.resolve(__dirname, './hmrClient.js') + ) + + const server = http.createServer(async (req, res) => { + const pathname = url.parse(req.url).pathname + if (pathname === '/__hmrClient') { + return sendJS(res, await hmrClientCode) + } else if (pathname.startsWith('/__modules/')) { + return moduleMiddleware(pathname.replace('/__modules/', ''), res) + } else if (pathname.endsWith('.vue')) { + return vue(req, res) + } else if (pathname.endsWith('.js')) { + const filename = path.join(process.cwd(), pathname.slice(1)) + try { + const content = await fs.readFile(filename, 'utf-8') + return sendJS(res, rewrite(content)) + } catch (e) { + if (e.code === 'ENOENT') { + // fallthrough to serve-handler + } else { + console.error(e) + } + } } - } - serve(req, res, { - rewrites: [{ source: '**', destination: '/index.html' }] + serve(req, res, { + rewrites: [{ source: '**', destination: '/index.html' }] + }) }) -}) - -const wss = new ws.Server({ server }) -const sockets = new Set() -wss.on('connection', (socket) => { - sockets.add(socket) - socket.send(JSON.stringify({ type: 'connected' })) - socket.on('close', () => { - sockets.delete(socket) + + const wss = new ws.Server({ server }) + const sockets = new Set() + + wss.on('connection', (socket) => { + sockets.add(socket) + socket.send(JSON.stringify({ type: 'connected' })) + socket.on('close', () => { + sockets.delete(socket) + }) }) -}) -createFileWatcher((payload) => - sockets.forEach((s) => s.send(JSON.stringify(payload))) -) + wss.on('error', (e) => { + if (e.code !== 'EADDRINUSE') { + console.error(e) + } + }) -// TODO customized port -server.listen(3000, () => { - console.log('Running at http://localhost:3000') -}) + createFileWatcher((payload) => + sockets.forEach((s) => s.send(JSON.stringify(payload))) + ) + + return new Promise((resolve, reject) => { + server.on('error', (e) => { + if (e.code === 'EADDRINUSE') { + console.log(`port ${port} is in use, trying another one...`) + setTimeout(() => { + server.close() + server.listen(++port) + }, 100) + } else { + console.error(e) + } + }) + + server.on('listening', () => { + console.log(`Running at http://localhost:${port}`) + resolve() + }) + + server.listen(port) + }) +} diff --git a/lib/utils.js b/lib/utils.js index 695e7227a9052d..33cf5dcedc6515 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,3 +1,5 @@ +const fs = require('fs') + function send(res, source, mime) { res.setHeader('Content-Type', mime) res.end(source) @@ -7,5 +9,17 @@ function sendJS(res, source) { send(res, source, 'application/javascript') } +function sendJSStream(res, file) { + res.setHeader('Content-Type', 'application/javascript') + const stream = fs.createReadStream(file) + stream.on('open', () => { + stream.pipe(res) + }) + stream.on('error', (err) => { + res.end(err) + }) +} + exports.send = send exports.sendJS = sendJS +exports.sendJSStream = sendJSStream diff --git a/lib/vue.js b/lib/vue.js deleted file mode 100644 index 020d1a5487c2d7..00000000000000 --- a/lib/vue.js +++ /dev/null @@ -1,7459 +0,0 @@ -// Make a map and return a function for checking if a key -// is in that map. -// -// IMPORTANT: all calls of this function must be prefixed with /*#__PURE__*/ -// So that rollup can tree-shake them if necessary. -function makeMap(str, expectsLowerCase) { - const map = Object.create(null); - const list = str.split(','); - for (let i = 0; i < list.length; i++) { - map[list[i]] = true; - } - return expectsLowerCase ? val => !!map[val.toLowerCase()] : val => !!map[val]; -} - -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'; -const isGloballyWhitelisted = /*#__PURE__*/ makeMap(GLOBALS_WHITE_LISTED); - -// On the client we only need to offer special cases for boolean attributes that -// have different names from their corresponding dom properties: -// - itemscope -> N/A -// - allowfullscreen -> allowFullscreen -// - formnovalidate -> formNoValidate -// - ismap -> isMap -// - nomodule -> noModule -// - novalidate -> noValidate -// - readonly -> readOnly -const specialBooleanAttrs = `itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly`; -const isSpecialBooleanAttr = /*#__PURE__*/ makeMap(specialBooleanAttrs); - -function normalizeStyle(value) { - if (isArray(value)) { - const res = {}; - for (let i = 0; i < value.length; i++) { - const normalized = normalizeStyle(value[i]); - if (normalized) { - for (const key in normalized) { - res[key] = normalized[key]; - } - } - } - return res; - } - else if (isObject(value)) { - return value; - } -} -function normalizeClass(value) { - let res = ''; - if (isString(value)) { - res = value; - } - else if (isArray(value)) { - for (let i = 0; i < value.length; i++) { - res += normalizeClass(value[i]) + ' '; - } - } - else if (isObject(value)) { - for (const name in value) { - if (value[name]) { - res += name + ' '; - } - } - } - return res.trim(); -} - -// These tag configs are shared between compiler-dom and runtime-dom, so they -// https://developer.mozilla.org/en-US/docs/Web/HTML/Element -const HTML_TAGS = 'html,body,base,head,link,meta,style,title,address,article,aside,footer,' + - 'header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,div,dd,dl,dt,figcaption,' + - 'figure,picture,hr,img,li,main,ol,p,pre,ul,a,b,abbr,bdi,bdo,br,cite,code,' + - 'data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,s,samp,small,span,strong,sub,sup,' + - 'time,u,var,wbr,area,audio,map,track,video,embed,object,param,source,' + - 'canvas,script,noscript,del,ins,caption,col,colgroup,table,thead,tbody,td,' + - 'th,tr,button,datalist,fieldset,form,input,label,legend,meter,optgroup,' + - 'option,output,progress,select,textarea,details,dialog,menu,menuitem,' + - 'summary,content,element,shadow,template,blockquote,iframe,tfoot'; -// https://developer.mozilla.org/en-US/docs/Web/SVG/Element -const SVG_TAGS = 'svg,animate,animateMotion,animateTransform,circle,clipPath,color-profile,' + - 'defs,desc,discard,ellipse,feBlend,feColorMatrix,feComponentTransfer,' + - 'feComposite,feConvolveMatrix,feDiffuseLighting,feDisplacementMap,' + - 'feDistanceLight,feDropShadow,feFlood,feFuncA,feFuncB,feFuncG,feFuncR,' + - 'feGaussianBlur,feImage,feMerge,feMergeNode,feMorphology,feOffset,' + - 'fePointLight,feSpecularLighting,feSpotLight,feTile,feTurbulence,filter,' + - 'foreignObject,g,hatch,hatchpath,image,line,linearGradient,marker,mask,' + - 'mesh,meshgradient,meshpatch,meshrow,metadata,mpath,path,pattern,' + - 'polygon,polyline,radialGradient,rect,set,solidcolor,stop,switch,symbol,' + - 'text,textPath,title,tspan,unknown,use,view'; -const isHTMLTag = /*#__PURE__*/ makeMap(HTML_TAGS); -const isSVGTag = /*#__PURE__*/ makeMap(SVG_TAGS); - -function looseEqual(a, b) { - if (a === b) - return true; - const isObjectA = isObject(a); - const isObjectB = isObject(b); - if (isObjectA && isObjectB) { - try { - const isArrayA = isArray(a); - const isArrayB = isArray(b); - if (isArrayA && isArrayB) { - return (a.length === b.length && - a.every((e, i) => looseEqual(e, b[i]))); - } - else if (a instanceof Date && b instanceof Date) { - return a.getTime() === b.getTime(); - } - else if (!isArrayA && !isArrayB) { - const keysA = Object.keys(a); - const keysB = Object.keys(b); - return (keysA.length === keysB.length && - keysA.every(key => looseEqual(a[key], b[key]))); - } - else { - /* istanbul ignore next */ - return false; - } - } - catch (e) { - /* istanbul ignore next */ - return false; - } - } - else if (!isObjectA && !isObjectB) { - return String(a) === String(b); - } - else { - return false; - } -} -function looseIndexOf(arr, val) { - return arr.findIndex(item => looseEqual(item, val)); -} - -const EMPTY_OBJ = Object.freeze({}) - ; -const EMPTY_ARR = []; -const NOOP = () => { }; -/** - * Always return false. - */ -const NO = () => false; -const onRE = /^on[^a-z]/; -const isOn = (key) => onRE.test(key); -const extend = (a, b) => { - for (const key in b) { - a[key] = b[key]; - } - return a; -}; -const remove = (arr, el) => { - const i = arr.indexOf(el); - if (i > -1) { - arr.splice(i, 1); - } -}; -const hasOwnProperty = Object.prototype.hasOwnProperty; -const hasOwn = (val, key) => hasOwnProperty.call(val, key); -const isArray = Array.isArray; -const isFunction = (val) => typeof val === 'function'; -const isString = (val) => typeof val === 'string'; -const isSymbol = (val) => typeof val === 'symbol'; -const isObject = (val) => val !== null && typeof val === 'object'; -const isPromise = (val) => { - return isObject(val) && isFunction(val.then) && isFunction(val.catch); -}; -const objectToString = Object.prototype.toString; -const toTypeString = (value) => objectToString.call(value); -const toRawType = (value) => { - return toTypeString(value).slice(8, -1); -}; -const isPlainObject = (val) => toTypeString(val) === '[object Object]'; -const isReservedProp = /*#__PURE__*/ makeMap('key,ref,' + - 'onVnodeBeforeMount,onVnodeMounted,' + - 'onVnodeBeforeUpdate,onVnodeUpdated,' + - 'onVnodeBeforeUnmount,onVnodeUnmounted'); -const cacheStringFunction = (fn) => { - const cache = Object.create(null); - return ((str) => { - const hit = cache[str]; - return hit || (cache[str] = fn(str)); - }); -}; -const camelizeRE = /-(\w)/g; -const camelize = cacheStringFunction((str) => { - return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : '')); -}); -const hyphenateRE = /\B([A-Z])/g; -const hyphenate = cacheStringFunction((str) => { - return str.replace(hyphenateRE, '-$1').toLowerCase(); -}); -const capitalize = cacheStringFunction((str) => { - return str.charAt(0).toUpperCase() + str.slice(1); -}); -// compare whether a value has changed, accounting for NaN. -const hasChanged = (value, oldValue) => value !== oldValue && (value === value || oldValue === oldValue); -// for converting {{ interpolation }} values to displayed strings. -const toDisplayString = (val) => { - return val == null - ? '' - : isArray(val) || (isPlainObject(val) && val.toString === objectToString) - ? JSON.stringify(val, null, 2) - : String(val); -}; -const invokeArrayFns = (fns, arg) => { - for (let i = 0; i < fns.length; i++) { - fns[i](arg); - } -}; -const def = (obj, key, value) => { - Object.defineProperty(obj, key, { value }); -}; - -const targetMap = new WeakMap(); -const effectStack = []; -let activeEffect; -const ITERATE_KEY = Symbol( 'iterate' ); -const MAP_KEY_ITERATE_KEY = Symbol( 'Map key iterate' ); -function isEffect(fn) { - return fn && fn._isEffect === true; -} -function effect(fn, options = EMPTY_OBJ) { - if (isEffect(fn)) { - fn = fn.raw; - } - const effect = createReactiveEffect(fn, options); - if (!options.lazy) { - effect(); - } - return effect; -} -function stop(effect) { - if (effect.active) { - cleanup(effect); - if (effect.options.onStop) { - effect.options.onStop(); - } - effect.active = false; - } -} -let uid = 0; -function createReactiveEffect(fn, options) { - const effect = function reactiveEffect(...args) { - if (!effect.active) { - return options.scheduler ? undefined : fn(...args); - } - if (!effectStack.includes(effect)) { - cleanup(effect); - try { - enableTracking(); - effectStack.push(effect); - activeEffect = effect; - return fn(...args); - } - finally { - effectStack.pop(); - resetTracking(); - activeEffect = effectStack[effectStack.length - 1]; - } - } - }; - effect.id = uid++; - effect._isEffect = true; - effect.active = true; - effect.raw = fn; - effect.deps = []; - effect.options = options; - return effect; -} -function cleanup(effect) { - const { deps } = effect; - if (deps.length) { - for (let i = 0; i < deps.length; i++) { - deps[i].delete(effect); - } - deps.length = 0; - } -} -let shouldTrack = true; -const trackStack = []; -function pauseTracking() { - trackStack.push(shouldTrack); - shouldTrack = false; -} -function enableTracking() { - trackStack.push(shouldTrack); - shouldTrack = true; -} -function resetTracking() { - const last = trackStack.pop(); - shouldTrack = last === undefined ? true : last; -} -function track(target, type, key) { - if (!shouldTrack || activeEffect === undefined) { - return; - } - let depsMap = targetMap.get(target); - if (depsMap === void 0) { - targetMap.set(target, (depsMap = new Map())); - } - let dep = depsMap.get(key); - if (dep === void 0) { - depsMap.set(key, (dep = new Set())); - } - if (!dep.has(activeEffect)) { - dep.add(activeEffect); - activeEffect.deps.push(dep); - if ( activeEffect.options.onTrack) { - activeEffect.options.onTrack({ - effect: activeEffect, - target, - type, - key - }); - } - } -} -function trigger(target, type, key, newValue, oldValue, oldTarget) { - const depsMap = targetMap.get(target); - if (depsMap === void 0) { - // never been tracked - return; - } - const effects = new Set(); - const computedRunners = new Set(); - const add = (effectsToAdd) => { - if (effectsToAdd !== void 0) { - effectsToAdd.forEach(effect => { - if (effect !== activeEffect || !shouldTrack) { - if (effect.options.computed) { - computedRunners.add(effect); - } - else { - effects.add(effect); - } - } - }); - } - }; - if (type === "clear" /* CLEAR */) { - // collection being cleared - // trigger all effects for target - depsMap.forEach(add); - } - else if (key === 'length' && isArray(target)) { - depsMap.forEach((dep, key) => { - if (key === 'length' || key >= newValue) { - add(dep); - } - }); - } - else { - // schedule runs for SET | ADD | DELETE - if (key !== void 0) { - add(depsMap.get(key)); - } - // also run for iteration key on ADD | DELETE | Map.SET - const isAddOrDelete = type === "add" /* ADD */ || - (type === "delete" /* DELETE */ && !isArray(target)); - if (isAddOrDelete || - (type === "set" /* SET */ && target instanceof Map)) { - add(depsMap.get(isArray(target) ? 'length' : ITERATE_KEY)); - } - if (isAddOrDelete && target instanceof Map) { - add(depsMap.get(MAP_KEY_ITERATE_KEY)); - } - } - const run = (effect) => { - if ( effect.options.onTrigger) { - effect.options.onTrigger({ - effect, - target, - key, - type, - newValue, - oldValue, - oldTarget - }); - } - if (effect.options.scheduler !== void 0) { - effect.options.scheduler(effect); - } - else { - effect(); - } - }; - // Important: computed effects must be run first so that computed getters - // can be invalidated before any normal effects that depend on them are run. - computedRunners.forEach(run); - effects.forEach(run); -} - -const builtInSymbols = new Set(Object.getOwnPropertyNames(Symbol) - .map(key => Symbol[key]) - .filter(isSymbol)); -const get = /*#__PURE__*/ createGetter(); -const shallowGet = /*#__PURE__*/ createGetter(false, true); -const readonlyGet = /*#__PURE__*/ createGetter(true); -const shallowReadonlyGet = /*#__PURE__*/ createGetter(true, true); -const arrayInstrumentations = {}; -['includes', 'indexOf', 'lastIndexOf'].forEach(key => { - arrayInstrumentations[key] = function (...args) { - const arr = toRaw(this); - for (let i = 0, l = this.length; i < l; i++) { - track(arr, "get" /* GET */, i + ''); - } - // we run the method using the original args first (which may be reactive) - const res = arr[key](...args); - if (res === -1 || res === false) { - // if that didn't work, run it again using raw values. - return arr[key](...args.map(toRaw)); - } - else { - return res; - } - }; -}); -function createGetter(isReadonly = false, shallow = false) { - return function get(target, key, receiver) { - const targetIsArray = isArray(target); - if (targetIsArray && hasOwn(arrayInstrumentations, key)) { - return Reflect.get(arrayInstrumentations, key, receiver); - } - const res = Reflect.get(target, key, receiver); - if (isSymbol(key) && builtInSymbols.has(key)) { - return res; - } - if (shallow) { - !isReadonly && track(target, "get" /* GET */, key); - return res; - } - if (isRef(res)) { - if (targetIsArray) { - !isReadonly && track(target, "get" /* GET */, key); - return res; - } - else { - // ref unwrapping, only for Objects, not for Arrays. - return res.value; - } - } - !isReadonly && track(target, "get" /* GET */, key); - return isObject(res) - ? isReadonly - ? // need to lazy access readonly and reactive here to avoid - // circular dependency - readonly(res) - : reactive(res) - : res; - }; -} -const set = /*#__PURE__*/ createSetter(); -const shallowSet = /*#__PURE__*/ createSetter(true); -function createSetter(shallow = false) { - return function set(target, key, value, receiver) { - const oldValue = target[key]; - if (!shallow) { - value = toRaw(value); - if (!isArray(target) && isRef(oldValue) && !isRef(value)) { - oldValue.value = value; - return true; - } - } - const hadKey = hasOwn(target, key); - const result = Reflect.set(target, key, value, receiver); - // don't trigger if target is something up in the prototype chain of original - if (target === toRaw(receiver)) { - if (!hadKey) { - trigger(target, "add" /* ADD */, key, value); - } - else if (hasChanged(value, oldValue)) { - trigger(target, "set" /* SET */, key, value, oldValue); - } - } - return result; - }; -} -function deleteProperty(target, key) { - const hadKey = hasOwn(target, key); - const oldValue = target[key]; - const result = Reflect.deleteProperty(target, key); - if (result && hadKey) { - trigger(target, "delete" /* DELETE */, key, undefined, oldValue); - } - return result; -} -function has(target, key) { - const result = Reflect.has(target, key); - track(target, "has" /* HAS */, key); - return result; -} -function ownKeys(target) { - track(target, "iterate" /* ITERATE */, ITERATE_KEY); - return Reflect.ownKeys(target); -} -const mutableHandlers = { - get, - set, - deleteProperty, - has, - ownKeys -}; -const readonlyHandlers = { - get: readonlyGet, - has, - ownKeys, - set(target, key) { - { - console.warn(`Set operation on key "${String(key)}" failed: target is readonly.`, target); - } - return true; - }, - deleteProperty(target, key) { - { - console.warn(`Delete operation on key "${String(key)}" failed: target is readonly.`, target); - } - return true; - } -}; -const shallowReactiveHandlers = { - ...mutableHandlers, - get: shallowGet, - set: shallowSet -}; -// Props handlers are special in the sense that it should not unwrap top-level -// refs (in order to allow refs to be explicitly passed down), but should -// retain the reactivity of the normal readonly object. -const shallowReadonlyHandlers = { - ...readonlyHandlers, - get: shallowReadonlyGet -}; - -const toReactive = (value) => isObject(value) ? reactive(value) : value; -const toReadonly = (value) => isObject(value) ? readonly(value) : value; -const getProto = (v) => Reflect.getPrototypeOf(v); -function get$1(target, key, wrap) { - target = toRaw(target); - const rawKey = toRaw(key); - if (key !== rawKey) { - track(target, "get" /* GET */, key); - } - track(target, "get" /* GET */, rawKey); - const { has, get } = getProto(target); - if (has.call(target, key)) { - return wrap(get.call(target, key)); - } - else if (has.call(target, rawKey)) { - return wrap(get.call(target, rawKey)); - } -} -function has$1(key) { - const target = toRaw(this); - const rawKey = toRaw(key); - if (key !== rawKey) { - track(target, "has" /* HAS */, key); - } - track(target, "has" /* HAS */, rawKey); - const has = getProto(target).has; - return has.call(target, key) || has.call(target, rawKey); -} -function size(target) { - target = toRaw(target); - track(target, "iterate" /* ITERATE */, ITERATE_KEY); - return Reflect.get(getProto(target), 'size', target); -} -function add(value) { - value = toRaw(value); - const target = toRaw(this); - const proto = getProto(target); - const hadKey = proto.has.call(target, value); - const result = proto.add.call(target, value); - if (!hadKey) { - trigger(target, "add" /* ADD */, value, value); - } - return result; -} -function set$1(key, value) { - value = toRaw(value); - const target = toRaw(this); - const { has, get, set } = getProto(target); - let hadKey = has.call(target, key); - if (!hadKey) { - key = toRaw(key); - hadKey = has.call(target, key); - } - else { - checkIdentityKeys(target, has, key); - } - const oldValue = get.call(target, key); - const result = set.call(target, key, value); - if (!hadKey) { - trigger(target, "add" /* ADD */, key, value); - } - else if (hasChanged(value, oldValue)) { - trigger(target, "set" /* SET */, key, value, oldValue); - } - return result; -} -function deleteEntry(key) { - const target = toRaw(this); - const { has, get, delete: del } = getProto(target); - let hadKey = has.call(target, key); - if (!hadKey) { - key = toRaw(key); - hadKey = has.call(target, key); - } - else { - checkIdentityKeys(target, has, key); - } - const oldValue = get ? get.call(target, key) : undefined; - // forward the operation before queueing reactions - const result = del.call(target, key); - if (hadKey) { - trigger(target, "delete" /* DELETE */, key, undefined, oldValue); - } - return result; -} -function clear() { - const target = toRaw(this); - const hadItems = target.size !== 0; - const oldTarget = target instanceof Map - ? new Map(target) - : new Set(target) - ; - // forward the operation before queueing reactions - const result = getProto(target).clear.call(target); - if (hadItems) { - trigger(target, "clear" /* CLEAR */, undefined, undefined, oldTarget); - } - return result; -} -function createForEach(isReadonly) { - return function forEach(callback, thisArg) { - const observed = this; - const target = toRaw(observed); - const wrap = isReadonly ? toReadonly : toReactive; - !isReadonly && track(target, "iterate" /* ITERATE */, ITERATE_KEY); - // important: create sure the callback is - // 1. invoked with the reactive map as `this` and 3rd arg - // 2. the value received should be a corresponding reactive/readonly. - function wrappedCallback(value, key) { - return callback.call(observed, wrap(value), wrap(key), observed); - } - return getProto(target).forEach.call(target, wrappedCallback, thisArg); - }; -} -function createIterableMethod(method, isReadonly) { - return function (...args) { - const target = toRaw(this); - const isMap = target instanceof Map; - const isPair = method === 'entries' || (method === Symbol.iterator && isMap); - const isKeyOnly = method === 'keys' && isMap; - const innerIterator = getProto(target)[method].apply(target, args); - const wrap = isReadonly ? toReadonly : toReactive; - !isReadonly && - track(target, "iterate" /* ITERATE */, isKeyOnly ? MAP_KEY_ITERATE_KEY : ITERATE_KEY); - // return a wrapped iterator which returns observed versions of the - // values emitted from the real iterator - return { - // iterator protocol - next() { - const { value, done } = innerIterator.next(); - return done - ? { value, done } - : { - value: isPair ? [wrap(value[0]), wrap(value[1])] : wrap(value), - done - }; - }, - // iterable protocol - [Symbol.iterator]() { - return this; - } - }; - }; -} -function createReadonlyMethod(type) { - return function (...args) { - { - const key = args[0] ? `on key "${args[0]}" ` : ``; - console.warn(`${capitalize(type)} operation ${key}failed: target is readonly.`, toRaw(this)); - } - return type === "delete" /* DELETE */ ? false : this; - }; -} -const mutableInstrumentations = { - get(key) { - return get$1(this, key, toReactive); - }, - get size() { - return size(this); - }, - has: has$1, - add, - set: set$1, - delete: deleteEntry, - clear, - forEach: createForEach(false) -}; -const readonlyInstrumentations = { - get(key) { - return get$1(this, key, toReadonly); - }, - get size() { - return size(this); - }, - has: has$1, - add: createReadonlyMethod("add" /* ADD */), - set: createReadonlyMethod("set" /* SET */), - delete: createReadonlyMethod("delete" /* DELETE */), - clear: createReadonlyMethod("clear" /* CLEAR */), - forEach: createForEach(true) -}; -const iteratorMethods = ['keys', 'values', 'entries', Symbol.iterator]; -iteratorMethods.forEach(method => { - mutableInstrumentations[method] = createIterableMethod(method, false); - readonlyInstrumentations[method] = createIterableMethod(method, true); -}); -function createInstrumentationGetter(instrumentations) { - return (target, key, receiver) => Reflect.get(hasOwn(instrumentations, key) && key in target - ? instrumentations - : target, key, receiver); -} -const mutableCollectionHandlers = { - get: createInstrumentationGetter(mutableInstrumentations) -}; -const readonlyCollectionHandlers = { - get: createInstrumentationGetter(readonlyInstrumentations) -}; -function checkIdentityKeys(target, has, key) { - const rawKey = toRaw(key); - if (rawKey !== key && has.call(target, rawKey)) { - const type = toRawType(target); - console.warn(`Reactive ${type} contains both the raw and reactive ` + - `versions of the same object${type === `Map` ? `as keys` : ``}, ` + - `which can lead to inconsistencies. ` + - `Avoid differentiating between the raw and reactive versions ` + - `of an object and only use the reactive version if possible.`); - } -} - -// WeakMaps that store {raw <-> observed} pairs. -const rawToReactive = new WeakMap(); -const reactiveToRaw = new WeakMap(); -const rawToReadonly = new WeakMap(); -const readonlyToRaw = new WeakMap(); -// WeakSets for values that are marked readonly or non-reactive during -// observable creation. -const rawValues = new WeakSet(); -const collectionTypes = new Set([Set, Map, WeakMap, WeakSet]); -const isObservableType = /*#__PURE__*/ makeMap('Object,Array,Map,Set,WeakMap,WeakSet'); -const canObserve = (value) => { - return (!value._isVue && - !value._isVNode && - isObservableType(toRawType(value)) && - !rawValues.has(value) && - !Object.isFrozen(value)); -}; -function reactive(target) { - // if trying to observe a readonly proxy, return the readonly version. - if (readonlyToRaw.has(target)) { - return target; - } - return createReactiveObject(target, rawToReactive, reactiveToRaw, mutableHandlers, mutableCollectionHandlers); -} -// Return a reactive-copy of the original object, where only the root level -// properties are reactive, and does NOT unwrap refs nor recursively convert -// returned properties. -function shallowReactive(target) { - return createReactiveObject(target, rawToReactive, reactiveToRaw, shallowReactiveHandlers, mutableCollectionHandlers); -} -function readonly(target) { - return createReactiveObject(target, rawToReadonly, readonlyToRaw, readonlyHandlers, readonlyCollectionHandlers); -} -// Return a reactive-copy of the original object, where only the root level -// properties are readonly, and does NOT unwrap refs nor recursively convert -// returned properties. -// This is used for creating the props proxy object for stateful components. -function shallowReadonly(target) { - return createReactiveObject(target, rawToReadonly, readonlyToRaw, shallowReadonlyHandlers, readonlyCollectionHandlers); -} -function createReactiveObject(target, toProxy, toRaw, baseHandlers, collectionHandlers) { - if (!isObject(target)) { - { - console.warn(`value cannot be made reactive: ${String(target)}`); - } - return target; - } - // target already has corresponding Proxy - let observed = toProxy.get(target); - if (observed !== void 0) { - return observed; - } - // target is already a Proxy - if (toRaw.has(target)) { - return target; - } - // only a whitelist of value types can be observed. - if (!canObserve(target)) { - return target; - } - const handlers = collectionTypes.has(target.constructor) - ? collectionHandlers - : baseHandlers; - observed = new Proxy(target, handlers); - toProxy.set(target, observed); - toRaw.set(observed, target); - return observed; -} -function isReactive(value) { - value = readonlyToRaw.get(value) || value; - return reactiveToRaw.has(value); -} -function isReadonly(value) { - return readonlyToRaw.has(value); -} -function isProxy(value) { - return readonlyToRaw.has(value) || reactiveToRaw.has(value); -} -function toRaw(observed) { - observed = readonlyToRaw.get(observed) || observed; - return reactiveToRaw.get(observed) || observed; -} -function markRaw(value) { - rawValues.add(value); - return value; -} - -const convert = (val) => isObject(val) ? reactive(val) : val; -function isRef(r) { - return r ? r._isRef === true : false; -} -function ref(value) { - return createRef(value); -} -function shallowRef(value) { - return createRef(value, true); -} -function createRef(value, shallow = false) { - if (isRef(value)) { - return value; - } - if (!shallow) { - value = convert(value); - } - const r = { - _isRef: true, - get value() { - track(r, "get" /* GET */, 'value'); - return value; - }, - set value(newVal) { - value = shallow ? newVal : convert(newVal); - trigger(r, "set" /* SET */, 'value', { newValue: newVal } ); - } - }; - return r; -} -function unref(ref) { - return isRef(ref) ? ref.value : ref; -} -function customRef(factory) { - const { get, set } = factory(() => track(r, "get" /* GET */, 'value'), () => trigger(r, "set" /* SET */, 'value')); - const r = { - _isRef: true, - get value() { - return get(); - }, - set value(v) { - set(v); - } - }; - return r; -} -function toRefs(object) { - if ( !isProxy(object)) { - console.warn(`toRefs() expects a reactive object but received a plain one.`); - } - const ret = {}; - for (const key in object) { - ret[key] = toRef(object, key); - } - return ret; -} -function toRef(object, key) { - return { - _isRef: true, - get value() { - return object[key]; - }, - set value(newVal) { - object[key] = newVal; - } - }; -} - -function computed(getterOrOptions) { - let getter; - let setter; - if (isFunction(getterOrOptions)) { - getter = getterOrOptions; - setter = () => { - console.warn('Write operation failed: computed value is readonly'); - } - ; - } - else { - getter = getterOrOptions.get; - setter = getterOrOptions.set; - } - let dirty = true; - let value; - let computed; - const runner = effect(getter, { - lazy: true, - // mark effect as computed so that it gets priority during trigger - computed: true, - scheduler: () => { - if (!dirty) { - dirty = true; - trigger(computed, "set" /* SET */, 'value'); - } - } - }); - computed = { - _isRef: true, - // expose effect so computed can be stopped - effect: runner, - get value() { - if (dirty) { - value = runner(); - dirty = false; - } - track(computed, "get" /* GET */, 'value'); - return value; - }, - set value(newValue) { - setter(newValue); - } - }; - return computed; -} - -const stack = []; -function pushWarningContext(vnode) { - stack.push(vnode); -} -function popWarningContext() { - stack.pop(); -} -function warn(msg, ...args) { - // avoid props formatting or warn handler tracking deps that might be mutated - // during patch, leading to infinite recursion. - pauseTracking(); - const instance = stack.length ? stack[stack.length - 1].component : null; - const appWarnHandler = instance && instance.appContext.config.warnHandler; - const trace = getComponentTrace(); - if (appWarnHandler) { - callWithErrorHandling(appWarnHandler, instance, 11 /* APP_WARN_HANDLER */, [ - msg + args.join(''), - instance && instance.proxy, - trace - .map(({ vnode }) => `at <${formatComponentName(vnode.type)}>`) - .join('\n'), - trace - ]); - } - else { - const warnArgs = [`[Vue warn]: ${msg}`, ...args]; - if (trace.length && - // avoid spamming console during tests - !false) { - warnArgs.push(`\n`, ...formatTrace(trace)); - } - console.warn(...warnArgs); - } - resetTracking(); -} -function getComponentTrace() { - let currentVNode = stack[stack.length - 1]; - if (!currentVNode) { - return []; - } - // we can't just use the stack because it will be incomplete during updates - // that did not start from the root. Re-construct the parent chain using - // instance parent pointers. - const normalizedStack = []; - while (currentVNode) { - const last = normalizedStack[0]; - if (last && last.vnode === currentVNode) { - last.recurseCount++; - } - else { - normalizedStack.push({ - vnode: currentVNode, - recurseCount: 0 - }); - } - const parentInstance = currentVNode.component - .parent; - currentVNode = parentInstance && parentInstance.vnode; - } - return normalizedStack; -} -function formatTrace(trace) { - const logs = []; - trace.forEach((entry, i) => { - logs.push(...(i === 0 ? [] : [`\n`]), ...formatTraceEntry(entry)); - }); - return logs; -} -function formatTraceEntry({ vnode, recurseCount }) { - const postfix = recurseCount > 0 ? `... (${recurseCount} recursive calls)` : ``; - const open = ` at <${formatComponentName(vnode)}`; - const close = `>` + postfix; - const rootLabel = vnode.component.parent == null ? `(Root)` : ``; - return vnode.props - ? [open, ...formatProps(vnode.props), close, rootLabel] - : [open + close, rootLabel]; -} -function formatProps(props) { - const res = []; - const keys = Object.keys(props); - keys.slice(0, 3).forEach(key => { - res.push(...formatProp(key, props[key])); - }); - if (keys.length > 3) { - res.push(` ...`); - } - return res; -} -function formatProp(key, value, raw) { - if (isString(value)) { - value = JSON.stringify(value); - return raw ? value : [`${key}=${value}`]; - } - else if (typeof value === 'number' || - typeof value === 'boolean' || - value == null) { - return raw ? value : [`${key}=${value}`]; - } - else if (isRef(value)) { - value = formatProp(key, toRaw(value.value), true); - return raw ? value : [`${key}=Ref<`, value, `>`]; - } - else if (isFunction(value)) { - return [`${key}=fn${value.name ? `<${value.name}>` : ``}`]; - } - else { - value = toRaw(value); - return raw ? value : [`${key}=`, value]; - } -} - -const ErrorTypeStrings = { - ["bc" /* BEFORE_CREATE */]: 'beforeCreate hook', - ["c" /* CREATED */]: 'created hook', - ["bm" /* BEFORE_MOUNT */]: 'beforeMount hook', - ["m" /* MOUNTED */]: 'mounted hook', - ["bu" /* BEFORE_UPDATE */]: 'beforeUpdate hook', - ["u" /* UPDATED */]: 'updated', - ["bum" /* BEFORE_UNMOUNT */]: 'beforeUnmount hook', - ["um" /* UNMOUNTED */]: 'unmounted hook', - ["a" /* ACTIVATED */]: 'activated hook', - ["da" /* DEACTIVATED */]: 'deactivated hook', - ["ec" /* ERROR_CAPTURED */]: 'errorCaptured hook', - ["rtc" /* RENDER_TRACKED */]: 'renderTracked hook', - ["rtg" /* RENDER_TRIGGERED */]: 'renderTriggered hook', - [0 /* SETUP_FUNCTION */]: 'setup function', - [1 /* RENDER_FUNCTION */]: 'render function', - [2 /* WATCH_GETTER */]: 'watcher getter', - [3 /* WATCH_CALLBACK */]: 'watcher callback', - [4 /* WATCH_CLEANUP */]: 'watcher cleanup function', - [5 /* NATIVE_EVENT_HANDLER */]: 'native event handler', - [6 /* COMPONENT_EVENT_HANDLER */]: 'component event handler', - [7 /* VNODE_HOOK */]: 'vnode hook', - [8 /* DIRECTIVE_HOOK */]: 'directive hook', - [9 /* TRANSITION_HOOK */]: 'transition hook', - [10 /* APP_ERROR_HANDLER */]: 'app errorHandler', - [11 /* APP_WARN_HANDLER */]: 'app warnHandler', - [12 /* FUNCTION_REF */]: 'ref function', - [13 /* ASYNC_COMPONENT_LOADER */]: 'async component loader', - [14 /* SCHEDULER */]: 'scheduler flush. This is likely a Vue internals bug. ' + - 'Please open an issue at https://new-issue.vuejs.org/?repo=vuejs/vue-next' -}; -function callWithErrorHandling(fn, instance, type, args) { - let res; - try { - res = args ? fn(...args) : fn(); - } - catch (err) { - handleError(err, instance, type); - } - return res; -} -function callWithAsyncErrorHandling(fn, instance, type, args) { - if (isFunction(fn)) { - const res = callWithErrorHandling(fn, instance, type, args); - if (res && !res._isVue && isPromise(res)) { - res.catch(err => { - handleError(err, instance, type); - }); - } - return res; - } - const values = []; - for (let i = 0; i < fn.length; i++) { - values.push(callWithAsyncErrorHandling(fn[i], instance, type, args)); - } - return values; -} -function handleError(err, instance, type) { - const contextVNode = instance ? instance.vnode : null; - if (instance) { - let cur = instance.parent; - // the exposed instance is the render proxy to keep it consistent with 2.x - const exposedInstance = instance.proxy; - // in production the hook receives only the error code - const errorInfo = ErrorTypeStrings[type] ; - while (cur) { - const errorCapturedHooks = cur.ec; - if (errorCapturedHooks) { - for (let i = 0; i < errorCapturedHooks.length; i++) { - if (errorCapturedHooks[i](err, exposedInstance, errorInfo)) { - return; - } - } - } - cur = cur.parent; - } - // app-level handling - const appErrorHandler = instance.appContext.config.errorHandler; - if (appErrorHandler) { - callWithErrorHandling(appErrorHandler, null, 10 /* APP_ERROR_HANDLER */, [err, exposedInstance, errorInfo]); - return; - } - } - logError(err, type, contextVNode); -} -function logError(err, type, contextVNode) { - // default behavior is crash in prod & test, recover in dev. - { - const info = ErrorTypeStrings[type]; - if (contextVNode) { - pushWarningContext(contextVNode); - } - warn(`Unhandled error${info ? ` during execution of ${info}` : ``}`); - console.error(err); - if (contextVNode) { - popWarningContext(); - } - } -} - -const queue = []; -const postFlushCbs = []; -const p = Promise.resolve(); -let isFlushing = false; -let isFlushPending = false; -const RECURSION_LIMIT = 100; -function nextTick(fn) { - return fn ? p.then(fn) : p; -} -function queueJob(job) { - if (!queue.includes(job)) { - queue.push(job); - queueFlush(); - } -} -function invalidateJob(job) { - const i = queue.indexOf(job); - if (i > -1) { - queue[i] = null; - } -} -function queuePostFlushCb(cb) { - if (!isArray(cb)) { - postFlushCbs.push(cb); - } - else { - postFlushCbs.push(...cb); - } - queueFlush(); -} -function queueFlush() { - if (!isFlushing && !isFlushPending) { - isFlushPending = true; - nextTick(flushJobs); - } -} -function flushPostFlushCbs(seen) { - if (postFlushCbs.length) { - const cbs = [...new Set(postFlushCbs)]; - postFlushCbs.length = 0; - { - seen = seen || new Map(); - } - for (let i = 0; i < cbs.length; i++) { - { - checkRecursiveUpdates(seen, cbs[i]); - } - cbs[i](); - } - } -} -const getId = (job) => (job.id == null ? Infinity : job.id); -function flushJobs(seen) { - isFlushPending = false; - isFlushing = true; - let job; - { - seen = seen || new Map(); - } - // Sort queue before flush. - // This ensures that: - // 1. Components are updated from parent to child. (because parent is always - // created before the child so its render effect will have smaller - // priority number) - // 2. If a component is unmounted during a parent component's update, - // its update can be skipped. - // Jobs can never be null before flush starts, since they are only invalidated - // during execution of another flushed job. - queue.sort((a, b) => getId(a) - getId(b)); - while ((job = queue.shift()) !== undefined) { - if (job === null) { - continue; - } - { - checkRecursiveUpdates(seen, job); - } - callWithErrorHandling(job, null, 14 /* SCHEDULER */); - } - flushPostFlushCbs(seen); - isFlushing = false; - // some postFlushCb queued jobs! - // keep flushing until it drains. - if (queue.length || postFlushCbs.length) { - flushJobs(seen); - } -} -function checkRecursiveUpdates(seen, fn) { - if (!seen.has(fn)) { - seen.set(fn, 1); - } - else { - const count = seen.get(fn); - if (count > RECURSION_LIMIT) { - throw new Error('Maximum recursive updates exceeded. ' + - "You may have code that is mutating state in your component's " + - 'render function or updated hook or watcher source function.'); - } - else { - seen.set(fn, count + 1); - } - } -} - -// mark the current rendering instance for asset resolution (e.g. -// resolveComponent, resolveDirective) during render -let currentRenderingInstance = null; -function setCurrentRenderingInstance(instance) { - currentRenderingInstance = instance; -} -// dev only flag to track whether $attrs was used during render. -// If $attrs was used during render then the warning for failed attrs -// fallthrough can be suppressed. -let accessedAttrs = false; -function markAttrsAccessed() { - accessedAttrs = true; -} -function renderComponentRoot(instance) { - const { type: Component, parent, vnode, proxy, withProxy, props, slots, attrs, emit, renderCache } = instance; - let result; - currentRenderingInstance = instance; - { - accessedAttrs = false; - } - try { - let fallthroughAttrs; - if (vnode.shapeFlag & 4 /* STATEFUL_COMPONENT */) { - // withProxy is a proxy with a different `has` trap only for - // runtime-compiled render functions using `with` block. - const proxyToUse = withProxy || proxy; - result = normalizeVNode(instance.render.call(proxyToUse, proxyToUse, renderCache)); - fallthroughAttrs = attrs; - } - else { - // functional - const render = Component; - result = normalizeVNode(render.length > 1 - ? render(props, { - attrs, - slots, - emit - }) - : render(props, null /* we know it doesn't need it */)); - fallthroughAttrs = Component.props ? attrs : getFallthroughAttrs(attrs); - } - // attr merging - // in dev mode, comments are preserved, and it's possible for a template - // to have comments along side the root element which makes it a fragment - let root = result; - let setRoot = undefined; - if (true) { - ; - [root, setRoot] = getChildRoot(result); - } - if (Component.inheritAttrs !== false && - fallthroughAttrs && - Object.keys(fallthroughAttrs).length) { - if (root.shapeFlag & 1 /* ELEMENT */ || - root.shapeFlag & 6 /* COMPONENT */) { - root = cloneVNode(root, fallthroughAttrs); - // If the child root node is a compiler optimized vnode, make sure it - // force update full props to account for the merged attrs. - if (root.dynamicChildren) { - root.patchFlag |= 16 /* FULL_PROPS */; - } - } - else if (true && !accessedAttrs && root.type !== Comment) { - warn(`Extraneous non-props attributes (` + - `${Object.keys(attrs).join(', ')}) ` + - `were passed to component but could not be automatically inherited ` + - `because component renders fragment or text root nodes.`); - } - } - // inherit scopeId - const parentScopeId = parent && parent.type.__scopeId; - if (parentScopeId) { - root = cloneVNode(root, { [parentScopeId]: '' }); - } - // inherit directives - if (vnode.dirs) { - if (true && !isElementRoot(root)) { - warn(`Runtime directive used on component with non-element root node. ` + - `The directives will not function as intended.`); - } - root.dirs = vnode.dirs; - } - // inherit transition data - if (vnode.transition) { - if (true && !isElementRoot(root)) { - warn(`Component inside renders non-element root node ` + - `that cannot be animated.`); - } - root.transition = vnode.transition; - } - if (true && setRoot) { - setRoot(root); - } - else { - result = root; - } - } - catch (err) { - handleError(err, instance, 1 /* RENDER_FUNCTION */); - result = createVNode(Comment); - } - currentRenderingInstance = null; - return result; -} -const getChildRoot = (vnode) => { - if (vnode.type !== Fragment) { - return [vnode, undefined]; - } - const rawChildren = vnode.children; - const dynamicChildren = vnode.dynamicChildren; - const children = rawChildren.filter(child => { - return !(isVNode(child) && child.type === Comment); - }); - if (children.length !== 1) { - return [vnode, undefined]; - } - const childRoot = children[0]; - const index = rawChildren.indexOf(childRoot); - const dynamicIndex = dynamicChildren - ? dynamicChildren.indexOf(childRoot) - : null; - const setRoot = (updatedRoot) => { - rawChildren[index] = updatedRoot; - if (dynamicIndex !== null) - dynamicChildren[dynamicIndex] = updatedRoot; - }; - return [normalizeVNode(childRoot), setRoot]; -}; -const getFallthroughAttrs = (attrs) => { - let res; - for (const key in attrs) { - if (key === 'class' || key === 'style' || isOn(key)) { - (res || (res = {}))[key] = attrs[key]; - } - } - return res; -}; -const isElementRoot = (vnode) => { - return (vnode.shapeFlag & 6 /* COMPONENT */ || - vnode.shapeFlag & 1 /* ELEMENT */ || - vnode.type === Comment // potential v-if branch switch - ); -}; -function shouldUpdateComponent(prevVNode, nextVNode, parentComponent, optimized) { - const { props: prevProps, children: prevChildren } = prevVNode; - const { props: nextProps, children: nextChildren, patchFlag } = nextVNode; - // Parent component's render function was hot-updated. Since this may have - // caused the child component's slots content to have changed, we need to - // force the child to update as well. - if ( - (prevChildren || nextChildren) && - parentComponent && - parentComponent.renderUpdated) { - return true; - } - // force child update for runtime directive or transition on component vnode. - if (nextVNode.dirs || nextVNode.transition) { - return true; - } - if (patchFlag > 0) { - if (patchFlag & 1024 /* DYNAMIC_SLOTS */) { - // slot content that references values that might have changed, - // e.g. in a v-for - return true; - } - if (patchFlag & 16 /* FULL_PROPS */) { - // presence of this flag indicates props are always non-null - return hasPropsChanged(prevProps, nextProps); - } - else if (patchFlag & 8 /* PROPS */) { - const dynamicProps = nextVNode.dynamicProps; - for (let i = 0; i < dynamicProps.length; i++) { - const key = dynamicProps[i]; - if (nextProps[key] !== prevProps[key]) { - return true; - } - } - } - } - else if (!optimized) { - // this path is only taken by manually written render functions - // so presence of any children leads to a forced update - if (prevChildren || nextChildren) { - if (!nextChildren || !nextChildren.$stable) { - return true; - } - } - if (prevProps === nextProps) { - return false; - } - if (!prevProps) { - return !!nextProps; - } - if (!nextProps) { - return true; - } - return hasPropsChanged(prevProps, nextProps); - } - return false; -} -function hasPropsChanged(prevProps, nextProps) { - const nextKeys = Object.keys(nextProps); - if (nextKeys.length !== Object.keys(prevProps).length) { - return true; - } - for (let i = 0; i < nextKeys.length; i++) { - const key = nextKeys[i]; - if (nextProps[key] !== prevProps[key]) { - return true; - } - } - return false; -} -function updateHOCHostEl({ vnode, parent }, el // HostNode -) { - while (parent && parent.subTree === vnode) { - (vnode = parent.vnode).el = el; - parent = parent.parent; - } -} - -const isSuspense = (type) => type.__isSuspense; -// Suspense exposes a component-like API, and is treated like a component -// in the compiler, but internally it's a special built-in type that hooks -// directly into the renderer. -const SuspenseImpl = { - // In order to make Suspense tree-shakable, we need to avoid importing it - // directly in the renderer. The renderer checks for the __isSuspense flag - // on a vnode's type and calls the `process` method, passing in renderer - // internals. - __isSuspense: true, - process(n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized, - // platform-specific impl passed from renderer - rendererInternals) { - if (n1 == null) { - mountSuspense(n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized, rendererInternals); - } - else { - patchSuspense(n1, n2, container, anchor, parentComponent, isSVG, optimized, rendererInternals); - } - }, - hydrate: hydrateSuspense -}; -// Force-casted public typing for h and TSX props inference -const Suspense = ( SuspenseImpl - ); -function mountSuspense(n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized, rendererInternals) { - const { p: patch, o: { createElement } } = rendererInternals; - const hiddenContainer = createElement('div'); - const suspense = (n2.suspense = createSuspenseBoundary(n2, parentSuspense, parentComponent, container, hiddenContainer, anchor, isSVG, optimized, rendererInternals)); - // start mounting the content subtree in an off-dom container - patch(null, suspense.subTree, hiddenContainer, null, parentComponent, suspense, isSVG, optimized); - // now check if we have encountered any async deps - if (suspense.deps > 0) { - // mount the fallback tree - patch(null, suspense.fallbackTree, container, anchor, parentComponent, null, // fallback tree will not have suspense context - isSVG, optimized); - n2.el = suspense.fallbackTree.el; - } - else { - // Suspense has no async deps. Just resolve. - suspense.resolve(); - } -} -function patchSuspense(n1, n2, container, anchor, parentComponent, isSVG, optimized, { p: patch }) { - const suspense = (n2.suspense = n1.suspense); - suspense.vnode = n2; - const { content, fallback } = normalizeSuspenseChildren(n2); - const oldSubTree = suspense.subTree; - const oldFallbackTree = suspense.fallbackTree; - if (!suspense.isResolved) { - patch(oldSubTree, content, suspense.hiddenContainer, null, parentComponent, suspense, isSVG, optimized); - if (suspense.deps > 0) { - // still pending. patch the fallback tree. - patch(oldFallbackTree, fallback, container, anchor, parentComponent, null, // fallback tree will not have suspense context - isSVG, optimized); - n2.el = fallback.el; - } - // If deps somehow becomes 0 after the patch it means the patch caused an - // async dep component to unmount and removed its dep. It will cause the - // suspense to resolve and we don't need to do anything here. - } - else { - // just normal patch inner content as a fragment - patch(oldSubTree, content, container, anchor, parentComponent, suspense, isSVG, optimized); - n2.el = content.el; - } - suspense.subTree = content; - suspense.fallbackTree = fallback; -} -function createSuspenseBoundary(vnode, parent, parentComponent, container, hiddenContainer, anchor, isSVG, optimized, rendererInternals, isHydrating = false) { - const { p: patch, m: move, um: unmount, n: next, o: { parentNode } } = rendererInternals; - const getCurrentTree = () => suspense.isResolved || suspense.isHydrating - ? suspense.subTree - : suspense.fallbackTree; - const { content, fallback } = normalizeSuspenseChildren(vnode); - const suspense = { - vnode, - parent, - parentComponent, - isSVG, - optimized, - container, - hiddenContainer, - anchor, - deps: 0, - subTree: content, - fallbackTree: fallback, - isHydrating, - isResolved: false, - isUnmounted: false, - effects: [], - resolve() { - { - if (suspense.isResolved) { - throw new Error(`resolveSuspense() is called on an already resolved suspense boundary.`); - } - if (suspense.isUnmounted) { - throw new Error(`resolveSuspense() is called on an already unmounted suspense boundary.`); - } - } - const { vnode, subTree, fallbackTree, effects, parentComponent, container } = suspense; - if (suspense.isHydrating) { - suspense.isHydrating = false; - } - else { - // this is initial anchor on mount - let { anchor } = suspense; - // unmount fallback tree - if (fallbackTree.el) { - // if the fallback tree was mounted, it may have been moved - // as part of a parent suspense. get the latest anchor for insertion - anchor = next(fallbackTree); - unmount(fallbackTree, parentComponent, suspense, true); - } - // move content from off-dom container to actual container - move(subTree, container, anchor, 0 /* ENTER */); - } - const el = (vnode.el = subTree.el); - // suspense as the root node of a component... - if (parentComponent && parentComponent.subTree === vnode) { - parentComponent.vnode.el = el; - updateHOCHostEl(parentComponent, el); - } - // check if there is a pending parent suspense - let parent = suspense.parent; - let hasUnresolvedAncestor = false; - while (parent) { - if (!parent.isResolved) { - // found a pending parent suspense, merge buffered post jobs - // into that parent - parent.effects.push(...effects); - hasUnresolvedAncestor = true; - break; - } - parent = parent.parent; - } - // no pending parent suspense, flush all jobs - if (!hasUnresolvedAncestor) { - queuePostFlushCb(effects); - } - suspense.isResolved = true; - suspense.effects = []; - // invoke @resolve event - const onResolve = vnode.props && vnode.props.onResolve; - if (isFunction(onResolve)) { - onResolve(); - } - }, - recede() { - suspense.isResolved = false; - const { vnode, subTree, fallbackTree, parentComponent, container, hiddenContainer, isSVG, optimized } = suspense; - // move content tree back to the off-dom container - const anchor = next(subTree); - move(subTree, hiddenContainer, null, 1 /* LEAVE */); - // remount the fallback tree - patch(null, fallbackTree, container, anchor, parentComponent, null, // fallback tree will not have suspense context - isSVG, optimized); - const el = (vnode.el = fallbackTree.el); - // suspense as the root node of a component... - if (parentComponent && parentComponent.subTree === vnode) { - parentComponent.vnode.el = el; - updateHOCHostEl(parentComponent, el); - } - // invoke @recede event - const onRecede = vnode.props && vnode.props.onRecede; - if (isFunction(onRecede)) { - onRecede(); - } - }, - move(container, anchor, type) { - move(getCurrentTree(), container, anchor, type); - suspense.container = container; - }, - next() { - return next(getCurrentTree()); - }, - registerDep(instance, setupRenderEffect) { - // suspense is already resolved, need to recede. - // use queueJob so it's handled synchronously after patching the current - // suspense tree - if (suspense.isResolved) { - queueJob(() => { - suspense.recede(); - }); - } - const hydratedEl = instance.vnode.el; - suspense.deps++; - instance - .asyncDep.catch(err => { - handleError(err, instance, 0 /* SETUP_FUNCTION */); - }) - .then(asyncSetupResult => { - // retry when the setup() promise resolves. - // component may have been unmounted before resolve. - if (instance.isUnmounted || suspense.isUnmounted) { - return; - } - suspense.deps--; - // retry from this component - instance.asyncResolved = true; - const { vnode } = instance; - { - pushWarningContext(vnode); - } - handleSetupResult(instance, asyncSetupResult); - if (hydratedEl) { - // vnode may have been replaced if an update happened before the - // async dep is reoslved. - vnode.el = hydratedEl; - } - setupRenderEffect(instance, vnode, - // component may have been moved before resolve. - // if this is not a hydration, instance.subTree will be the comment - // placeholder. - hydratedEl - ? parentNode(hydratedEl) - : parentNode(instance.subTree.el), - // anchor will not be used if this is hydration, so only need to - // consider the comment placeholder case. - hydratedEl ? null : next(instance.subTree), suspense, isSVG, optimized); - updateHOCHostEl(instance, vnode.el); - { - popWarningContext(); - } - if (suspense.deps === 0) { - suspense.resolve(); - } - }); - }, - unmount(parentSuspense, doRemove) { - suspense.isUnmounted = true; - unmount(suspense.subTree, parentComponent, parentSuspense, doRemove); - if (!suspense.isResolved) { - unmount(suspense.fallbackTree, parentComponent, parentSuspense, doRemove); - } - } - }; - return suspense; -} -function hydrateSuspense(node, vnode, parentComponent, parentSuspense, isSVG, optimized, rendererInternals, hydrateNode) { - const suspense = (vnode.suspense = createSuspenseBoundary(vnode, parentSuspense, parentComponent, node.parentNode, document.createElement('div'), null, isSVG, optimized, rendererInternals, true /* hydrating */)); - // there are two possible scenarios for server-rendered suspense: - // - success: ssr content should be fully resolved - // - failure: ssr content should be the fallback branch. - // however, on the client we don't really know if it has failed or not - // attempt to hydrate the DOM assuming it has succeeded, but we still - // need to construct a suspense boundary first - const result = hydrateNode(node, suspense.subTree, parentComponent, suspense, optimized); - if (suspense.deps === 0) { - suspense.resolve(); - } - return result; -} -function normalizeSuspenseChildren(vnode) { - const { shapeFlag, children } = vnode; - if (shapeFlag & 32 /* SLOTS_CHILDREN */) { - const { default: d, fallback } = children; - return { - content: normalizeVNode(isFunction(d) ? d() : d), - fallback: normalizeVNode(isFunction(fallback) ? fallback() : fallback) - }; - } - else { - return { - content: normalizeVNode(children), - fallback: normalizeVNode(null) - }; - } -} -function queueEffectWithSuspense(fn, suspense) { - if (suspense && !suspense.isResolved) { - if (isArray(fn)) { - suspense.effects.push(...fn); - } - else { - suspense.effects.push(fn); - } - } - else { - queuePostFlushCb(fn); - } -} - -function withCtx(fn, ctx = currentRenderingInstance) { - if (!ctx) - return fn; - return function renderFnWithContext() { - const owner = currentRenderingInstance; - setCurrentRenderingInstance(ctx); - const res = fn.apply(null, arguments); - setCurrentRenderingInstance(owner); - return res; - }; -} - -// SFC scoped style ID management. -let currentScopeId = null; -const scopeIdStack = []; -function pushScopeId(id) { - scopeIdStack.push((currentScopeId = id)); -} -function popScopeId() { - scopeIdStack.pop(); - currentScopeId = scopeIdStack[scopeIdStack.length - 1] || null; -} -function withScopeId(id) { - return ((fn) => withCtx(function () { - pushScopeId(id); - const res = fn.apply(this, arguments); - popScopeId(); - return res; - })); -} - -const isTeleport = (type) => type.__isTeleport; -const isTeleportDisabled = (props) => props && (props.disabled || props.disabled === ''); -const resolveTarget = (props, select) => { - const targetSelector = props && props.to; - if (isString(targetSelector)) { - if (!select) { - - warn(`Current renderer does not support string target for Teleports. ` + - `(missing querySelector renderer option)`); - return null; - } - else { - const target = select(targetSelector); - if (!target) { - - warn(`Failed to locate Teleport target with selector "${targetSelector}".`); - } - return target; - } - } - else { - if ( !targetSelector) { - warn(`Invalid Teleport target: ${targetSelector}`); - } - return targetSelector; - } -}; -const TeleportImpl = { - __isTeleport: true, - process(n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized, internals) { - const { mc: mountChildren, pc: patchChildren, pbc: patchBlockChildren, o: { insert, querySelector, createText, createComment } } = internals; - const disabled = isTeleportDisabled(n2.props); - const { shapeFlag, children } = n2; - if (n1 == null) { - // insert anchors in the main view - const placeholder = (n2.el = createComment('teleport start') - ); - const mainAnchor = (n2.anchor = createComment('teleport end') - ); - insert(placeholder, container, anchor); - insert(mainAnchor, container, anchor); - const target = (n2.target = resolveTarget(n2.props, querySelector)); - const targetAnchor = (n2.targetAnchor = createText('')); - if (target) { - insert(targetAnchor, target); - } - else { - warn('Invalid Teleport target on mount:', target, `(${typeof target})`); - } - const mount = (container, anchor) => { - // Teleport *always* has Array children. This is enforced in both the - // compiler and vnode children normalization. - if (shapeFlag & 16 /* ARRAY_CHILDREN */) { - mountChildren(children, container, anchor, parentComponent, parentSuspense, isSVG, optimized); - } - }; - if (disabled) { - mount(container, mainAnchor); - } - else if (target) { - mount(target, targetAnchor); - } - } - else { - // update content - n2.el = n1.el; - const mainAnchor = (n2.anchor = n1.anchor); - const target = (n2.target = n1.target); - const targetAnchor = (n2.targetAnchor = n1.targetAnchor); - const wasDisabled = isTeleportDisabled(n1.props); - const currentContainer = wasDisabled ? container : target; - const currentAnchor = wasDisabled ? mainAnchor : targetAnchor; - if (n2.dynamicChildren) { - // fast path when the teleport happens to be a block root - patchBlockChildren(n1.dynamicChildren, n2.dynamicChildren, currentContainer, parentComponent, parentSuspense, isSVG); - } - else if (!optimized) { - patchChildren(n1, n2, currentContainer, currentAnchor, parentComponent, parentSuspense, isSVG); - } - if (disabled) { - if (!wasDisabled) { - // enabled -> disabled - // move into main container - moveTeleport(n2, container, mainAnchor, internals, 1 /* TOGGLE */); - } - } - else { - // target changed - if ((n2.props && n2.props.to) !== (n1.props && n1.props.to)) { - const nextTarget = (n2.target = resolveTarget(n2.props, querySelector)); - if (nextTarget) { - moveTeleport(n2, nextTarget, null, internals, 0 /* TARGET_CHANGE */); - } - else { - warn('Invalid Teleport target on update:', target, `(${typeof target})`); - } - } - else if (wasDisabled) { - // disabled -> enabled - // move into teleport target - moveTeleport(n2, target, targetAnchor, internals, 1 /* TOGGLE */); - } - } - } - }, - remove(vnode, { r: remove, o: { remove: hostRemove } }) { - const { shapeFlag, children, anchor } = vnode; - hostRemove(anchor); - if (shapeFlag & 16 /* ARRAY_CHILDREN */) { - for (let i = 0; i < children.length; i++) { - remove(children[i]); - } - } - }, - move: moveTeleport, - hydrate: hydrateTeleport -}; -function moveTeleport(vnode, container, parentAnchor, { o: { insert }, m: move }, moveType = 2 /* REORDER */) { - // move target anchor if this is a target change. - if (moveType === 0 /* TARGET_CHANGE */) { - insert(vnode.targetAnchor, container, parentAnchor); - } - const { el, anchor, shapeFlag, children, props } = vnode; - const isReorder = moveType === 2 /* REORDER */; - // move main view anchor if this is a re-order. - if (isReorder) { - insert(el, container, parentAnchor); - } - // if this is a re-order and teleport is enabled (content is in target) - // do not move children. So the opposite is: only move children if this - // is not a reorder, or the teleport is disabled - if (!isReorder || isTeleportDisabled(props)) { - // Teleport has either Array children or no children. - if (shapeFlag & 16 /* ARRAY_CHILDREN */) { - for (let i = 0; i < children.length; i++) { - move(children[i], container, parentAnchor, 2 /* REORDER */); - } - } - } - // move main view anchor if this is a re-order. - if (isReorder) { - insert(anchor, container, parentAnchor); - } -} -function hydrateTeleport(node, vnode, parentComponent, parentSuspense, optimized, { o: { nextSibling, parentNode, querySelector } }, hydrateChildren) { - const target = (vnode.target = resolveTarget(vnode.props, querySelector)); - if (target) { - // if multiple teleports rendered to the same target element, we need to - // pick up from where the last teleport finished instead of the first node - const targetNode = target._lpa || target.firstChild; - if (vnode.shapeFlag & 16 /* ARRAY_CHILDREN */) { - if (isTeleportDisabled(vnode.props)) { - vnode.anchor = hydrateChildren(nextSibling(node), vnode, parentNode(node), parentComponent, parentSuspense, optimized); - vnode.targetAnchor = targetNode; - } - else { - vnode.anchor = nextSibling(node); - vnode.targetAnchor = hydrateChildren(targetNode, vnode, target, parentComponent, parentSuspense, optimized); - } - target._lpa = nextSibling(vnode.targetAnchor); - } - } - return vnode.anchor && nextSibling(vnode.anchor); -} -// Force-casted public typing for h and TSX props inference -const Teleport = TeleportImpl; - -const Fragment = Symbol( 'Fragment' ); -const Text = Symbol( 'Text' ); -const Comment = Symbol( 'Comment' ); -const Static = Symbol( 'Static' ); -// Since v-if and v-for are the two possible ways node structure can dynamically -// change, once we consider v-if branches and each v-for fragment a block, we -// can divide a template into nested blocks, and within each block the node -// structure would be stable. This allows us to skip most children diffing -// and only worry about the dynamic nodes (indicated by patch flags). -const blockStack = []; -let currentBlock = null; -// Open a block. -// This must be called before `createBlock`. It cannot be part of `createBlock` -// because the children of the block are evaluated before `createBlock` itself -// is called. The generated code typically looks like this: -// -// function render() { -// return (openBlock(),createBlock('div', null, [...])) -// } -// -// disableTracking is true when creating a fragment block, since a fragment -// always diffs its children. -function openBlock(disableTracking = false) { - blockStack.push((currentBlock = disableTracking ? null : [])); -} -// Whether we should be tracking dynamic child nodes inside a block. -// Only tracks when this value is > 0 -// We are not using a simple boolean because this value may need to be -// incremented/decremented by nested usage of v-once (see below) -let shouldTrack$1 = 1; -// Block tracking sometimes needs to be disabled, for example during the -// creation of a tree that needs to be cached by v-once. The compiler generates -// code like this: -// _cache[1] || ( -// setBlockTracking(-1), -// _cache[1] = createVNode(...), -// setBlockTracking(1), -// _cache[1] -// ) -function setBlockTracking(value) { - shouldTrack$1 += value; -} -// Create a block root vnode. Takes the same exact arguments as `createVNode`. -// A block root keeps track of dynamic nodes within the block in the -// `dynamicChildren` array. -function createBlock(type, props, children, patchFlag, dynamicProps) { - // avoid a block with patchFlag tracking itself - shouldTrack$1--; - const vnode = createVNode(type, props, children, patchFlag, dynamicProps); - shouldTrack$1++; - // save current block children on the block vnode - vnode.dynamicChildren = currentBlock || EMPTY_ARR; - // close block - blockStack.pop(); - currentBlock = blockStack[blockStack.length - 1] || null; - // a block is always going to be patched, so track it as a child of its - // parent block - if (currentBlock) { - currentBlock.push(vnode); - } - return vnode; -} -function isVNode(value) { - return value ? value._isVNode === true : false; -} -function isSameVNodeType(n1, n2) { - if ( - n2.shapeFlag & 6 /* COMPONENT */ && - n2.type.__hmrUpdated) { - // HMR only: if the component has been hot-updated, force a reload. - return false; - } - return n1.type === n2.type && n1.key === n2.key; -} -let vnodeArgsTransformer; -// Internal API for registering an arguments transform for createVNode -// used for creating stubs in the test-utils -function transformVNodeArgs(transformer) { - vnodeArgsTransformer = transformer; -} -const createVNodeWithArgsTransform = (...args) => { - return _createVNode(...(vnodeArgsTransformer - ? vnodeArgsTransformer(args, currentRenderingInstance) - : args)); -}; -const InternalObjectKey = `__vInternal`; -const createVNode = ( createVNodeWithArgsTransform - ); -function _createVNode(type, props = null, children = null, patchFlag = 0, dynamicProps = null) { - if (!type) { - { - warn(`Invalid vnode type when creating vnode: ${type}.`); - } - type = Comment; - } - // class component normalization. - if (isFunction(type) && '__vccOpts' in type) { - type = type.__vccOpts; - } - // class & style normalization. - if (props) { - // for reactive or proxy objects, we need to clone it to enable mutation. - if (isProxy(props) || InternalObjectKey in props) { - props = extend({}, props); - } - let { class: klass, style } = props; - if (klass && !isString(klass)) { - props.class = normalizeClass(klass); - } - if (isObject(style)) { - // reactive state objects need to be cloned since they are likely to be - // mutated - if (isProxy(style) && !isArray(style)) { - style = extend({}, style); - } - props.style = normalizeStyle(style); - } - } - // encode the vnode type information into a bitmap - const shapeFlag = isString(type) - ? 1 /* ELEMENT */ - : isSuspense(type) - ? 128 /* SUSPENSE */ - : isTeleport(type) - ? 64 /* TELEPORT */ - : isObject(type) - ? 4 /* STATEFUL_COMPONENT */ - : isFunction(type) - ? 2 /* FUNCTIONAL_COMPONENT */ - : 0; - if ( shapeFlag & 4 /* STATEFUL_COMPONENT */ && isProxy(type)) { - type = toRaw(type); - warn(`Vue received a Component which was made a reactive object. This can ` + - `lead to unnecessary performance overhead, and should be avoided by ` + - `marking the component with \`markRaw\` or using \`shallowRef\` ` + - `instead of \`ref\`.`, `\nComponent that was made reactive: `, type); - } - const vnode = { - _isVNode: true, - type, - props, - key: props && props.key !== undefined ? props.key : null, - ref: props && props.ref !== undefined - ? [currentRenderingInstance, props.ref] - : null, - scopeId: currentScopeId, - children: null, - component: null, - suspense: null, - dirs: null, - transition: null, - el: null, - anchor: null, - target: null, - targetAnchor: null, - shapeFlag, - patchFlag, - dynamicProps, - dynamicChildren: null, - appContext: null - }; - normalizeChildren(vnode, children); - // presence of a patch flag indicates this node needs patching on updates. - // component nodes also should always be patched, because even if the - // component doesn't need to update, it needs to persist the instance on to - // the next vnode so that it can be properly unmounted later. - if (shouldTrack$1 > 0 && - currentBlock && - // the EVENTS flag is only for hydration and if it is the only flag, the - // vnode should not be considered dynamic due to handler caching. - patchFlag !== 32 /* HYDRATE_EVENTS */ && - (patchFlag > 0 || - shapeFlag & 128 /* SUSPENSE */ || - shapeFlag & 4 /* STATEFUL_COMPONENT */ || - shapeFlag & 2 /* FUNCTIONAL_COMPONENT */)) { - currentBlock.push(vnode); - } - return vnode; -} -function cloneVNode(vnode, extraProps) { - // This is intentionally NOT using spread or extend to avoid the runtime - // key enumeration cost. - return { - _isVNode: true, - type: vnode.type, - props: extraProps - ? vnode.props - ? mergeProps(vnode.props, extraProps) - : extend({}, extraProps) - : vnode.props, - key: vnode.key, - ref: vnode.ref, - scopeId: vnode.scopeId, - children: vnode.children, - target: vnode.target, - targetAnchor: vnode.targetAnchor, - shapeFlag: vnode.shapeFlag, - patchFlag: vnode.patchFlag, - dynamicProps: vnode.dynamicProps, - dynamicChildren: vnode.dynamicChildren, - appContext: vnode.appContext, - dirs: vnode.dirs, - transition: vnode.transition, - // These should technically only be non-null on mounted VNodes. However, - // they *should* be copied for kept-alive vnodes. So we just always copy - // them since them being non-null during a mount doesn't affect the logic as - // they will simply be overwritten. - component: vnode.component, - suspense: vnode.suspense, - el: vnode.el, - anchor: vnode.anchor - }; -} -function createTextVNode(text = ' ', flag = 0) { - return createVNode(Text, null, text, flag); -} -function createStaticVNode(content) { - return createVNode(Static, null, content); -} -function createCommentVNode(text = '', -// when used as the v-else branch, the comment node must be created as a -// block to ensure correct updates. -asBlock = false) { - return asBlock - ? (openBlock(), createBlock(Comment, null, text)) - : createVNode(Comment, null, text); -} -function normalizeVNode(child) { - if (child == null || typeof child === 'boolean') { - // empty placeholder - return createVNode(Comment); - } - else if (isArray(child)) { - // fragment - return createVNode(Fragment, null, child); - } - else if (typeof child === 'object') { - // already vnode, this should be the most common since compiled templates - // always produce all-vnode children arrays - return child.el === null ? child : cloneVNode(child); - } - else { - // strings and numbers - return createVNode(Text, null, String(child)); - } -} -// optimized normalization for template-compiled render fns -function cloneIfMounted(child) { - return child.el === null ? child : cloneVNode(child); -} -function normalizeChildren(vnode, children) { - let type = 0; - const { shapeFlag } = vnode; - if (children == null) { - children = null; - } - else if (isArray(children)) { - type = 16 /* ARRAY_CHILDREN */; - } - else if (typeof children === 'object') { - // Normalize slot to plain children - if ((shapeFlag & 1 /* ELEMENT */ || shapeFlag & 64 /* TELEPORT */) && - children.default) { - normalizeChildren(vnode, children.default()); - return; - } - else { - type = 32 /* SLOTS_CHILDREN */; - if (!children._ && !(InternalObjectKey in children)) { - children._ctx = currentRenderingInstance; - } - } - } - else if (isFunction(children)) { - children = { default: children, _ctx: currentRenderingInstance }; - type = 32 /* SLOTS_CHILDREN */; - } - else { - children = String(children); - // force teleport children to array so it can be moved around - if (shapeFlag & 64 /* TELEPORT */) { - type = 16 /* ARRAY_CHILDREN */; - children = [createTextVNode(children)]; - } - else { - type = 8 /* TEXT_CHILDREN */; - } - } - vnode.children = children; - vnode.shapeFlag |= type; -} -const handlersRE = /^on|^vnode/; -function mergeProps(...args) { - const ret = {}; - extend(ret, args[0]); - for (let i = 1; i < args.length; i++) { - const toMerge = args[i]; - for (const key in toMerge) { - if (key === 'class') { - if (ret.class !== toMerge.class) { - ret.class = normalizeClass([ret.class, toMerge.class]); - } - } - else if (key === 'style') { - ret.style = normalizeStyle([ret.style, toMerge.style]); - } - else if (handlersRE.test(key)) { - // on*, vnode* - const existing = ret[key]; - const incoming = toMerge[key]; - if (existing !== incoming) { - ret[key] = existing - ? [].concat(existing, toMerge[key]) - : incoming; - } - } - else { - ret[key] = toMerge[key]; - } - } - } - return ret; -} - -function emit(instance, event, ...args) { - const props = instance.vnode.props || EMPTY_OBJ; - { - const options = normalizeEmitsOptions(instance.type.emits); - if (options) { - if (!(event in options)) { - const propsOptions = normalizePropsOptions(instance.type.props)[0]; - if (!propsOptions || !(`on` + capitalize(event) in propsOptions)) { - warn(`Component emitted event "${event}" but it is neither declared in ` + - `the emits option nor as an "on${capitalize(event)}" prop.`); - } - } - else { - const validator = options[event]; - if (isFunction(validator)) { - const isValid = validator(...args); - if (!isValid) { - warn(`Invalid event arguments: event validation failed for event "${event}".`); - } - } - } - } - } - let handler = props[`on${capitalize(event)}`]; - // for v-model update:xxx events, also trigger kebab-case equivalent - // for props passed via kebab-case - if (!handler && event.indexOf('update:') === 0) { - event = hyphenate(event); - handler = props[`on${capitalize(event)}`]; - } - if (handler) { - callWithAsyncErrorHandling(handler, instance, 6 /* COMPONENT_EVENT_HANDLER */, args); - } -} -function normalizeEmitsOptions(options) { - if (!options) { - return; - } - else if (isArray(options)) { - if (options._n) { - return options._n; - } - const normalized = {}; - options.forEach(key => (normalized[key] = null)); - def(options, '_n', normalized); - return normalized; - } - else { - return options; - } -} -// Check if an incoming prop key is a declared emit event listener. -// e.g. With `emits: { click: null }`, props named `onClick` and `onclick` are -// both considered matched listeners. -function isEmitListener(emits, key) { - return (isOn(key) && - (hasOwn((emits = normalizeEmitsOptions(emits)), key[2].toLowerCase() + key.slice(3)) || - hasOwn(emits, key.slice(2)))); -} - -function initProps(instance, rawProps, isStateful, // result of bitwise flag comparison -isSSR = false) { - const props = {}; - const attrs = {}; - def(attrs, InternalObjectKey, 1); - setFullProps(instance, rawProps, props, attrs); - const options = instance.type.props; - // validation - if ( options && rawProps) { - validateProps(props, options); - } - if (isStateful) { - // stateful - instance.props = isSSR ? props : shallowReactive(props); - } - else { - if (!options) { - // functional w/ optional props, props === attrs - instance.props = attrs; - } - else { - // functional w/ declared props - instance.props = props; - } - } - instance.attrs = attrs; -} -function updateProps(instance, rawProps, optimized) { - const { props, attrs, vnode: { patchFlag } } = instance; - const rawOptions = instance.type.props; - const rawCurrentProps = toRaw(props); - const { 0: options } = normalizePropsOptions(rawOptions); - if ((optimized || patchFlag > 0) && !(patchFlag & 16 /* FULL_PROPS */)) { - if (patchFlag & 8 /* PROPS */) { - // Compiler-generated props & no keys change, just set the updated - // the props. - const propsToUpdate = instance.vnode.dynamicProps; - for (let i = 0; i < propsToUpdate.length; i++) { - const key = propsToUpdate[i]; - // PROPS flag guarantees rawProps to be non-null - const value = rawProps[key]; - if (options) { - // attr / props separation was done on init and will be consistent - // in this code path, so just check if attrs have it. - if (hasOwn(attrs, key)) { - attrs[key] = value; - } - else { - const camelizedKey = camelize(key); - props[camelizedKey] = resolvePropValue(options, rawCurrentProps, camelizedKey, value); - } - } - else { - attrs[key] = value; - } - } - } - } - else { - // full props update. - setFullProps(instance, rawProps, props, attrs); - // in case of dynamic props, check if we need to delete keys from - // the props object - let kebabKey; - for (const key in rawCurrentProps) { - if (!rawProps || - (!hasOwn(rawProps, key) && - // it's possible the original props was passed in as kebab-case - // and converted to camelCase (#955) - ((kebabKey = hyphenate(key)) === key || !hasOwn(rawProps, kebabKey)))) { - if (options) { - props[key] = resolvePropValue(options, rawProps || EMPTY_OBJ, key, undefined); - } - else { - delete props[key]; - } - } - } - for (const key in attrs) { - if (!rawProps || !hasOwn(rawProps, key)) { - delete attrs[key]; - } - } - } - if ( rawOptions && rawProps) { - validateProps(props, rawOptions); - } -} -function setFullProps(instance, rawProps, props, attrs) { - const { 0: options, 1: needCastKeys } = normalizePropsOptions(instance.type.props); - const emits = instance.type.emits; - if (rawProps) { - for (const key in rawProps) { - const value = rawProps[key]; - // key, ref are reserved and never passed down - if (isReservedProp(key)) { - continue; - } - // prop option names are camelized during normalization, so to support - // kebab -> camel conversion here we need to camelize the key. - let camelKey; - if (options && hasOwn(options, (camelKey = camelize(key)))) { - props[camelKey] = value; - } - else if (!emits || !isEmitListener(emits, key)) { - // Any non-declared (either as a prop or an emitted event) props are put - // into a separate `attrs` object for spreading. Make sure to preserve - // original key casing - attrs[key] = value; - } - } - } - if (needCastKeys) { - for (let i = 0; i < needCastKeys.length; i++) { - const key = needCastKeys[i]; - props[key] = resolvePropValue(options, props, key, props[key]); - } - } -} -function resolvePropValue(options, props, key, value) { - const opt = options[key]; - if (opt != null) { - const hasDefault = hasOwn(opt, 'default'); - // default values - if (hasDefault && value === undefined) { - const defaultValue = opt.default; - value = isFunction(defaultValue) ? defaultValue() : defaultValue; - } - // boolean casting - if (opt[0 /* shouldCast */]) { - if (!hasOwn(props, key) && !hasDefault) { - value = false; - } - else if (opt[1 /* shouldCastTrue */] && - (value === '' || value === hyphenate(key))) { - value = true; - } - } - } - return value; -} -function normalizePropsOptions(raw) { - if (!raw) { - return EMPTY_ARR; - } - if (raw._n) { - return raw._n; - } - const normalized = {}; - const needCastKeys = []; - if (isArray(raw)) { - for (let i = 0; i < raw.length; i++) { - if ( !isString(raw[i])) { - warn(`props must be strings when using array syntax.`, raw[i]); - } - const normalizedKey = camelize(raw[i]); - if (validatePropName(normalizedKey)) { - normalized[normalizedKey] = EMPTY_OBJ; - } - } - } - else { - if ( !isObject(raw)) { - warn(`invalid props options`, raw); - } - for (const key in raw) { - const normalizedKey = camelize(key); - if (validatePropName(normalizedKey)) { - const opt = raw[key]; - const prop = (normalized[normalizedKey] = - isArray(opt) || isFunction(opt) ? { type: opt } : opt); - if (prop) { - const booleanIndex = getTypeIndex(Boolean, prop.type); - const stringIndex = getTypeIndex(String, prop.type); - prop[0 /* shouldCast */] = booleanIndex > -1; - prop[1 /* shouldCastTrue */] = - stringIndex < 0 || booleanIndex < stringIndex; - // if the prop needs boolean casting or default value - if (booleanIndex > -1 || hasOwn(prop, 'default')) { - needCastKeys.push(normalizedKey); - } - } - } - } - } - const normalizedEntry = [normalized, needCastKeys]; - def(raw, '_n', normalizedEntry); - return normalizedEntry; -} -// use function string name to check type constructors -// so that it works across vms / iframes. -function getType(ctor) { - const match = ctor && ctor.toString().match(/^\s*function (\w+)/); - return match ? match[1] : ''; -} -function isSameType(a, b) { - return getType(a) === getType(b); -} -function getTypeIndex(type, expectedTypes) { - if (isArray(expectedTypes)) { - for (let i = 0, len = expectedTypes.length; i < len; i++) { - if (isSameType(expectedTypes[i], type)) { - return i; - } - } - } - else if (isFunction(expectedTypes)) { - return isSameType(expectedTypes, type) ? 0 : -1; - } - return -1; -} -function validateProps(props, rawOptions) { - const rawValues = toRaw(props); - const options = normalizePropsOptions(rawOptions)[0]; - for (const key in options) { - let opt = options[key]; - if (opt == null) - continue; - validateProp(key, rawValues[key], opt, !hasOwn(rawValues, key)); - } -} -function validatePropName(key) { - if (key[0] !== '$') { - return true; - } - else { - warn(`Invalid prop name: "${key}" is a reserved property.`); - } - return false; -} -function validateProp(name, value, prop, isAbsent) { - const { type, required, validator } = prop; - // required! - if (required && isAbsent) { - warn('Missing required prop: "' + name + '"'); - return; - } - // missing but optional - if (value == null && !prop.required) { - return; - } - // type check - if (type != null && type !== true) { - let isValid = false; - const types = isArray(type) ? type : [type]; - const expectedTypes = []; - // value is valid as long as one of the specified types match - for (let i = 0; i < types.length && !isValid; i++) { - const { valid, expectedType } = assertType(value, types[i]); - expectedTypes.push(expectedType || ''); - isValid = valid; - } - if (!isValid) { - warn(getInvalidTypeMessage(name, value, expectedTypes)); - return; - } - } - // custom validator - if (validator && !validator(value)) { - warn('Invalid prop: custom validator check failed for prop "' + name + '".'); - } -} -const isSimpleType = /*#__PURE__*/ makeMap('String,Number,Boolean,Function,Symbol'); -function assertType(value, type) { - let valid; - const expectedType = getType(type); - if (isSimpleType(expectedType)) { - const t = typeof value; - valid = t === expectedType.toLowerCase(); - // for primitive wrapper objects - if (!valid && t === 'object') { - valid = value instanceof type; - } - } - else if (expectedType === 'Object') { - valid = toRawType(value) === 'Object'; - } - else if (expectedType === 'Array') { - valid = isArray(value); - } - else { - valid = value instanceof type; - } - return { - valid, - expectedType - }; -} -function getInvalidTypeMessage(name, value, expectedTypes) { - let message = `Invalid prop: type check failed for prop "${name}".` + - ` Expected ${expectedTypes.map(capitalize).join(', ')}`; - const expectedType = expectedTypes[0]; - const receivedType = toRawType(value); - const expectedValue = styleValue(value, expectedType); - const receivedValue = styleValue(value, receivedType); - // check if we need to specify expected value - if (expectedTypes.length === 1 && - isExplicable(expectedType) && - !isBoolean(expectedType, receivedType)) { - message += ` with value ${expectedValue}`; - } - message += `, got ${receivedType} `; - // check if we need to specify received value - if (isExplicable(receivedType)) { - message += `with value ${receivedValue}.`; - } - return message; -} -function styleValue(value, type) { - if (type === 'String') { - return `"${value}"`; - } - else if (type === 'Number') { - return `${Number(value)}`; - } - else { - return `${value}`; - } -} -function isExplicable(type) { - const explicitTypes = ['string', 'number', 'boolean']; - return explicitTypes.some(elem => type.toLowerCase() === elem); -} -function isBoolean(...args) { - return args.some(elem => elem.toLowerCase() === 'boolean'); -} - -const isInternalKey = (key) => key[0] === '_' || key === '$stable'; -const normalizeSlotValue = (value) => isArray(value) - ? value.map(normalizeVNode) - : [normalizeVNode(value)]; -const normalizeSlot = (key, rawSlot, ctx) => withCtx((props) => { - if ( currentInstance) { - warn(`Slot "${key}" invoked outside of the render function: ` + - `this will not track dependencies used in the slot. ` + - `Invoke the slot function inside the render function instead.`); - } - return normalizeSlotValue(rawSlot(props)); -}, ctx); -const normalizeObjectSlots = (rawSlots, slots) => { - const ctx = rawSlots._ctx; - for (const key in rawSlots) { - if (isInternalKey(key)) - continue; - const value = rawSlots[key]; - if (isFunction(value)) { - slots[key] = normalizeSlot(key, value, ctx); - } - else if (value != null) { - { - warn(`Non-function value encountered for slot "${key}". ` + - `Prefer function slots for better performance.`); - } - const normalized = normalizeSlotValue(value); - slots[key] = () => normalized; - } - } -}; -const normalizeVNodeSlots = (instance, children) => { - if ( !isKeepAlive(instance.vnode)) { - warn(`Non-function value encountered for default slot. ` + - `Prefer function slots for better performance.`); - } - const normalized = normalizeSlotValue(children); - instance.slots.default = () => normalized; -}; -const initSlots = (instance, children) => { - if (instance.vnode.shapeFlag & 32 /* SLOTS_CHILDREN */) { - if (children._ === 1) { - instance.slots = children; - } - else { - normalizeObjectSlots(children, (instance.slots = {})); - } - } - else { - instance.slots = {}; - if (children) { - normalizeVNodeSlots(instance, children); - } - } - def(instance.slots, InternalObjectKey, 1); -}; -const updateSlots = (instance, children) => { - const { vnode, slots } = instance; - let needDeletionCheck = true; - let deletionComparisonTarget = EMPTY_OBJ; - if (vnode.shapeFlag & 32 /* SLOTS_CHILDREN */) { - if (children._ === 1) { - // compiled slots. - if ( - // bail on dynamic slots (v-if, v-for, reference of scope variables) - !(vnode.patchFlag & 1024 /* DYNAMIC_SLOTS */) && - // bail on HRM updates - !( instance.parent && instance.parent.renderUpdated)) { - // compiled AND static. - // no need to update, and skip stale slots removal. - needDeletionCheck = false; - } - else { - // compiled but dynamic - update slots, but skip normalization. - extend(slots, children); - } - } - else { - needDeletionCheck = !children.$stable; - normalizeObjectSlots(children, slots); - } - deletionComparisonTarget = children; - } - else if (children) { - // non slot object children (direct value) passed to a component - normalizeVNodeSlots(instance, children); - deletionComparisonTarget = { default: 1 }; - } - // delete stale slots - if (needDeletionCheck) { - for (const key in slots) { - if (!isInternalKey(key) && !(key in deletionComparisonTarget)) { - delete slots[key]; - } - } - } -}; - -/** -Runtime helper for applying directives to a vnode. Example usage: - -const comp = resolveComponent('comp') -const foo = resolveDirective('foo') -const bar = resolveDirective('bar') - -return withDirectives(h(comp), [ - [foo, this.x], - [bar, this.y] -]) -*/ -const isBuiltInDirective = /*#__PURE__*/ makeMap('bind,cloak,else-if,else,for,html,if,model,on,once,pre,show,slot,text'); -function validateDirectiveName(name) { - if (isBuiltInDirective(name)) { - warn('Do not use built-in directive ids as custom directive id: ' + name); - } -} -function withDirectives(vnode, directives) { - const internalInstance = currentRenderingInstance; - if (internalInstance === null) { - warn(`withDirectives can only be used inside render functions.`); - return vnode; - } - const instance = internalInstance.proxy; - const bindings = vnode.dirs || (vnode.dirs = []); - for (let i = 0; i < directives.length; i++) { - let [dir, value, arg, modifiers = EMPTY_OBJ] = directives[i]; - if (isFunction(dir)) { - dir = { - mounted: dir, - updated: dir - }; - } - bindings.push({ - dir, - instance, - value, - oldValue: void 0, - arg, - modifiers - }); - } - return vnode; -} -function invokeDirectiveHook(vnode, prevVNode, instance, name) { - const bindings = vnode.dirs; - const oldBindings = prevVNode && prevVNode.dirs; - for (let i = 0; i < bindings.length; i++) { - const binding = bindings[i]; - if (oldBindings) { - binding.oldValue = oldBindings[i].value; - } - const hook = binding.dir[name]; - if (hook) { - callWithAsyncErrorHandling(hook, instance, 8 /* DIRECTIVE_HOOK */, [ - vnode.el, - binding, - vnode, - prevVNode - ]); - } - } -} - -function createAppContext() { - return { - config: { - isNativeTag: NO, - devtools: true, - performance: false, - globalProperties: {}, - optionMergeStrategies: {}, - isCustomElement: NO, - errorHandler: undefined, - warnHandler: undefined - }, - mixins: [], - components: {}, - directives: {}, - provides: Object.create(null) - }; -} -function createAppAPI(render, hydrate) { - return function createApp(rootComponent, rootProps = null) { - if (rootProps != null && !isObject(rootProps)) { - warn(`root props passed to app.mount() must be an object.`); - rootProps = null; - } - const context = createAppContext(); - const installedPlugins = new Set(); - let isMounted = false; - const app = { - _component: rootComponent, - _props: rootProps, - _container: null, - _context: context, - get config() { - return context.config; - }, - set config(v) { - { - warn(`app.config cannot be replaced. Modify individual options instead.`); - } - }, - use(plugin, ...options) { - if (installedPlugins.has(plugin)) { - warn(`Plugin has already been applied to target app.`); - } - else if (plugin && isFunction(plugin.install)) { - installedPlugins.add(plugin); - plugin.install(app, ...options); - } - else if (isFunction(plugin)) { - installedPlugins.add(plugin); - plugin(app, ...options); - } - else { - warn(`A plugin must either be a function or an object with an "install" ` + - `function.`); - } - return app; - }, - mixin(mixin) { - { - if (!context.mixins.includes(mixin)) { - context.mixins.push(mixin); - } - else { - warn('Mixin has already been applied to target app' + - (mixin.name ? `: ${mixin.name}` : '')); - } - } - return app; - }, - component(name, component) { - { - validateComponentName(name, context.config); - } - if (!component) { - return context.components[name]; - } - if ( context.components[name]) { - warn(`Component "${name}" has already been registered in target app.`); - } - context.components[name] = component; - return app; - }, - directive(name, directive) { - { - validateDirectiveName(name); - } - if (!directive) { - return context.directives[name]; - } - if ( context.directives[name]) { - warn(`Directive "${name}" has already been registered in target app.`); - } - context.directives[name] = directive; - return app; - }, - mount(rootContainer, isHydrate) { - if (!isMounted) { - const vnode = createVNode(rootComponent, rootProps); - // store app context on the root VNode. - // this will be set on the root instance on initial mount. - vnode.appContext = context; - // HMR root reload - { - context.reload = () => { - render(cloneVNode(vnode), rootContainer); - }; - } - if (isHydrate && hydrate) { - hydrate(vnode, rootContainer); - } - else { - render(vnode, rootContainer); - } - isMounted = true; - app._container = rootContainer; - return vnode.component.proxy; - } - else { - warn(`App has already been mounted. Create a new app instance instead.`); - } - }, - unmount() { - if (isMounted) { - render(null, app._container); - } - else { - warn(`Cannot unmount an app that is not mounted.`); - } - }, - provide(key, value) { - if ( key in context.provides) { - warn(`App already provides property with key "${key}". ` + - `It will be overwritten with the new value.`); - } - // TypeScript doesn't allow symbols as index type - // https://github.com/Microsoft/TypeScript/issues/24587 - context.provides[key] = value; - return app; - } - }; - return app; - }; -} - -// Expose the HMR runtime on the global object -// This makes it entirely tree-shakable without polluting the exports and makes -// it easier to be used in toolings like vue-loader -// Note: for a component to be eligible for HMR it also needs the __hmrId option -// to be set so that its instances can be registered / removed. -{ - const globalObject = typeof global !== 'undefined' - ? global - : typeof self !== 'undefined' - ? self - : typeof window !== 'undefined' - ? window - : {}; - globalObject.__VUE_HMR_RUNTIME__ = { - createRecord: tryWrap(createRecord), - rerender: tryWrap(rerender), - reload: tryWrap(reload) - }; -} -const map = new Map(); -function registerHMR(instance) { - const id = instance.type.__hmrId; - let record = map.get(id); - if (!record) { - createRecord(id, instance.type); - record = map.get(id); - } - record.instances.add(instance); -} -function unregisterHMR(instance) { - map.get(instance.type.__hmrId).instances.delete(instance); -} -function createRecord(id, comp) { - if (map.has(id)) { - return false; - } - map.set(id, { - comp, - instances: new Set() - }); - return true; -} -function rerender(id, newRender) { - const record = map.get(id); - if (!record) - return; - // Array.from creates a snapshot which avoids the set being mutated during - // updates - Array.from(record.instances).forEach(instance => { - if (newRender) { - instance.render = newRender; - } - instance.renderCache = []; - // this flag forces child components with slot content to update - instance.renderUpdated = true; - instance.update(); - instance.renderUpdated = false; - }); -} -function reload(id, newComp) { - const record = map.get(id); - if (!record) - return; - // 1. Update existing comp definition to match new one - const comp = record.comp; - Object.assign(comp, newComp); - for (const key in comp) { - if (!(key in newComp)) { - delete comp[key]; - } - } - // 2. Mark component dirty. This forces the renderer to replace the component - // on patch. - comp.__hmrUpdated = true; - // Array.from creates a snapshot which avoids the set being mutated during - // updates - Array.from(record.instances).forEach(instance => { - if (instance.parent) { - // 3. Force the parent instance to re-render. This will cause all updated - // components to be unmounted and re-mounted. Queue the update so that we - // don't end up forcing the same parent to re-render multiple times. - queueJob(instance.parent.update); - } - else if (instance.appContext.reload) { - // root instance mounted via createApp() has a reload method - instance.appContext.reload(); - } - else if (typeof window !== 'undefined') { - // root instance inside tree created via raw render(). Force reload. - window.location.reload(); - } - else { - console.warn('[HMR] Root or manually mounted instance modified. Full reload required.'); - } - }); - // 4. Make sure to unmark the component after the reload. - queuePostFlushCb(() => { - comp.__hmrUpdated = false; - }); -} -function tryWrap(fn) { - return (id, arg) => { - try { - return fn(id, arg); - } - catch (e) { - console.error(e); - console.warn(`[HMR] Something went wrong during Vue component hot-reload. ` + - `Full reload required.`); - } - }; -} - -let hasMismatch = false; -const isSVGContainer = (container) => /svg/.test(container.namespaceURI) && container.tagName !== 'foreignObject'; -const isComment = (node) => node.nodeType === 8 /* COMMENT */; -// Note: hydration is DOM-specific -// But we have to place it in core due to tight coupling with core - splitting -// it out creates a ton of unnecessary complexity. -// Hydration also depends on some renderer internal logic which needs to be -// passed in via arguments. -function createHydrationFunctions(rendererInternals) { - const { mt: mountComponent, p: patch, o: { patchProp, nextSibling, parentNode, remove, insert, createComment } } = rendererInternals; - const hydrate = (vnode, container) => { - if ( !container.hasChildNodes()) { - warn(`Attempting to hydrate existing markup but container is empty. ` + - `Performing full mount instead.`); - patch(null, vnode, container); - return; - } - hasMismatch = false; - hydrateNode(container.firstChild, vnode, null, null); - flushPostFlushCbs(); - if (hasMismatch && !false) { - // this error should show up in production - console.error(`Hydration completed but contains mismatches.`); - } - }; - const hydrateNode = (node, vnode, parentComponent, parentSuspense, optimized = false) => { - const isFragmentStart = isComment(node) && node.data === '['; - const onMismatch = () => handleMismtach(node, vnode, parentComponent, parentSuspense, isFragmentStart); - const { type, shapeFlag } = vnode; - const domType = node.nodeType; - vnode.el = node; - switch (type) { - case Text: - if (domType !== 3 /* TEXT */) { - return onMismatch(); - } - if (node.data !== vnode.children) { - hasMismatch = true; - - warn(`Hydration text mismatch:` + - `\n- Client: ${JSON.stringify(vnode.children)}`, `\n- Server: ${JSON.stringify(node.data)}`); - node.data = vnode.children; - } - return nextSibling(node); - case Comment: - if (domType !== 8 /* COMMENT */ || isFragmentStart) { - return onMismatch(); - } - return nextSibling(node); - case Static: - if (domType !== 1 /* ELEMENT */) { - return onMismatch(); - } - return nextSibling(node); - case Fragment: - if (!isFragmentStart) { - return onMismatch(); - } - return hydrateFragment(node, vnode, parentComponent, parentSuspense, optimized); - default: - if (shapeFlag & 1 /* ELEMENT */) { - if (domType !== 1 /* ELEMENT */ || - vnode.type !== node.tagName.toLowerCase()) { - return onMismatch(); - } - return hydrateElement(node, vnode, parentComponent, parentSuspense, optimized); - } - else if (shapeFlag & 6 /* COMPONENT */) { - // when setting up the render effect, if the initial vnode already - // has .el set, the component will perform hydration instead of mount - // on its sub-tree. - const container = parentNode(node); - const hydrateComponent = () => { - mountComponent(vnode, container, null, parentComponent, parentSuspense, isSVGContainer(container), optimized); - }; - // async component - const loadAsync = vnode.type.__asyncLoader; - if (loadAsync) { - loadAsync().then(hydrateComponent); - } - else { - hydrateComponent(); - } - // component may be async, so in the case of fragments we cannot rely - // on component's rendered output to determine the end of the fragment - // instead, we do a lookahead to find the end anchor node. - return isFragmentStart - ? locateClosingAsyncAnchor(node) - : nextSibling(node); - } - else if (shapeFlag & 64 /* TELEPORT */) { - if (domType !== 8 /* COMMENT */) { - return onMismatch(); - } - return vnode.type.hydrate(node, vnode, parentComponent, parentSuspense, optimized, rendererInternals, hydrateChildren); - } - else if ( shapeFlag & 128 /* SUSPENSE */) { - return vnode.type.hydrate(node, vnode, parentComponent, parentSuspense, isSVGContainer(parentNode(node)), optimized, rendererInternals, hydrateNode); - } - else { - warn('Invalid HostVNode type:', type, `(${typeof type})`); - } - return null; - } - }; - const hydrateElement = (el, vnode, parentComponent, parentSuspense, optimized) => { - optimized = optimized || !!vnode.dynamicChildren; - const { props, patchFlag, shapeFlag, dirs } = vnode; - // skip props & children if this is hoisted static nodes - if (patchFlag !== -1 /* HOISTED */) { - // props - if (props) { - if (!optimized || - (patchFlag & 16 /* FULL_PROPS */ || - patchFlag & 32 /* HYDRATE_EVENTS */)) { - for (const key in props) { - if (!isReservedProp(key) && isOn(key)) { - patchProp(el, key, null, props[key]); - } - } - } - else if (props.onClick) { - // Fast path for click listeners (which is most often) to avoid - // iterating through props. - patchProp(el, 'onClick', null, props.onClick); - } - } - // vnode / directive hooks - let vnodeHooks; - if ((vnodeHooks = props && props.onVnodeBeforeMount)) { - invokeVNodeHook(vnodeHooks, parentComponent, vnode); - } - if (dirs) { - invokeDirectiveHook(vnode, null, parentComponent, 'beforeMount'); - } - if ((vnodeHooks = props && props.onVnodeMounted) || dirs) { - queueEffectWithSuspense(() => { - vnodeHooks && invokeVNodeHook(vnodeHooks, parentComponent, vnode); - dirs && invokeDirectiveHook(vnode, null, parentComponent, 'mounted'); - }, parentSuspense); - } - // children - if (shapeFlag & 16 /* ARRAY_CHILDREN */ && - // skip if element has innerHTML / textContent - !(props && (props.innerHTML || props.textContent))) { - let next = hydrateChildren(el.firstChild, vnode, el, parentComponent, parentSuspense, optimized); - let hasWarned = false; - while (next) { - hasMismatch = true; - if ( !hasWarned) { - warn(`Hydration children mismatch in <${vnode.type}>: ` + - `server rendered element contains more child nodes than client vdom.`); - hasWarned = true; - } - // The SSRed DOM contains more nodes than it should. Remove them. - const cur = next; - next = next.nextSibling; - remove(cur); - } - } - else if (shapeFlag & 8 /* TEXT_CHILDREN */) { - if (el.textContent !== vnode.children) { - hasMismatch = true; - - warn(`Hydration text content mismatch in <${vnode.type}>:\n` + - `- Client: ${el.textContent}\n` + - `- Server: ${vnode.children}`); - el.textContent = vnode.children; - } - } - } - return el.nextSibling; - }; - const hydrateChildren = (node, vnode, container, parentComponent, parentSuspense, optimized) => { - optimized = optimized || !!vnode.dynamicChildren; - const children = vnode.children; - const l = children.length; - let hasWarned = false; - for (let i = 0; i < l; i++) { - const vnode = optimized - ? children[i] - : (children[i] = normalizeVNode(children[i])); - if (node) { - node = hydrateNode(node, vnode, parentComponent, parentSuspense, optimized); - } - else { - hasMismatch = true; - if ( !hasWarned) { - warn(`Hydration children mismatch in <${container.tagName.toLowerCase()}>: ` + - `server rendered element contains fewer child nodes than client vdom.`); - hasWarned = true; - } - // the SSRed DOM didn't contain enough nodes. Mount the missing ones. - patch(null, vnode, container, null, parentComponent, parentSuspense, isSVGContainer(container)); - } - } - return node; - }; - const hydrateFragment = (node, vnode, parentComponent, parentSuspense, optimized) => { - const container = parentNode(node); - const next = hydrateChildren(nextSibling(node), vnode, container, parentComponent, parentSuspense, optimized); - if (next && isComment(next) && next.data === ']') { - return nextSibling((vnode.anchor = next)); - } - else { - // fragment didn't hydrate successfully, since we didn't get a end anchor - // back. This should have led to node/children mismatch warnings. - hasMismatch = true; - // since the anchor is missing, we need to create one and insert it - insert((vnode.anchor = createComment(`]`)), container, next); - return next; - } - }; - const handleMismtach = (node, vnode, parentComponent, parentSuspense, isFragment) => { - hasMismatch = true; - - warn(`Hydration node mismatch:\n- Client vnode:`, vnode.type, `\n- Server rendered DOM:`, node, node.nodeType === 3 /* TEXT */ - ? `(text)` - : isComment(node) && node.data === '[' - ? `(start of fragment)` - : ``); - vnode.el = null; - if (isFragment) { - // remove excessive fragment nodes - const end = locateClosingAsyncAnchor(node); - while (true) { - const next = nextSibling(node); - if (next && next !== end) { - remove(next); - } - else { - break; - } - } - } - const next = nextSibling(node); - const container = parentNode(node); - remove(node); - patch(null, vnode, container, next, parentComponent, parentSuspense, isSVGContainer(container)); - return next; - }; - const locateClosingAsyncAnchor = (node) => { - let match = 0; - while (node) { - node = nextSibling(node); - if (node && isComment(node)) { - if (node.data === '[') - match++; - if (node.data === ']') { - if (match === 0) { - return nextSibling(node); - } - else { - match--; - } - } - } - } - return node; - }; - return [hydrate, hydrateNode]; -} - -let supported; -let perf; -function startMeasure(instance, type) { - if (instance.appContext.config.performance && isSupported()) { - perf.mark(`vue-${type}-${instance.uid}`); - } -} -function endMeasure(instance, type) { - if (instance.appContext.config.performance && isSupported()) { - const startTag = `vue-${type}-${instance.uid}`; - const endTag = startTag + `:end`; - perf.mark(endTag); - perf.measure(`<${formatComponentName(instance.type)}> ${type}`, startTag, endTag); - perf.clearMarks(startTag); - perf.clearMarks(endTag); - } -} -function isSupported() { - if (supported !== undefined) { - return supported; - } - if (typeof window !== 'undefined' && window.performance) { - supported = true; - perf = window.performance; - } - else { - supported = false; - } - return supported; -} - -function createDevEffectOptions(instance) { - return { - scheduler: queueJob, - onTrack: instance.rtc ? e => invokeArrayFns(instance.rtc, e) : void 0, - onTrigger: instance.rtg ? e => invokeArrayFns(instance.rtg, e) : void 0 - }; -} -const queuePostRenderEffect = queueEffectWithSuspense - ; -/** - * The createRenderer function accepts two generic arguments: - * HostNode and HostElement, corresponding to Node and Element types in the - * host environment. For example, for runtime-dom, HostNode would be the DOM - * `Node` interface and HostElement would be the DOM `Element` interface. - * - * Custom renderers can pass in the platform specific types like this: - * - * ``` js - * const { render, createApp } = createRenderer({ - * patchProp, - * ...nodeOps - * }) - * ``` - */ -function createRenderer(options) { - return baseCreateRenderer(options); -} -// Separate API for creating hydration-enabled renderer. -// Hydration logic is only used when calling this function, making it -// tree-shakable. -function createHydrationRenderer(options) { - return baseCreateRenderer(options, createHydrationFunctions); -} -// implementation -function baseCreateRenderer(options, createHydrationFns) { - const { insert: hostInsert, remove: hostRemove, patchProp: hostPatchProp, createElement: hostCreateElement, createText: hostCreateText, createComment: hostCreateComment, setText: hostSetText, setElementText: hostSetElementText, parentNode: hostParentNode, nextSibling: hostNextSibling, setScopeId: hostSetScopeId = NOOP, cloneNode: hostCloneNode, insertStaticContent: hostInsertStaticContent } = options; - // Note: functions inside this closure should use `const xxx = () => {}` - // style in order to prevent being inlined by minifiers. - const patch = (n1, n2, container, anchor = null, parentComponent = null, parentSuspense = null, isSVG = false, optimized = false) => { - // patching & not same type, unmount old tree - if (n1 && !isSameVNodeType(n1, n2)) { - anchor = getNextHostNode(n1); - unmount(n1, parentComponent, parentSuspense, true); - n1 = null; - } - const { type, ref, shapeFlag } = n2; - switch (type) { - case Text: - processText(n1, n2, container, anchor); - break; - case Comment: - processCommentNode(n1, n2, container, anchor); - break; - case Static: - if (n1 == null) { - mountStaticNode(n2, container, anchor, isSVG); - } // static nodes are noop on patch - break; - case Fragment: - processFragment(n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized); - break; - default: - if (shapeFlag & 1 /* ELEMENT */) { - processElement(n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized); - } - else if (shapeFlag & 6 /* COMPONENT */) { - processComponent(n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized); - } - else if (shapeFlag & 64 /* TELEPORT */) { - type.process(n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized, internals); - } - else if ( shapeFlag & 128 /* SUSPENSE */) { - type.process(n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized, internals); - } - else { - warn('Invalid VNode type:', type, `(${typeof type})`); - } - } - // set ref - if (ref != null && parentComponent) { - const refValue = shapeFlag & 4 /* STATEFUL_COMPONENT */ ? n2.component.proxy : n2.el; - setRef(ref, n1 && n1.ref, parentComponent, refValue); - } - }; - const processText = (n1, n2, container, anchor) => { - if (n1 == null) { - hostInsert((n2.el = hostCreateText(n2.children)), container, anchor); - } - else { - const el = (n2.el = n1.el); - if (n2.children !== n1.children) { - hostSetText(el, n2.children); - } - } - }; - const processCommentNode = (n1, n2, container, anchor) => { - if (n1 == null) { - hostInsert((n2.el = hostCreateComment(n2.children || '')), container, anchor); - } - else { - // there's no support for dynamic comments - n2.el = n1.el; - } - }; - const mountStaticNode = (n2, container, anchor, isSVG) => { - if (n2.el && hostCloneNode !== undefined) { - hostInsert(hostCloneNode(n2.el), container, anchor); - } - else { - // static nodes are only present when used with compiler-dom/runtime-dom - // which guarantees presence of hostInsertStaticContent. - n2.el = hostInsertStaticContent(n2.children, container, anchor, isSVG); - } - }; - const processElement = (n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized) => { - isSVG = isSVG || n2.type === 'svg'; - if (n1 == null) { - mountElement(n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized); - } - else { - patchElement(n1, n2, parentComponent, parentSuspense, isSVG, optimized); - } - }; - const mountElement = (vnode, container, anchor, parentComponent, parentSuspense, isSVG, optimized) => { - let el; - let vnodeHook; - const { type, props, shapeFlag, transition, scopeId, patchFlag, dirs } = vnode; - if (vnode.el && - hostCloneNode !== undefined && - patchFlag === -1 /* HOISTED */) { - // If a vnode has non-null el, it means it's being reused. - // Only static vnodes can be reused, so its mounted DOM nodes should be - // exactly the same, and we can simply do a clone here. - el = vnode.el = hostCloneNode(vnode.el); - } - else { - el = vnode.el = hostCreateElement(vnode.type, isSVG, props && props.is); - // props - if (props) { - for (const key in props) { - if (!isReservedProp(key)) { - hostPatchProp(el, key, null, props[key], isSVG); - } - } - if ((vnodeHook = props.onVnodeBeforeMount)) { - invokeVNodeHook(vnodeHook, parentComponent, vnode); - } - } - if (dirs) { - invokeDirectiveHook(vnode, null, parentComponent, 'beforeMount'); - } - // scopeId - if (scopeId) { - hostSetScopeId(el, scopeId); - } - const treeOwnerId = parentComponent && parentComponent.type.__scopeId; - // vnode's own scopeId and the current patched component's scopeId is - // different - this is a slot content node. - if (treeOwnerId && treeOwnerId !== scopeId) { - hostSetScopeId(el, treeOwnerId + '-s'); - } - // children - if (shapeFlag & 8 /* TEXT_CHILDREN */) { - hostSetElementText(el, vnode.children); - } - else if (shapeFlag & 16 /* ARRAY_CHILDREN */) { - mountChildren(vnode.children, el, null, parentComponent, parentSuspense, isSVG && type !== 'foreignObject', optimized || !!vnode.dynamicChildren); - } - if (transition && !transition.persisted) { - transition.beforeEnter(el); - } - } - hostInsert(el, container, anchor); - if ((vnodeHook = props && props.onVnodeMounted) || - (transition && !transition.persisted) || - dirs) { - queuePostRenderEffect(() => { - vnodeHook && invokeVNodeHook(vnodeHook, parentComponent, vnode); - transition && !transition.persisted && transition.enter(el); - dirs && invokeDirectiveHook(vnode, null, parentComponent, 'mounted'); - }, parentSuspense); - } - }; - const mountChildren = (children, container, anchor, parentComponent, parentSuspense, isSVG, optimized, start = 0) => { - for (let i = start; i < children.length; i++) { - const child = (children[i] = optimized - ? cloneIfMounted(children[i]) - : normalizeVNode(children[i])); - patch(null, child, container, anchor, parentComponent, parentSuspense, isSVG, optimized); - } - }; - const patchElement = (n1, n2, parentComponent, parentSuspense, isSVG, optimized) => { - const el = (n2.el = n1.el); - let { patchFlag, dynamicChildren, dirs } = n2; - const oldProps = (n1 && n1.props) || EMPTY_OBJ; - const newProps = n2.props || EMPTY_OBJ; - let vnodeHook; - if ((vnodeHook = newProps.onVnodeBeforeUpdate)) { - invokeVNodeHook(vnodeHook, parentComponent, n2, n1); - } - if (dirs) { - invokeDirectiveHook(n2, n1, parentComponent, 'beforeUpdate'); - } - if ( parentComponent && parentComponent.renderUpdated) { - // HMR updated, force full diff - patchFlag = 0; - optimized = false; - dynamicChildren = null; - } - if (patchFlag > 0) { - // the presence of a patchFlag means this element's render code was - // generated by the compiler and can take the fast path. - // in this path old node and new node are guaranteed to have the same shape - // (i.e. at the exact same position in the source template) - if (patchFlag & 16 /* FULL_PROPS */) { - // element props contain dynamic keys, full diff needed - patchProps(el, n2, oldProps, newProps, parentComponent, parentSuspense, isSVG); - } - else { - // class - // this flag is matched when the element has dynamic class bindings. - if (patchFlag & 2 /* CLASS */) { - if (oldProps.class !== newProps.class) { - hostPatchProp(el, 'class', null, newProps.class, isSVG); - } - } - // style - // this flag is matched when the element has dynamic style bindings - if (patchFlag & 4 /* STYLE */) { - hostPatchProp(el, 'style', oldProps.style, newProps.style, isSVG); - } - // props - // This flag is matched when the element has dynamic prop/attr bindings - // other than class and style. The keys of dynamic prop/attrs are saved for - // faster iteration. - // Note dynamic keys like :[foo]="bar" will cause this optimization to - // bail out and go through a full diff because we need to unset the old key - if (patchFlag & 8 /* PROPS */) { - // if the flag is present then dynamicProps must be non-null - const propsToUpdate = n2.dynamicProps; - for (let i = 0; i < propsToUpdate.length; i++) { - const key = propsToUpdate[i]; - const prev = oldProps[key]; - const next = newProps[key]; - if (prev !== next) { - hostPatchProp(el, key, prev, next, isSVG, n1.children, parentComponent, parentSuspense, unmountChildren); - } - } - } - } - // text - // This flag is matched when the element has only dynamic text children. - if (patchFlag & 1 /* TEXT */) { - if (n1.children !== n2.children) { - hostSetElementText(el, n2.children); - } - } - } - else if (!optimized && dynamicChildren == null) { - // unoptimized, full diff - patchProps(el, n2, oldProps, newProps, parentComponent, parentSuspense, isSVG); - } - const areChildrenSVG = isSVG && n2.type !== 'foreignObject'; - if (dynamicChildren) { - patchBlockChildren(n1.dynamicChildren, dynamicChildren, el, parentComponent, parentSuspense, areChildrenSVG); - } - else if (!optimized) { - // full diff - patchChildren(n1, n2, el, null, parentComponent, parentSuspense, areChildrenSVG); - } - if ((vnodeHook = newProps.onVnodeUpdated) || dirs) { - queuePostRenderEffect(() => { - vnodeHook && invokeVNodeHook(vnodeHook, parentComponent, n2, n1); - dirs && invokeDirectiveHook(n2, n1, parentComponent, 'updated'); - }, parentSuspense); - } - }; - // The fast path for blocks. - const patchBlockChildren = (oldChildren, newChildren, fallbackContainer, parentComponent, parentSuspense, isSVG) => { - for (let i = 0; i < newChildren.length; i++) { - const oldVNode = oldChildren[i]; - const newVNode = newChildren[i]; - // Determine the container (parent element) for the patch. - const container = - // - In the case of a Fragment, we need to provide the actual parent - // of the Fragment itself so it can move its children. - oldVNode.type === Fragment || - // - In the case of different nodes, there is going to be a replacement - // which also requires the correct parent container - !isSameVNodeType(oldVNode, newVNode) || - // - In the case of a component, it could contain anything. - oldVNode.shapeFlag & 6 /* COMPONENT */ - ? hostParentNode(oldVNode.el) - : // In other cases, the parent container is not actually used so we - // just pass the block element here to avoid a DOM parentNode call. - fallbackContainer; - patch(oldVNode, newVNode, container, null, parentComponent, parentSuspense, isSVG, true); - } - }; - const patchProps = (el, vnode, oldProps, newProps, parentComponent, parentSuspense, isSVG) => { - if (oldProps !== newProps) { - for (const key in newProps) { - if (isReservedProp(key)) - continue; - const next = newProps[key]; - const prev = oldProps[key]; - if (next !== prev) { - hostPatchProp(el, key, prev, next, isSVG, vnode.children, parentComponent, parentSuspense, unmountChildren); - } - } - if (oldProps !== EMPTY_OBJ) { - for (const key in oldProps) { - if (!isReservedProp(key) && !(key in newProps)) { - hostPatchProp(el, key, oldProps[key], null, isSVG, vnode.children, parentComponent, parentSuspense, unmountChildren); - } - } - } - } - }; - const processFragment = (n1, n2, container, anchor, parentComponent, parentSuspense, isSVG, optimized) => { - const fragmentStartAnchor = (n2.el = n1 ? n1.el : hostCreateText('')); - const fragmentEndAnchor = (n2.anchor = n1 ? n1.anchor : hostCreateText('')); - let { patchFlag, dynamicChildren } = n2; - if (patchFlag > 0) { - optimized = true; - } - if ( parentComponent && parentComponent.renderUpdated) { - // HMR updated, force full diff - patchFlag = 0; - optimized = false; - dynamicChildren = null; - } - if (n1 == null) { - hostInsert(fragmentStartAnchor, container, anchor); - hostInsert(fragmentEndAnchor, container, anchor); - // a fragment can only have array children - // since they are either generated by the compiler, or implicitly created - // from arrays. - mountChildren(n2.children, container, fragmentEndAnchor, parentComponent, parentSuspense, isSVG, optimized); - } - else { - if (patchFlag & 64 /* STABLE_FRAGMENT */ && dynamicChildren) { - // a stable fragment (template root or