1、文件目录
首先来到src目录下,我们可以看到以下几个目录(由于了解尚浅,大致理解了一下)。
src
├── compiler # 编译相关
├── core # 核心代码
├── platforms # 不同平台的支持
├── server # 服务端渲染
├── sfc # .vue 文件解析
├── shared # 共享代码
2、源码构建过程
查看package.json,可以看到在scripts中有很多的可执行命令
"scripts": {
"dev": "rollup -w -c scripts/config.js --environment TARGET:web-full-dev",
"dev:cjs": "rollup -w -c scripts/config.js --environment TARGET:web-runtime-cjs-dev",
"dev:esm": "rollup -w -c scripts/config.js --environment TARGET:web-runtime-esm",
"dev:test": "karma start test/unit/karma.dev.config.js",
"dev:ssr": "rollup -w -c scripts/config.js --environment TARGET:web-server-renderer",
"dev:compiler": "rollup -w -c scripts/config.js --environment TARGET:web-compiler ",
"dev:weex": "rollup -w -c scripts/config.js --environment TARGET:weex-framework",
"dev:weex:factory": "rollup -w -c scripts/config.js --environment TARGET:weex-factory",
"dev:weex:compiler": "rollup -w -c scripts/config.js --environment TARGET:weex-compiler ",
"build": "node scripts/build.js",
"build:ssr": "npm run build -- web-runtime-cjs,web-server-renderer",
"build:weex": "npm run build -- weex",
"test": "npm run lint && flow check && npm run test:types && npm run test:cover && npm run test:e2e -- --env phantomjs && npm run test:ssr && npm run test:weex",
"test:unit": "karma start test/unit/karma.unit.config.js",
"test:cover": "karma start test/unit/karma.cover.config.js",
"test:e2e": "npm run build -- web-full-prod,web-server-basic-renderer && node test/e2e/runner.js",
"test:weex": "npm run build:weex && jasmine JASMINE_CONFIG_PATH=test/weex/jasmine.js",
"test:ssr": "npm run build:ssr && jasmine JASMINE_CONFIG_PATH=test/ssr/jasmine.js",
"test:sauce": "npm run sauce -- 0 && npm run sauce -- 1 && npm run sauce -- 2",
"test:types": "tsc -p ./types/test/tsconfig.json",
"lint": "eslint src scripts test",
"flow": "flow check",
"sauce": "karma start test/unit/karma.sauce.config.js",
"bench:ssr": "npm run build:ssr && node benchmarks/ssr/renderToString.js && node benchmarks/ssr/renderToStream.js",
"release": "bash scripts/release.sh",
"release:weex": "bash scripts/release-weex.sh",
"release:note": "node scripts/gen-release-note.js",
"commit": "git-cz"
},
我们可以看到build的过程都是在scripts/build.js文件中
1 . 首先引入了所配置文件builds
- 然后通过执行命令后的参数进行对配置的过滤
- 执行build
build函数就是一个递归过程,一直build,打包成不同的平台。
3、Runtime Only VS Runtime + Compiler
- Runtime Only
我们在使用 Runtime Only 版本的 Vue.js 的时候,通常需要借助如 webpack 的 vue-loader 工具把 .vue 文件编译成 JavaScript,因为是在编译阶段做的,所以它只包含运行时的 Vue.js 代码,因此代码体积也会更轻量。
- Runtime + Compiler
我们如果没有对代码做预编译,但又使用了 Vue 的 template 属性并传入一个字符串,则需要在客户端编译模板。
我们看源码则需要看编译的过程,则选择了compiler版本
在platform/web目录下
4、入口文件plateforms/entry-runtime-with-compiler
我们先不管具体的代码实现
import Vue from './runtime/index'
const mount = Vue.prototype.$mount
Vue.prototype.$mount = function (
el?: string | Element,
hydrating?: boolean
): Component {}
Vue.compile = compileToFunctions
export default Vue
往Vue的原型上挂载一些方法,如$mount。这个Vue的引入来自自于./runtime/index文件下
继续往前看
5、./runtime/index
import Vue from 'core/index'
// install platform specific utils
Vue.config.mustUseProp = mustUseProp
Vue.config.isReservedTag = isReservedTag
Vue.config.isReservedAttr = isReservedAttr
Vue.config.getTagNamespace = getTagNamespace
Vue.config.isUnknownElement = isUnknownElement
// install platform runtime directives & components
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)
}
export default Vue
也是往vue对象的原型或者属性上增加一些方法。继承自定义指令model,show和组件transition组件
继续往前看
6、core/index
import Vue from './instance/index'
import { initGlobalAPI } from './global-api/index'
initGlobalAPI(Vue)
Object.defineProperty(Vue.prototype, '$isServer', {
get: isServerRendering
})
Object.defineProperty(Vue.prototype, '$ssrContext', {
get () {
/* istanbul ignore next */
return this.$vnode && this.$vnode.ssrContext
}
})
// expose FunctionalRenderContext for ssr runtime helper installation
Object.defineProperty(Vue, 'FunctionalRenderContext', {
value: FunctionalRenderContext
})
Vue.version = '__VERSION__'
export default Vue
很显然易见,这个文件初始化了全局api,我们点进去这个函数
export function initGlobalAPI(Vue: GlobalAPI) {
// config
const configDef = {}
configDef.get = () => config
if (process.env.NODE_ENV !== "production") {
configDef.set = () => {
warn(
"Do not replace the Vue.config object, set individual fields instead."
)
}
}
Object.defineProperty(Vue, "config", configDef)
// exposed util methods.
// NOTE: these are not considered part of the public API - avoid relying on
// them unless you are aware of the risk.
Vue.util = {
warn,
extend,
mergeOptions,
defineReactive,
}
Vue.set = set
Vue.delete = del
Vue.nextTick = nextTick
// 2.6 explicit observable API
Vue.observable = <T>(obj: T): T => {
observe(obj)
return obj
}
Vue.options = Object.create(null)
ASSET_TYPES.forEach((type) => {
Vue.options[type + "s"] = Object.create(null)
})
// this is used to identify the "base" constructor to extend all plain-object
// components with in Weex's multi-instance scenarios.
Vue.options._base = Vue
extend(Vue.options.components, builtInComponents)
initUse(Vue)
initMixin(Vue)
initExtend(Vue)
initAssetRegisters(Vue)
}
首先是对vue的config做了一层get拦截,然后在Vue构造函数中添加了全局静态方法,如set,delete,nextTick,observable等等
然后初始化了一些很多东西
initUse(Vue) 定义Vue.use()方法
initMixin(Vue) 原型上挂载_init方法
initExtend(Vue) 定义extend方法
initAssetRegisters(Vue)
我们继续往前走
7、instance/index
终于看到了vue的庐山真面目,一个构造函数
function Vue(options) {
if (process.env.NODE_ENV !== "production" && !(this instanceof Vue)) {
warn("Vue is a constructor and should be called with the `new` keyword")
}
this._init(options)
}
initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)
export default Vue
有人可能要问了?为什么不用es6的class呢,而要使用构造函数
- 因为构造函数的原型上的对象可拓展性很强,可以在原型上加很多方法。
- 把原型上的方法实现拆分到不同的目录文件,使得项目的维护性很强
- 用es6的class不是想要实现不是很方便
8、总结
在import vue的过程中,vue做了很多的初始化,比如在原型上挂载了mount方法,__init方法等,初始化了config,options属性等,新增了set,delete,nextTick,use,extend,observable静态方法等等