Vue源码学习 - shared目录公共函数

Vue 源码学习 - shared 目录公共方法

Banner
shared目录中共有以下文件:

  • codeframe.ts
  • domAttrConfig.ts
  • domTagConfig.ts
  • escapeHtml.ts
  • general.ts
  • globalsAllowList.ts
  • looseEqual.ts
  • makeMap.ts
  • normalizeProp.ts
  • patchFlags.ts
  • shapeFlags.ts
  • slotFlags.ts
  • toDisplayString.ts
  • typeUtils.ts

内容很长,保持耐心。

makeMap.ts 文件

makeMap 函数

/*! #__NO_SIDE_EFFECTS__ */
export function makeMap(
  str: string,
  expectsLowerCase?: boolean,
): (key: string) => boolean {
  const set = new Set(str.split(','))
  return expectsLowerCase
  ? val => set.has(val.toLowerCase())
   : val => set.has(val)
}

makeMap 函数用于根据传入的字符串创建一个 Set 对象,并返回一个用于检查给定的键是否在该集合中的函数。参数 expectsLowerCase 决定了在检查时是否将键转换为小写。使用 Set 而不是数组进行判断的优势在于:

  • 查找操作平均时间复杂度为 O(1),效率更高,尤其在元素数量较多时。
  • 元素具有唯一性,能自动去重。

looseEqual.ts 文件

looseCompareArrays 函数

function looseCompareArrays(a: any[], b: any[]) {
  if (a.length!== b.length) return false
  let equal = true
  for (let i = 0; equal && i < a.length; i++) {
    equal = looseEqual(a[i], b[i])
  }
  return equal
}

该函数用于对两个数组进行宽松比较,如果两个数组长度不同则直接返回 false,否则逐个比较数组元素,只要有一个元素不相等就停止比较并返回 false,全部相等则返回 true

looseEqual 函数

export function looseEqual(a: any, b: any): boolean {
  if (a === b) return true
  let aValidType = isDate(a)
  let bValidType = isDate(b)
  if (aValidType || bValidType) {
    return aValidType && bValidType? a.getTime() === b.getTime() : false
  }
  aValidType = isSymbol(a)
  bValidType = isSymbol(b)
  if (aValidType || bValidType) {
    return a === b
  }
  aValidType = isArray(a)
  bValidType = isArray(b)
  if (aValidType || bValidType) {
    return aValidType && bValidType? looseCompareArrays(a, b) : false
  }
  aValidType = isObject(a)
  bValidType = isObject(b)
  if (aValidType || bValidType) {
    /* istanbul ignore if: this if will probably never be called */
    if (!aValidType ||!bValidType) {
      return false
    }
    const aKeysCount = Object.keys(a).length
    const bKeysCount = Object.keys(b).length
    if (aKeysCount!== bKeysCount) {
      return false
    }
    for (const key in a) {
      const aHasKey = a.hasOwnProperty(key)
      const bHasKey = b.hasOwnProperty(key)
      if (
        (aHasKey &&!bHasKey) ||
        (!aHasKey && bHasKey) ||
      !looseEqual(a[key], b[key])
      ) {
        return false
      }
    }
  }
  return String(a) === String(b)
}

looseEqual 函数用于对两个值进行宽松的相等性比较。它会根据值的类型进行不同的处理,包括日期、符号、数组、对象等。对于对象,会比较属性的个数和属性值。

looseIndexOf 函数

export function looseIndexOf(arr: any[], val: any): number {
  return arr.findIndex(item => looseEqual(item, val))
}

looseIndexOf 函数通过调用 looseEqual 函数来查找数组中与给定值宽松相等的元素的索引。

这些函数在处理不同类型的数据的相等性判断和数组操作中发挥了重要作用,为 Vue 框架的其他部分提供了基础的比较和查找功能。


globalsAllowList.ts 文件

isGloballyAllowed 函数

import { makeMap } from './makeMap'

const GLOBALS_ALLOWED =
  'Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,' +
  'decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,' +
  'Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt,console,Error,Symbol'

export const isGloballyAllowed: (key: string) => boolean =
  /*#__PURE__*/ makeMap(GLOBALS_ALLOWED)

isGloballyAllowed 函数通过调用 makeMap 函数,基于预定义的全局允许的字符串列表 GLOBALS_ALLOWED 创建了一个用于判断给定字符串是否在允许列表中的函数。这有助于在特定的上下文中对全局相关的标识符进行有效和便捷的检查和控制。 咱不清楚此函数用在Vue3源码中的何处。


general.ts文件

export const EMPTY_OBJ: { readonly [key: string]: any } = __DEV__
 ? Object.freeze({})
  : {}

EMPTY_OBJ:在开发环境(__DEV__ 为真)时是一个冻结的空对象,在生产环境时是一个普通的空对象。

export const EMPTY_ARR: readonly never[] = __DEV__? Object.freeze([]) : []

EMPTY_ARR:开发环境下是冻结的空数组,生产环境下是普通空数组。

export const NOOP = (): void => {}

NOOP:这是一个空函数,不执行任何具体操作。

/**
 * Always return false.
 */
export const NO = () => false

NO:总是返回 false 的函数。

export const isOn = (key: string): boolean =>
  key.charCodeAt(0) === 111 /* o */ &&
  key.charCodeAt(1) === 110 /* n */ &&
  // uppercase letter
  (key.charCodeAt(2) > 122 || key.charCodeAt(2) < 97)

isOn:根据输入字符串 key 的前几个字符的编码来判断是否符合特定条件,用于检测是否与某种特定的格式匹配。

export const isModelListener = (key: string): key is `onUpdate:${string}` =>
  key.startsWith('onUpdate:')

isModelListener:判断输入的字符串 key 是否以 'onUpdate:' 开头。

export const extend: typeof Object.assign = Object.assign

extend:直接引用了 Object.assign 方法。

export const remove = <T>(arr: T[], el: T): void => {
  const i = arr.indexOf(el)
  if (i > -1) {
    arr.splice(i, 1)
  }
}

remove:用于从给定的数组 arr 中移除指定的元素 el

const hasOwnProperty = Object.prototype.hasOwnProperty
export const hasOwn = (
  val: object,
  key: string | symbol,
): key is keyof typeof val => hasOwnProperty.call(val, key)

hasOwn:基于 Object.prototype.hasOwnProperty 来判断对象 val 是否具有指定的属性 key

export const isArray: typeof Array.isArray = Array.isArray

isArray:使用 Array.isArray 来判断一个值是否为数组。

export const isMap = (val: unknown): val is Map<any, any> =>
  toTypeString(val) === '[object Map]'

isMap:通过获取值的类型字符串并与 '[object Map]' 比较来判断是否为 Map

