import config from '../config'
import { noop } from 'shared/util'
let warn = noop
let tip = noop
let formatComponentName
//如果是在开发环境 或者 在测试环境
if (process.env.NODE_ENV !== 'production') {
//如果 有 window.console, 这里用typeof判断, 是因为如果用 if(window.console)
//在没有console的浏览器中, window对象会增加一个属性 console, 虽然它的值是undefined, 不太确定
const hasConsole = typeof console !== 'undefined'
//这个正则就是把连接符转换成的驼峰写法, 并且第一个字符大写 ^|[-_] 的意思是 字符串的开头, 或者 -_ 后面的一个字符
// str = 'ms-border' 经过 classify(str) => MsBorder
//这里 ?: 是希望在它的这个括号不用捕获了, 也就是 (?:^|[-_])这个整体, 正则不会把它当成是一个子项, 所以 $1就是(w)
//?: 非常常见, 是为了提高正则的性能
const classifyRE = /(?:^|[-_])(w)/g
const classify = str => str
.replace(classifyRE, c => c.toUpperCase())
.replace(/[-_]/g, '')
//classifyRE = /(^|[-_])(w)/g 如果写成这样 str.replace(classifyRE,function(a,b,c){ console.log( 'a:'+a +' b:' +b+ ' c:' +c ) })
//会输出 a:a b: c:a a:-p b:- c:p
//可以看到 b第一次是开头, 开头的位置, 没有值, 所以第一次b是空
//第二次是 -
warn = (msg, vm) => {
//如果配置的console.silent, 就不会打印错误日志
if (hasConsole && (!config.silent)) {
console.error(`[Vue warn]: ${msg} ` + (
//取得vm的名字 , 如果获取不到, 提示用户配置一个
vm ? formatLocation(formatComponentName(vm)) : ''
))
}
}
//这个函数功能和上面一样, 但是上面的程度比较严重, 用了console.error, 这里是 console.warn
tip = (msg, vm) => {
if (hasConsole && (!config.silent)) {
console.warn(`[Vue tip]: ${msg} ` + (
vm ? formatLocation(formatComponentName(vm)) : ''
))
}
}
formatComponentName = (vm, includeFile) => {
//看来如果是根组件, 它会有一个属性.$root 指向它自己
if (vm.$root === vm) {
return '<Root>'
}
//这三元写的, 可读性太差, 源码这么写是为了节省代码, 简单的来说就是先看option有没自定义name,如果没有就用vm.name, 这个name应该是vue自己配置的一个随机数
let name = typeof vm === 'string'
? vm
: typeof vm === 'function' && vm.options
? vm.options.name
: vm._isVue
? vm.$options.name || vm.$options._componentTag
: vm.name
const file = vm._isVue && vm.$options.__file
if (!name && file) {
// abc/dd.vue 获取其中的dd , 也就是组件的名称
const match = file.match(/([^/\]+).vue$/)
//全匹配时 dd.vue, 第一个子项是 dd
name = match && match[1]
}
return (
// 这里使用了es6的语法 ${变量名}, 最终返回驼峰
(name ? `<${classify(name)}>` : `<Anonymous>`) +
//提示文件路径出错
(file && includeFile !== false ? ` at ${file}` : '')
)
}
// 就是返回那段 (found in component <...> )
const formatLocation = str => {
if (str === `<Anonymous>`) {
// 如果是本地调试? 提示用户配置名字, 跟容易跟踪出错信息
str += ` - use the "name" option for better debugging messages.`
}
return `
(found in ${str})`
}
}
export { warn, tip, formatComponentName }