随着Vue框架状态越来越火热,不少feder已经不仅仅满足于vue框架的使用,有很多人都打算阅读vue源码来提升自己。那么提到源码阅读就不免产生了一个问题,到底要从何处开始源码阅读呢?
package的入口:
// package.json
"main": "dist/vue.runtime.common.js"
经过全局搜索文件名找到入口源码的打包配置在scripts/config.js
// scripts/config.js
'web-runtime-cjs-dev': {
entry: resolve('web/entry-runtime.js'),
dest: resolve('dist/vue.runtime.common.dev.js'),
format: 'cjs',
env: 'development',
banner
},
'web-runtime-cjs-prod': {
entry: resolve('web/entry-runtime.js'),
dest: resolve('dist/vue.runtime.common.prod.js'),
format: 'cjs',
env: 'production',
banner
}
即项目入口为:
// scripts/config.js
resolve('web/entry-runtime.js')
可以看到这个地址并非是直接目录,同文件内找到解析函数resolve:
// scripts/config.js
const aliases = require('./alias')
const resolve = p => {
const base = p.split('/')[0]
if (aliases[base]) {
return path.resolve(aliases[base], p.slice(base.length + 1))
} else {
return path.resolve(__dirname, '../', p)
}
}
可以看到这个地址解析函数引入了别名文件,并且取’/‘之前的作为别名检查存在性,如果不存在则整体进行解析,可以看到入口文件的’/'之前是web,打开别名文件./alias
// scripts/alias.js
module.exports = {
vue: resolve('src/platforms/web/entry-runtime-with-compiler'),
compiler: resolve('src/compiler'),
core: resolve('src/core'),
shared: resolve('src/shared'),
web: resolve('src/platforms/web'),
weex: resolve('src/platforms/weex'),
server: resolve('src/server'),
sfc: resolve('src/sfc')
}
可以看到web这个别名是存在的,因此入口地址
resolve('web/entry-runtime.js')
将被解析为:
src/platforms/web/entry-runtime.js
打开该文件:
// src/platforms/web/entry-runtime.js
import Vue from './runtime/index'
export default Vue
即入口文件在此处的操作是引入./runtime/inde并暴露出去,因此核心文件的解析将从src/platforms/web/runtime/index.js开始
// src/platforms/web/runtime/index.js
/* @flow */
import Vue from 'core/index'
import config from 'core/config'
import {
extend, noop } from 'shared/util'
import {
mountComponent } from 'core/instance/lifecycle'
import {
devtools, inBrowser } from 'core/util/index'
import {
query,
mustUseProp,
isReservedTag,
isReservedAttr,
getTagNamespace,
isUnknownElement
} from 'web/util/index'
import {
patch } from './patch'
import platformDirectives from './directives/index'
import platformComponents from './components/index'
// install platform specific utils
// 标签及属性使用限制
Vue.config.mustUseProp = mustUseProp
// 判定是否为html或svg标签
Vue.config.isReservedTag = isReservedTag
// 判定是否为style、class
Vue.config.isReservedAttr = isReservedAttr
// 获取tag的命名空间
Vue.config.getTagNamespace = getTagNamespace
// 判定标签是否为未定义标签
Vue.config.isUnknownElement = isUnknownElement
// install platform runtime directives & components
// 给vue原型链上进行方法挂载
// 将platformDirectives对象可枚举属性拷贝给Vue.options.directives
extend(Vue.options.directives, platformDirectives)
extend(Vue.options.components, platformComponents)
// install platform patch function
Vue.prototype.__patch__ = inBrowser ? patch : noop
// public mount method
Vue.prototype.$mount = function (
el?: string | Element,
hydrating?: boolean
): Component {
el = el && inBrowser ? query(el) : undefined
return mountComponent(this, el, hydrating)
}
// devtools global hook
/* istanbul ignore next */
if (inBrowser) {
setTimeout(() => {
// 开发者工具init事件触发及提示
if (config.devtools) {
if (devtools) {
devtools.emit('init', Vue)
} else if (
process.env.N