export const isSet = (val: unknown): val is Set<any> =>
  toTypeString(val) === '[object Set]'

isSet:通过类型字符串判断是否为 Set

export const isDate = (val: unknown): val is Date =>
  toTypeString(val) === '[object Date]'

isDate:根据类型字符串判断是否为 Date 类型。

export const isRegExp = (val: unknown): val is RegExp =>
  toTypeString(val) === '[object RegExp]'

isRegExp:通过类型字符串判断是否为正则表达式类型。

export const isFunction = (val: unknown): val is Function =>
  typeof val === 'function'

isFunction:通过 typeof 操作符判断是否为函数类型。

export const isString = (val: unknown): val is string => typeof val ==='string'

isString:通过 typeof 判断是否为字符串类型。

export const isSymbol = (val: unknown): val is symbol => typeof val ==='symbol'

isSymbol:通过 typeof 判断是否为符号类型。

export const isObject = (val: unknown): val is Record<any, any> =>
  val!== null && typeof val === 'object'

isObject:判断值不为 null 且类型为 object

export const isPromise = <T = any>(val: unknown): val is Promise<T> => {
  return (
    (isObject(val) || isFunction(val)) &&
    isFunction((val as any).then) &&
    isFunction((val as any).catch)
  )
}

isPromise:判断一个值是否为 Promise ,通过检查其类型以及是否具有 thencatch 方法。

export const objectToString: typeof Object.prototype.toString =
  Object.prototype.toString

objectToString:引用了 Object.prototype.toString 方法。

export const toTypeString = (value: unknown): string =>
  objectToString.call(value)

toTypeString:调用 objectToString.call 来获取输入值的类型字符串。

export const toRawType = (value: unknown): string => {
  // extract "RawType" from strings like "[object RawType]"
  return toTypeString(value).slice(8, -1)
}

toRawType:从通过 toTypeString 获取的类型字符串中提取出原始类型部分。

export const isPlainObject = (val: unknown): val is object =>
  toTypeString(val) === '[object Object]'

isPlainObject:通过类型字符串判断是否为普通对象。

export const isIntegerKey = (key: unknown): boolean =>
  isString(key) &&
  key!== 'NaN' &&
  key[0]!== '-' &&
  '' + parseInt(key, 10) === key

isIntegerKey:判断输入的键是否为整数格式的字符串。

export const isReservedProp: (key: string) => boolean = /*#__PURE__*/ makeMap(
  // the leading comma is intentional so empty string "" is also included
  ',key,ref,ref_for,ref_key,' +
    'onVnodeBeforeMount,onVnodeMounted,' +
    'onVnodeBeforeUpdate,onVnodeUpdated,' +
    'onVnodeBeforeUnmount,onVnodeUnmounted',
)

isReservedProp:使用 makeMap 函数创建的用于判断字符串是否为预留属性的函数。

export const isBuiltInDirective: (key: string) => boolean =
  /*#__PURE__*/ makeMap(
    'bind,cloak,else-if,else,for,html,if,model,on,once,pre,show,slot,text,memo',
  )

isBuiltInDirective:通过 makeMap 生成用于判断是否为内置指令的函数。

const cacheStringFunction = <T extends (str: string) => string>(fn: T): T => {
  const cache: Record<string, string> = Object.create(null)
  return ((str: string) => {
    const hit = cache[str]
    return hit || (cache[str] = fn(str))
  }) as T
}

cacheStringFunction:用于对字符串处理函数进行缓存优化。

const camelizeRE = /-(\w)/g
/**
 * @private
 */
export const camelize: (str: string) => string = cacheStringFunction(
  (str: string): string => {
    return str.replace(camelizeRE, (_, c) => (c? c.toUpperCase() : ''))
  },
)

camelize:将连字符分隔的字符串转换为驼峰格式,并进行缓存优化。

const hyphenateRE = /\B([A-Z])/g
/**
 * @private
 */
export const hyphenate: (str: string) => string = cacheStringFunction(
  (str: string) => str.replace(hyphenateRE, '-$1').toLowerCase(),
)

hyphenate:将驼峰格式字符串转换为连字符分隔的格式,并进行缓存优化。

/**
 * @private
 */
export const capitalize: <T extends string>(str: T) => Capitalize<T> =
  cacheStringFunction(<T extends string>(str: T) => {
    return (str.charAt(0).toUpperCase() + str.slice(1)) as Capitalize<T>
  })

capitalize:将字符串的首字母大写,并进行缓存优化。

/**
 * @private
 */
export const toHandlerKey: <T extends string>(
  str: T,
) => T extends ''? '' : `on${Capitalize<T>}` = cacheStringFunction(
  <T extends string>(str: T) => {
    const s = str? `on${capitalize(str)}` : ''
    return s as T extends ''? '' : `on${Capitalize<T>}`
  },
)

toHandlerKey:根据输入字符串生成特定的处理键,并进行缓存优化。

// compare whether a value has changed, accounting for NaN.
export const hasChanged = (value: any, oldValue: any): boolean =>
 !Object.is(value, oldValue)

hasChanged:比较两个值是否发生变化,考虑了 NaN 的情况。

export const invokeArrayFns = (fns: Function[],...arg: any[]): void => {
  for (let i = 0; i < fns.length; i++) {
    fns[i](...arg)
  }
}

invokeArrayFns:依次执行函数数组中的每个函数,并传递给定的参数。

export const def = (
  obj: object,
  key: string | symbol,
  value: any,
  writable = false,
): void => {
  Object.defineProperty(obj, key, {
    configurable: true,
    enumerable: false,
    writable,
    value,
  })
}

def:用于定义对象的属性。

/**
 * "123-foo" will be parsed to 123
 * This is used for the.number modifier in v-model
 */
export const looseToNumber = (val: any): any => {
  const n = parseFloat(val)
  return isNaN(n)? val : n
}

looseToNumber:尝试将输入值解析为浮点数,如果无法解析则返回原始值。

/**
 * Only concerns number-like strings
 * "123-foo" will be returned as-is
 */
export const toNumber = (val: any): any => {
  const n = isString(val)? Number(val) : NaN
  return isNaN(n)? val : n
}

toNumber:将字符串转换为数字,如果无法转换则返回原始值。

// for typeof global checks without @types/node
declare var global: {}

let _globalThis: any
export const getGlobalThis = (): any => {
  return (
    _globalThis ||
    (_globalThis =
      typeof globalThis!== 'undefined'
      ? globalThis
       : typeof self!== 'undefined'
        ? self
         : typeof window!== 'undefined'
          ? window
           : typeof global!== 'undefined'
            ? global
             : {})
  )
}

getGlobalThis:获取全局对象。

const identRE = /^[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*$/

export function genPropsAccessExp(name: string): string {
  return identRE.test(name)
  ? `__props.${name}`
   : `__props[${JSON.stringify(name)}]`
}

genPropsAccessExp:根据输入的名称生成属性访问表达式。


escapeHtml.ts文件

escapeRE 常量

const escapeRE = /["'&<>]/

escapeRE :定义了一个用于匹配需要进行 HTML 转义的特定字符("'&<> )的正则表达式。

escapeHtml 函数

export function escapeHtml(string: unknown): string {
  const str = '' + string
  const match = escapeRE.exec(str)

  if (!match) {
    return str
  }

  let html = ''
  let escaped: string
  let index: number
  let lastIndex = 0

  for (index = match.index; index < str.length; index++) {
    switch (str.charCodeAt(index)) {
      case 34: // "
        escaped = '&quot;'
        break
      case 38: // &
        escaped = '&amp;'
        break
      case 39: // '
        escaped = '&#39;'
        break
      case 60: // <
        escaped = '&lt;'
        break
      case 62: // >
        escaped = '&gt;'
        break
      default:
        continue
    }

    if (lastIndex!== index) {
      html += str.slice(lastIndex, index)
    }

    lastIndex = index + 1
    html += escaped
  }

  return lastIndex!== index? html + str.slice(lastIndex, index) : html
}

escapeHtml 函数的算法流程如下:

  1. 首先,将输入的未知类型 string 转换为字符串 str ,并通过 escapeRE.exec(str) 查找是否存在需要转义的字符。如果没有找到匹配的字符,直接返回原始字符串 str

  2. 初始化一些变量:html 用于存储转义后的结果字符串,escaped 用于存储对应字符的转义字符,index 用于遍历字符串的索引,lastIndex 用于记录上一次处理到的位置。

  3. 进入一个循环,从找到的第一个需要转义的字符的索引位置开始,一直到字符串的末尾。

  4. 在循环中,通过 str.charCodeAt(index) 获取当前字符的编码,并根据编码进行不同的处理:

    • 对于特定的编码(34 表示 "38 表示 &39 表示 '60 表示 <62 表示 > ),设置相应的转义字符到 escaped 变量。
    • 如果当前位置与上一次处理的位置不同,将这之间的原始字符片段添加到 html 中。
  5. 更新 lastIndex 为当前位置加 1,并将转义字符添加到 html 中。

  6. 循环结束后,如果 lastIndex 不等于字符串的末尾索引,将剩余的原始字符片段添加到 html 中。

  7. 最终返回构建好的转义后的字符串 html

总的来说,这个函数通过逐步处理字符串中的每个字符,对需要转义的字符进行替换,从而生成符合 HTML 规范的转义字符串。

commentStripRE 常量

// https://www.w3.org/TR/html52/syntax.html#comments
const commentStripRE = /^-?>|<!--|-->|--!>|<!-$/g

commentStripRE :定义了一个用于匹配 HTML 注释相关模式的正则表达式。

escapeHtmlComment 函数

export function escapeHtmlComment(src: string): string {
  return src.replace(commentStripRE, '')
}

escapeHtmlComment :该函数使用 commentStripRE 正则表达式对输入的字符串进行替换操作,以去除其中的 HTML 注释部分。


domTagConfig.ts文件

HTML_TAGS 常量

const HTML_TAGS =
  'html,body,base,head,link,meta,style,title,address,article,aside,footer,' +
  'header,hgroup,h1,h2,h3,h4,h5,h6,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,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,' +
  'summary,template,blockquote,iframe,tfoot'

HTML_TAGS :包含了一系列常见的 HTML 标签名称的字符串。

SVG_TAGS 常量

const SVG_TAGS =
  'svg,animate,animateMotion,animateTransform,circle,clipPath,color-profile,' +
  'defs,desc,discard,ellipse,feBlend,feColorMatrix,feComponentTransfer,' +
  'feComposite,feConvolveMatrix,feDiffuseLighting,feDisplacementMap,' +
  'feDistantLight,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'

SVG_TAGS :包含了一系列 SVG 标签名称的字符串。

MATH_TAGS 常量

const MATH_TAGS =
  'annotation,annotation-xml,maction,maligngroup,malignmark,math,menclose,' +
  'merror,mfenced,mfrac,mfraction,mglyph,mi,mlabeledtr,mlongdiv,' +
  'mmultiscripts,mn,mo,mover,mpadded,mphantom,mprescripts,mroot,mrow,ms,' +
  'mscarries,mscarry,msgroup,msline,mspace,msqrt,msrow,mstack,mstyle,msub,' +
  'msubsup,msup,mtable,mtd,mtext,mtr,munder,munderover,none,semantics'

MATH_TAGS :包含了一系列 MathML 标签名称的字符串。

VOID_TAGS 常量

const VOID_TAGS =
  'area,base,br,col,embed,hr,img,input,link,meta,param,source,track,wbr'

VOID_TAGS :包含了一系列空标签名称的字符串。

isHTMLTag 函数

/**
 * Compiler only.
 * Do NOT use in runtime code paths unless behind `__DEV__` flag.
 */
export const isHTMLTag: (key: string) => boolean =
  /*#__PURE__*/ makeMap(HTML_TAGS)

isHTMLTag :通过 makeMap 函数基于 HTML_TAGS 创建的用于判断输入字符串是否为 HTML 标签的函数。

isSVGTag 函数

/**
 * Compiler only.
 * Do NOT use in runtime code paths unless behind `__DEV__` flag.
 */
export const isSVGTag: (key: string) => boolean =
  /*#__PURE__*/ makeMap(SVG_TAGS)

isSVGTag :通过 makeMap 函数基于 SVG_TAGS 创建的用于判断输入字符串是否为 SVG 标签的函数。

isMathMLTag 函数

/**
 * Compiler only.
 * Do NOT use in runtime code paths unless behind `__DEV__` flag.
 */
export const isMathMLTag: (key: string) => boolean =
  /*#__PURE__*/ makeMap(MATH_TAGS)

isMathMLTag :通过 makeMap 函数基于 MATH_TAGS 创建的用于判断输入字符串是否为 MathML 标签的函数。

isVoidTag 函数

/**
 * Compiler only.
 * Do NOT use in runtime code paths unless behind `__DEV__` flag.
 */
export const isVoidTag: (key: string) => boolean =
  /*#__PURE__*/ makeMap(VOID_TAGS)

isVoidTag :通过 makeMap 函数基于 VOID_TAGS 创建的用于判断输入字符串是否为空标签的函数。

这些函数和常量主要用于在编译器中进行不同类型标签的判断和处理。


domAttrConfig.ts文件

isSpecialBooleanAttr 函数

const specialBooleanAttrs = `itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly`
export const isSpecialBooleanAttr: (key: string) => boolean =
  /*#__PURE__*/ makeMap(specialBooleanAttrs)

isSpecialBooleanAttr :通过 makeMap 函数基于 specialBooleanAttrs 字符串创建,用于判断输入的字符串是否为特殊的布尔型属性。

isBooleanAttr 函数

/**
 * The full list is needed during SSR to produce the correct initial markup.
 */
export const isBooleanAttr: (key: string) => boolean = /*#__PURE__*/ makeMap(
  specialBooleanAttrs +
    `,async,autofocus,autoplay,controls,default,defer,disabled,hidden,` +
    `inert,loop,open,required,reversed,scoped,seamless,` +
    `checked,muted,multiple,selected`,
)

isBooleanAttr :通过 makeMap 函数创建,用于判断输入的字符串是否为布尔型属性。

includeBooleanAttr 函数

/**
 * Boolean attributes should be included if the value is truthy or ''.
 * e.g. `<select multiple>` compiles to `{ multiple: '' }`
 */
export function includeBooleanAttr(value: unknown): boolean {
  return!!value || value === ''
}

includeBooleanAttr :用于判断给定的值是否应该被包含作为布尔型属性的值,只要值为真值或空字符串则返回 true

isSSRSafeAttrName 函数

const unsafeAttrCharRE = /[>/="'\u0009\u000a\u000c\u0020]/
const attrValidationCache: Record<string, boolean> = {}

export function isSSRSafeAttrName(name: string): boolean {
  if (attrValidationCache.hasOwnProperty(name)) {
    return attrValidationCache[name]
  }
  const isUnsafe = unsafeAttrCharRE.test(name)
  if (isUnsafe) {
    console.error(`unsafe attribute name: ${name}`)
  }
  return (attrValidationCache[name] =!isUnsafe)
}

isSSRSafeAttrName :检查属性名称是否安全,通过正则表达式 unsafeAttrCharRE 来判断,如果不安全会打印错误信息,并将结果缓存起来。

propsToAttrMap 对象

export const propsToAttrMap: Record<string, string | undefined> = {
  acceptCharset: 'accept-charset',
  className: 'class',
  htmlFor: 'for',
  httpEquiv: 'http-equiv',
}

propsToAttrMap :一个映射对象,将一些属性名称转换为对应的 HTML 属性名称。

isKnownHtmlAttr 函数

/**
 * Known attributes, this is used for stringification of runtime static nodes
 * so that we don't stringify bindings that cannot be set from HTML.
 * Don't also forget to allow `data-*` and `aria-*`!
 * Generated from https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes
 */
export const isKnownHtmlAttr: (key: string) => boolean = /*#__PURE__*/ makeMap(
  `accept,accept-charset,accesskey,action,align,allow,alt,async,` +
    `autocapitalize,autocomplete,autofocus,autoplay,background,bgcolor,` +
    `border,buffered,capture,challenge,charset,checked,cite,class,code,` +
    `codebase,color,cols,colspan,content,contenteditable,contextmenu,controls,` +
    `coords,crossorigin,csp,data,datetime,decoding,default,defer,dir,dirname,` +
    `disabled,download,draggable,dropzone,enctype,enterkeyhint,for,form,` +
    `formaction,formenctype,formmethod,formnovalidate,formtarget,headers,` +
    `height,hidden,high,href,hreflang,http-equiv,icon,id,importance,inert,integrity,` +
    `ismap,itemprop,keytype,kind,label,lang,language,loading,list,loop,low,` +
    `manifest,max,maxlength,minlength,media,min,multiple,muted,name,novalidate,` +
    `open,optimum,pattern,ping,placeholder,poster,preload,radiogroup,readonly,` +
    `referrerpolicy,rel,required,reversed,rows,rowspan,sandbox,scope,scoped,` +
    `selected,shape,size,sizes,slot,span,spellcheck,src,srcdoc,srclang,srcset,` +
    `start,step,style,summary,tabindex,target,title,translate,type,usemap,` +
    `value,width,wrap`,
)

isKnownHtmlAttr :通过 makeMap 函数创建,用于判断输入的字符串是否为已知的 HTML 属性。

isKnownSvgAttr 函数

/**
 * Generated from https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute
 */
export const isKnownSvgAttr: (key: string) => boolean = /*#__PURE__*/ makeMap(
  `xmlns,accent-height,accumulate,additive,alignment-baseline,alphabetic,amplitude,` +
    `arabic-form,ascent,attributeName,attributeType,azimuth,baseFrequency,` +
    `baseline-shift,baseProfile,bbox,begin,bias,by,calcMode,cap-height,class,` +
    `clip,clipPathUnits,clip-path,clip-rule,color,color-interpolation,` +
    `color-interpolation-filters,color-profile,color-rendering,` +
    `contentScriptType,contentStyleType,crossorigin,cursor,cx,cy,d,decelerate,` +
    `descent,diffuseConstant,direction,display,divisor,dominant-baseline,dur,dx,` +
    `dy,edgeMode,elevation,enable-background,end,exponent,fill,fill-opacity,` +
    `fill-rule,filter,filterRes,filterUnits,flood-color,flood-opacity,` +
    `font-family,font-size,font-size-adjust,font-stretch,font-style,` +
    `font-variant,font-weight,format,from,fr,fx,fy,g1,g2,glyph-name,` +
    `glyph-orientation-horizontal,glyph-orientation-vertical,glyphRef,` +
    `gradientTransform,gradientUnits,hanging,height,href,hreflang,horiz-adv-x,` +
    `horiz-origin-x,id,ideographic,image-rendering,in,in2,intercept,k,k1,k2,k3,` +
    `k4,kernelMatrix,kernelUnitLength,kerning,keyPoints,keySplines,keyTimes,` +
    `lang,lengthAdjust,letter-spacing,lighting-color,limitingConeAngle,local,` +
    `marker-end,marker-mid,marker-start,markerHeight,markerUnits,markerWidth,` +
    `mask,maskContentUnits,maskUnits,mathematical,max,media,method,min,mode,` +
    `name,numOctaves,offset,opacity,operator,order,orient,orientation,origin,` +
    `overflow,overline-position,overline-thickness,panose-1,paint-order,path,` +
    `pathLength,patternContentUnits,patternTransform,patternUnits,ping,` +
    `pointer-events,points,pointsAtX,pointsAtY,pointsAtZ,preserveAlpha,` +
    `preserveAspectRatio,primitiveUnits,r,radius,referrerPolicy,refX,refY,rel,` +
    `rendering-intent,repeatCount,repeatDur,requiredExtensions,requiredFeatures,` +
    `restart,result,rotate,rx,ry,scale,seed,shape-rendering,slope,spacing,` +
    `specularConstant,specularExponent,speed,spreadMethod,startOffset,` +
    `stdDeviation,stemh,stemv,stitchTiles,stop-color,stop-opacity,` +
    `strikethrough-position,strikethrough-thickness,string,stroke,` +
    `stroke-dasharray,stroke-dashoffset,stroke-linecap,stroke-linejoin,` +
    `stroke-miterlimit,stroke-opacity,stroke-width,style,surfaceScale,` +
    `systemLanguage,tabindex,tableValues,target,targetX,targetY,text-anchor,` +
    `text-decoration,text-rendering,textLength,to,transform,transform-origin,` +
    `type,u1,u2,underline-position,underline-thickness,unicode,unicode-bidi,` +
    `unicode-range,units-per-em,v-alphabetic,v-hanging,v-ideographic,` +
    `v-mathematical,values,vector-effect,version,vert-adv-y,vert-origin-x,` +
    `vert-origin-y,viewBox,viewTarget,visibility,width,widths,word-spacing,` +
    `writing-mode,x,x-height,x1,x2,xChannelSelector,xlink:actuate,xlink:arcrole,` +
    `xlink:href,xlink:role,xlink:show,xlink:title,xlink:type,xmlns:xlink,xml:base,xml:lang,` +
    `xml:space,y,y1,y2,yChannelSelector,z,zoomAndPan`,
)

isKnownSvgAttr :通过 makeMap 函数创建,用于判断输入的字符串是否为已知的 SVG 属性。

isRenderableAttrValue 函数

/**
 * Shared between server-renderer and runtime-core hydration logic
 */
export function isRenderableAttrValue(value: unknown): boolean {
  if (value == null) {
    return false
  }
  const type = typeof value
  return type ==='string' || type === 'number' || type === 'boolean'
}

isRenderableAttrValue :用于判断属性值是否可渲染,只要值的类型为字符串、数字或布尔值则返回 true

codeFrame.ts文件

generateCodeFrame 函数

const range: number = 2

export function generateCodeFrame(
  source: string,
  start = 0,
  end: number = source.length,
): string {
  // 确保起始和结束位置在源字符串的有效范围内
  start = Math.max(0, Math.min(start, source.length))
  end = Math.max(0, Math.min(end, source.length))

  if (start > end) return ''

  // 将源字符串按换行符(包括换行符序列)拆分成行
  let lines = source.split(/(\r?\n)/)

  // 将换行符序列和行内容分别存储在不同的数组中
  const newlineSequences = lines.filter((_, idx) => idx % 2 === 1)
  lines = lines.filter((_, idx) => idx % 2 === 0)

  let count = 0
  const res: string[] = []

  for (let i = 0; i < lines.length; i++) {
    count +=
      lines[i].length +
      ((newlineSequences[i] && newlineSequences[i].length) || 0)
    if (count >= start) {
      for (let j = i - range; j <= i + range || end > count; j++) {
        if (j < 0 || j >= lines.length) continue
        const line = j + 1
        res.push(
          `${line}${' '.repeat(Math.max(3 - String(line).length, 0))}|  ${lines[j]}`,
        )
        const lineLength = lines[j].length
        const newLineSeqLength =
          (newlineSequences[j] && newlineSequences[j].length) || 0

        if (j === i) {
          // 推送上划线
          const pad = start - (count - (lineLength + newLineSeqLength))
          const length = Math.max(
            1,
            end > count? lineLength - pad : end - start,
          )
          res.push(`   |  ` + ' '.repeat(pad) + '^'.repeat(length))
        } else if (j > i) {
          if (end > count) {
            const length = Math.max(Math.min(end - count, lineLength), 1)
            res.push(`   |  ` + '^'.repeat(length))
          }

          count += lineLength + newLineSeqLength
        }
      }
      break
    }
  }
  return res.join('\n')
}

generateCodeFrame 函数的作用是根据给定的源字符串、起始位置和结束位置,生成包含指定范围前后几行代码的代码框架。通过对源字符串按行拆分和处理,为每行添加行号,并在指定位置添加下划线标识,以更清晰地展示相关代码片段的位置和上下文。

normalizeProp.ts文件

normalizeStyle 函数

export function normalizeStyle(
  value: unknown,
): NormalizedStyle | string | undefined {
  if (isArray(value)) {
    const res: NormalizedStyle = {}
    for (let i = 0; i < value.length; i++) {
      const item = value[i]
      const normalized = isString(item)
       ? parseStringStyle(item)
        : (normalizeStyle(item) as NormalizedStyle)
      if (normalized) {
        for (const key in normalized) {
          res[key] = normalized[key]
        }
      }
    }
    return res
  } else if (isString(value) || isObject(value)) {
    return value
  }
}

normalizeStyle 函数用于规范化样式输入。如果输入是数组,会遍历数组中的每个元素,对字符串元素调用 parseStringStyle 函数处理,对其他对象元素递归调用 normalizeStyle 函数处理,并将结果合并到一个新的对象中返回。如果输入是字符串或对象,则直接返回输入值。

parseStringStyle 函数

const listDelimiterRE = /;(?![^(]*\))/g
const propertyDelimiterRE = /:([^]+)/
const styleCommentRE = /\/\*[^]*?\*\//g

export function parseStringStyle(cssText: string): NormalizedStyle {
  const ret: NormalizedStyle = {}
  cssText
  .replace(styleCommentRE, '')
  .split(listDelimiterRE)
  .forEach(item => {
      if (item) {
        const tmp = item.split(propertyDelimiterRE)
        tmp.length > 1 && (ret[tmp[0].trim()] = tmp[1].trim())
      }
    })
  return ret
}

parseStringStyle 函数用于解析字符串形式的 CSS 样式文本。它先去除注释,然后按分号分割,再处理每个属性部分,提取属性名和属性值,并存储到一个对象中返回。

stringifyStyle 函数

export function stringifyStyle(
  styles: NormalizedStyle | string | undefined,
): string {
  let ret = ''
  if (!styles || isString(styles)) {
    return ret
  }
  for (const key in styles) {
    const value = styles[key]
    if (isString(value) || typeof value === 'number') {
      const normalizedKey = key.startsWith(`--`)? key : hyphenate(key)
      // only render valid values
      ret += `${normalizedKey}:${value};`
    }
  }
  return ret
}

stringifyStyle 函数将规范化的样式对象转换为字符串形式的 CSS 样式。

normalizeClass 函数

export function normalizeClass(value: unknown): string {
  let res = ''
  if (isString(value)) {
    res = value
  } else if (isArray(value)) {
    for (let i = 0; i < value.length; i++) {
      const normalized = normalizeClass(value[i])
      if (normalized) {
        res += normalized +' '
      }
    }
  } else if (isObject(value)) {
    for (const name in value) {
      if (value[name]) {
        res += name +' '
      }
    }
  }
  return res.trim()
}

normalizeClass 函数用于规范化类名输入。如果输入是字符串,直接使用;如果是数组,递归处理每个元素并拼接;如果是对象,将值为真的属性名拼接。

normalizeProps 函数

export function normalizeProps(
  props: Record<string, any> | null,
): Record<string, any> | null {
  if (!props) return null
  let { class: klass, style } = props
  if (klass &&!isString(klass)) {
    props.class = normalizeClass(klass)
  }
  if (style) {
    props.style = normalizeStyle(style)
  }
  return props
}

normalizeProps 函数用于规范化属性对象中的 classstyle 属性。


patchFlags.ts 文件

PatchFlags 枚举

/**
 * Patch flags are optimization hints generated by the compiler.
 * when a block with dynamicChildren is encountered during diff, the algorithm
 * enters "optimized mode". In this mode, we know that the vdom is produced by
 * a render function generated by the compiler, so the algorithm only needs to
 * handle updates explicitly marked by these patch flags.
 *
 * Patch flags can be combined using the | bitwise operator and can be checked
 * using the & operator, e.g.
 *
 * ```js
 * const flag = TEXT | CLASS
 * if (flag & TEXT) {... }
 * ```
 *
 * Check the `patchElement` function in '../../runtime-core/src/renderer.ts' to see how the
 * flags are handled during diff.
 */
export enum PatchFlags {
  /**
   * Indicates an element with dynamic textContent (children fast path)
   */
  TEXT = 1,

  /**
   * Indicates an element with dynamic class binding.
   */
  CLASS = 1 << 1,

  /**
   * Indicates an element with dynamic style
   * The compiler pre-compiles static string styles into static objects
   * + detects and hoists inline static objects
   * e.g. `style="color: red"` and `:style="{ color: 'red' }"` both get hoisted
   * as:
   * ```js
   * const style = { color: 'red' }
   * render() { return e('div', { style }) }
   * ```
   */
  STYLE = 1 << 2,

  /**
   * Indicates an element that has non-class/style dynamic props.
   * Can also be on a component that has any dynamic props (includes
   * class/style). when this flag is present, the vnode also has a dynamicProps
   * array that contains the keys of the props that may change so the runtime
   * can diff them faster (without having to worry about removed props)
   */
  PROPS = 1 << 3,

  /**
   * Indicates an element with props with dynamic keys. When keys change, a full
   * diff is always needed to remove the old key. This flag is mutually
   * exclusive with CLASS, STYLE and PROPS.
   */
  FULL_PROPS = 1 << 4,

  /**
   * Indicates an element that requires props hydration
   * (but not necessarily patching)
   * e.g. event listeners & v-bind with prop modifier
   */
  NEED_HYDRATION = 1 << 5,

  /**
   * Indicates a fragment whose children order doesn't change.
   */
  STABLE_FRAGMENT = 1 << 6,

  /**
   * Indicates a fragment with keyed or partially keyed children
   */
  KEYED_FRAGMENT = 1 << 7,

  /**
   * Indicates a fragment with unkeyed children.
   */
  UNKEYED_FRAGMENT = 1 << 8,

  /**
   * Indicates an element that only needs non-props patching, e.g. ref or
   * directives (onVnodeXXX hooks). since every patched vnode checks for refs
   * and onVnodeXXX hooks, it simply marks the vnode so that a parent block
   * will track it.
   */
  NEED_PATCH = 1 << 9,

  /**
   * Indicates a component with dynamic slots (e.g. slot that references a v-for
   * iterated value, or dynamic slot names).
   * Components with this flag are always force updated.
   */
  DYNAMIC_SLOTS = 1 << 10,

  /**
   * Indicates a fragment that was created only because the user has placed
   * comments at the root level of a template. This is a dev-only flag since
   * comments are stripped in production.
   */
  DEV_ROOT_FRAGMENT = 1 << 11,

  /**
   * SPECIAL FLAGS -------------------------------------------------------------
   * Special flags are negative integers. They are never matched against using
   * bitwise operators (bitwise matching should only happen in branches where
   * patchFlag > 0), and are mutually exclusive. When checking for a special
   * flag, simply check patchFlag === FLAG.
   */

  /**
   * Indicates a cached static vnode. This is also a hint for hydration to skip
   * the entire sub tree since static content never needs to be updated.
   */
  CACHED = -1,
  /**
   * A special flag that indicates that the diffing algorithm should bail out
   * of optimized mode. For example, on block fragments created by renderSlot()
   * when encountering non-compiler generated slots (i.e. manually written
   * render functions, which should always be fully diffed)
   * OR manually cloneVNodes
   */
  BAIL = -2,
}

PatchFlags 枚举定义了一系列用于表示元素或组件在渲染过程中的不同动态更新特征的标志。这些标志可以通过位运算进行组合和检查,以优化渲染过程中的差异比较和更新操作。

PatchFlagNames 对象

/**
 * dev only flag -> name mapping
 */
export const PatchFlagNames: Record<PatchFlags, string> = {
  [PatchFlags.TEXT]: `TEXT`,
  [PatchFlags.CLASS]: `CLASS`,
  [PatchFlags.STYLE]: `STYLE`,
  [PatchFlags.PROPS]: `PROPS`,
  [PatchFlags.FULL_PROPS]: `FULL_PROPS`,
  [PatchFlags.NEED_HYDRATION]: `NEED_HYDRATION`,
  [PatchFlags.STABLE_FRAGMENT]: `STABLE_FRAGMENT`,
  [PatchFlags.KEYED_FRAGMENT]: `KEYED_FRAGMENT`,
  [PatchFlags.UNKEYED_FRAGMENT]: `UNKEYED_FRAGMENT`,
  [PatchFlags.NEED_PATCH]: `NEED_PATCH`,
  [PatchFlags.DYNAMIC_SLOTS]: `DYNAMIC_SLOTS`,
  [PatchFlags.DEV_ROOT_FRAGMENT]: `DEV_ROOT_FRAGMENT`,
  [PatchFlags.CACHED]: `HOISTED`,
  [PatchFlags.BAIL]: `BAIL`,
}

PatchFlagNames 对象是 PatchFlags 枚举中标志值与名称的映射,主要用于开发过程中的调试和理解。


shapeFlags.ts文件

ShapeFlags 枚举

export enum ShapeFlags {
  ELEMENT = 1,
  FUNCTIONAL_COMPONENT = 1 << 1,
  STATEFUL_COMPONENT = 1 << 2,
  TEXT_CHILDREN = 1 << 3,
  ARRAY_CHILDREN = 1 << 4,
  SLOTS_CHILDREN = 1 << 5,
  TELEPORT = 1 << 6,
  SUSPENSE = 1 << 7,
  COMPONENT_SHOULD_KEEP_ALIVE = 1 << 8,
  COMPONENT_KEPT_ALIVE = 1 << 9,
  COMPONENT = ShapeFlags.STATEFUL_COMPONENT | ShapeFlags.FUNCTIONAL_COMPONENT,
}

ShapeFlags 枚举定义了一系列用于表示组件或元素的不同形状特征的标志。

  • ELEMENT:表示普通元素。
  • FUNCTIONAL_COMPONENT:表示函数式组件。
  • STATEFUL_COMPONENT:表示有状态组件。
  • TEXT_CHILDREN:表示具有文本子节点。
  • ARRAY_CHILDREN:表示具有数组子节点。
  • SLOTS_CHILDREN:表示具有插槽子节点。
  • TELEPORT:表示 teleport 组件。
  • SUSPENSE:表示 suspense 组件。
  • COMPONENT_SHOULD_KEEP_ALIVE:表示组件应该被保持活跃。
  • COMPONENT_KEPT_ALIVE:表示组件已被保持活跃。
  • COMPONENT:是 STATEFUL_COMPONENTFUNCTIONAL_COMPONENT 的组合。

这些标志有助于在 Vue 的渲染和处理过程中更精确地识别和处理不同类型的组件和元素。


slotFlags.ts 文件

SlotFlags 枚举

export enum SlotFlags {
  /**
   * Stable slots that only reference slot props or context state. The slot
   * can fully capture its own dependencies so when passed down the parent won't
   * need to force the child to update.
   */
  STABLE = 1,
  /**
   * Slots that reference scope variables (v-for or an outer slot prop), or
   * has conditional structure (v-if, v-for). The parent will need to force
   * the child to update because the slot does not fully capture its dependencies.
   */
  DYNAMIC = 2,
  /**
   * `<slot/>` being forwarded into a child component. Whether the parent needs
   * to update the child is dependent on what kind of slots the parent itself
   * received. This has to be refined at runtime, when the child's vnode
   * is being created (in `normalizeChildren`)
   */
  FORWARDED = 3,
}

SlotFlags 枚举定义了用于描述插槽(slot)特征的标志。

  • STABLE:表示稳定的插槽,其仅引用插槽属性或上下文状态,父组件传递时无需强制子组件更新。
  • DYNAMIC:表示动态的插槽,引用了作用域变量或具有条件结构,父组件需要强制子组件更新。
  • FORWARDED:表示转发的插槽,父组件是否需要更新子组件取决于父组件自身接收的插槽类型,这在运行时创建子组件的虚拟节点时确定。

slotFlagsText 对象

/**
 * Dev only
 */
export const slotFlagsText: Record<SlotFlags, string> = {
  [SlotFlags.STABLE]: 'STABLE',
  [SlotFlags.DYNAMIC]: 'DYNAMIC',
  [SlotFlags.FORWARDED]: 'FORWARDED',
}

slotFlagsText 对象是 SlotFlags 枚举中标志值与字符串表示的映射,主要用于开发过程中的调试和理解。


toDisplayString.ts 文件

isRef 函数

const isRef = (val: any): val is { value: unknown } => {
  return!!(val && val[ReactiveFlags.IS_REF] === true)
}

isRef 函数用于判断输入的值是否为具有特定标识 ReactiveFlags.IS_REF 且值为 true 的对象。

toDisplayString 函数

/**
 * For converting {{ interpolation }} values to displayed strings.
 * @private
 */
export const toDisplayString = (val: unknown): string => {
  return isString(val)
  ? val
    : val == null
     ? ''
      : isArray(val) ||
          (isObject(val) &&
            (val.toString === objectToString ||!isFunction(val.toString)))
       ? isRef(val)
         ? toDisplayString(val.value)
          : JSON.stringify(val, replacer, 2)
        : String(val)
}

toDisplayString 函数用于将各种类型的输入值转换为显示字符串。

  • 如果是字符串类型,直接返回。
  • 如果值为 null ,返回空字符串。
  • 如果是数组或对象(且 toString 方法不符合特定条件),如果是 Ref 类型则递归处理其 value ,否则使用 JSON.stringify 并传入 replacer 函数进行处理。
  • 其他情况使用 String 函数进行转换。

replacer 函数

const replacer = (_key: string, val: unknown): any => {
  if (isRef(val)) {
    return replacer(_key, val.value)
  } else if (isMap(val)) {
    return {
      [`Map(${val.size})`]: [...val.entries()].reduce(
        (entries, [key, val], i) => {
          entries[stringifySymbol(key, i) + ' =>'] = val
          return entries
        },
        {} as Record<string, any>,
      ),
    }
  } else if (isSet(val)) {
    return {
      [`Set(${val.size})`]: [...val.values()].map(v => stringifySymbol(v)),
    }
  } else if (isSymbol(val)) {
    return stringifySymbol(val)
  } else if (isObject(val) &&!isArray(val) &&!isPlainObject(val)) {
    // native elements
    return String(val)
  }
  return val
}

replacer 函数用于在 JSON.stringify 过程中处理特定类型的值。

  • 如果是 Ref 类型,递归处理其 value
  • 如果是 Map 类型,将其转换为特定格式的对象。
  • 如果是 Set 类型,将其值映射为特定格式。
  • 如果是 Symbol 类型,进行特定的字符串化处理。
  • 如果是特殊的非数组、非普通对象的对象类型,使用 String 转换。

stringifySymbol 函数

const stringifySymbol = (v: unknown, i: number | string = ''): any =>
  // Symbol.description in es2019+ so we need to cast here to pass
  // the lib: es2016 check
  isSymbol(v)? `Symbol(${(v as any).description?? i})` : v

stringifySymbol 函数用于将 Symbol 类型的值转换为特定的字符串表示。


typeUtils.ts 文件

Prettify 类型

export type Prettify<T> = { [K in keyof T]: T[K] } & {}

Prettify 类型用于对输入类型 T 的每个键进行重新映射,保留其对应的值,并确保结果是一个新的对象类型。

UnionToIntersection 类型

export type UnionToIntersection<U> = (
  U extends any? (k: U) => void : never
) extends (k: infer I) => void
 ? I
  : never

UnionToIntersection 类型用于将联合类型转换为交叉类型。

LooseRequired 类型

// make keys required but keep undefined values
export type LooseRequired<T> = { [P in keyof (T & Required<T>)]: T[P] }

LooseRequired 类型将输入类型 T 的键变为必填,但仍允许值为 undefined

IfAny 类型

// If the type T accepts type "any", output type Y, otherwise output type N.
// https://stackoverflow.com/questions/49927523/disallow-call-with-any/49928360#49928360
export type IfAny<T, Y, N> = 0 extends 1 & T? Y : N

IfAny 类型根据输入类型 T 是否接受 any 类型来决定输出类型是 Y 还是 N

Awaited 类型

// To prevent users with TypeScript versions lower than 4.5 from encountering unsupported Awaited<T> type, a copy has been made here.
export type Awaited<T> = T extends null | undefined
 ? T // special case for `null | undefined` when not in `--strictNullChecks` mode
  : T extends object & { then(onfulfilled: infer F,...args: infer _): any } // `await` only unwraps object types with a callable `then`. Non-object types are not unwrapped
   ? F extends (value: infer V,...args: infer _) => any // if the argument to `then` is callable, extracts the first argument
     ? Awaited<V> // recursively unwrap the value
      : never // the argument to `then` was not callable
    : T // non-object or non-thenable

Awaited 类型用于处理 async/await 中的类型,对具有可调用 then 方法的对象类型进行递归地解包值。

OverloadParameters 类型

/**
 * Utility for extracting the parameters from a function overload (for typed emits)
 * https://github.com/microsoft/TypeScript/issues/32164#issuecomment-1146737709
 */
export type OverloadParameters<T extends (...args: any[]) => any> = Parameters<
  OverloadUnion<T>
>

OverloadParameters 类型用于从函数重载中提取参数,通过 OverloadUnion 来处理。

OverloadUnionRecursive 类型

type OverloadProps<TOverload> = Pick<TOverload, keyof TOverload>

type OverloadUnionRecursive<
  TOverload,
  TPartialOverload = unknown,
> = TOverload extends (...args: infer TArgs) => infer TReturn
 ? TPartialOverload extends TOverload
   ? never
    :
        | OverloadUnionRecursive<
            TPartialOverload & TOverload,
            TPartialOverload &
              ((...args: TArgs) => TReturn) &
              OverloadProps<TOverload>
          >
        | ((...args: TArgs) => TReturn)
  : never

OverloadUnionRecursive 类型是处理函数重载的递归类型定义。

OverloadUnion 类型

type OverloadUnion<TOverload extends (...args: any[]) => any> = Exclude<
  OverloadUnionRecursive<(() => never) & TOverload>,
  TOverload extends () => never? never : () => never
>

OverloadUnion 类型用于合并函数重载的相关类型定义。

  • 11
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 这个错误是因为在当前项目中缺少 "@vue/cli-shared-utils" 模块。 要解决这个问题,可以尝试以下几个步骤: 1. 确认你的项目中是否已经安装了 "@vue/cli-shared-utils"。你可以在项目根目录下运行命令 "npm ls @vue/cli-shared-utils" 来检查。如果没有安装,你可以尝试运行 "npm install @vue/cli-shared-utils" 来安装它。 2. 如果 "@vue/cli-shared-utils" 已经安装,那么可能是版本不兼容导致的问题。你可以尝试更新 "@vue/cli-shared-utils" 到最新版本,或者回退到一个已知可用的版本。可以在 package.json 文件中修改 "@vue/cli-shared-utils" 的版本号,然后再运行 "npm install" 命令来安装或更新模块。 3. 如果以上方法都不行,可能是因为你的项目环境没有正确配置。你可以尝试重新安装或配置你的项目环境,或者创建一个新的项目来测试。 ### 回答2: 在使用Vue开发应用程序时,有时会出现错误提示“error: cannot find module '@vue/cli-shared-utils'”这个错误信息,这个错误通常出现在使用Vue CLI命令时。 出现这个错误消息的原因可能是以下几种情况: 1、Vue CLI版本过低或者没有安装。如果您的Vue CLI版本过低,或者没有安装Vue CLI,那么会导致无法找到模块的问题。 2、您的项目缺少依赖。如果您的项目缺少依赖,比如缺少@vue/cli-shared-utils的模块,那么就会出现找不到模块的错误。 3、您的本地环境配置出现问题。在项目运行过程中,如果您的本地环境配置出现问题,比如系统缺少某些依赖包,那么就会导致出现找不到模块的错误提示。 解决这个错误的方法,可以根据实际情况来进行如下操作: 1、先检查一下您的Vue CLI版本是否过低,或者是否安装Vue CLI。 2、检查您的项目依赖是否缺少了一些必要的模块。可以通过运行npm install命令来安装所需的依赖。 3、如果您的环境配置出现了问题,那么可以尝试升级您的系统或重新安装依赖包。 总之,无论是出现找不到模块的错误还是其他的错误信息,在处理之前我们都需要认真分析错误的原因,然后再针对具体情况来进行解决。在开发过程中,要时刻保持警惕,做好代码备份,尽可能预防和排除错误,减少出错的次数,提高开发效率。 ### 回答3: “@vue/cli-shared-utils”是Vue CLI 4.x中的一个常用模块,用于处理CLI内部的一些工具函数和工具类。这个错误提示意味着在运行Vue CLI相关命令时,系统无法找到这个模块。 通常这个错误产生有以下可能原因: 1. 没有正确安装Vue CLI 4.x或者版本不对。如果你使用的是Vue CLI 3.x的版本,那么这个模块的路径和名称会有不同。 2. Node.js环境不匹配。某些Node.js版本不兼容Vue CLI 4.x,如果你使用的是旧版Node.js可能会导致找不到模块的错误。 3. 模块未安装或安装不完全。Vue CLI 4.x是基于模块化的设计,如果你安装了Vue CLI 4.x但未正确安装“@vue/cli-shared-utils”模块,则会出现此错误。 解决这个错误可以尝试以下步骤: 1. 检查Vue CLI版本是否正确,可以使用命令“vue --version”查看当前Vue CLI版本是否是4.x版本,如果不是则需要升级。 2. 检查Node.js版本是否正确,可以使用命令“node --version”查看当前Node.js版本是否支持Vue CLI 4.x。 3. 重新安装Vue CLI 4.x,并确保安装完成后使用“npm install”命令安装所有依赖包。 4. 如果以上步骤都没有解决问题,可以尝试将“@vue/cli-shared-utils”模块重新安装,使用“npm install @vue/cli-shared-utils”命令重新安装一遍依赖包。 总之,在解决Vue CLI中的错误时,需要考虑多个因素,包括版本、环境以及依赖包等等因素,找到问题的根源并加以解决。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端天花板

看值不值吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值