Vue入口文件查找
- 查看 dist/vue.js 的构建过程
- 当运行
npm run dev
时指定了配置文件,从配置文件script/config.js
入手 - web-full-dev (web包含编译器和运行时的开发版)
script/config.js
基于 node 的模块"dev": "rollup -w -c scripts/config.js -m --environment TARGET:web-full-dev"
配置文件 config.js
...
// 判断是否有环境变量 target
if (process.env.TARGET) {
module.exports = genConfig(process.env.TARGET)
} else {
exports.getBuild = genConfig
exports.getAllBuilds = () => Object.keys(builds).map(genConfig)
}
genrator config 生成配置文件
function genConfig (name) {
const opts = builds[name]
...
return config
}
我们传入的环境变量指向 build 中的 带编译器的 开发版本
const builds = {
'web-full-dev': {
// resolve把后面的路径转化为绝对路径
// 实际获取的是 src/platforms/web/entry-runtime-with-compiler.js
// resolve方法会找到上面的路径,有别名操作
entry: resolve('web/entry-runtime-with-compiler.js'),
dest: resolve('dist/vue.js'),
format: 'umd',
env: 'development',
alias: { he: './entity-decoder' },
// 打包出的文件的文件头 banner:banner函数
banner
}
}
问题: 如果同时设置 template和 render 会执行谁?
const vm = new Vue({
el:"#app",
template:"<h3>Hello Template</h3>",
render(h) {
return h('h4',"Hello Render")
}
})
解析 entry 所对应的入口文件,并回答上面的问题
从 入口文件中,src/platforms/web/entry-runtime-with-compiler.js
- el是dom元素
- el不能是body或html标签
- 如果没有render,把template转化成render函数
- 如果有 render, 直接调用 mount 挂载 DOM
断点调试 $mount 方法
- 注意 npm run build 时并未开启sourcemap,如果想调试源码需要
- 给vue.js 添加 //# sourceMappingURL=vue.js.map,可调试 vue.js源码 或修改配置文件添加 -m
- 因此 当前入口文件文件的作用就是 重写原型$mount方法,对template模板进行处理,然后导出vue实例 (带编译器的版本)
- 注意 与
entry-runtime.js
不同, 没有处理tempalte代码,直接返回了 vue实例 (运行时版本)
问题:Vue的构造函数在哪?Vue实例的成员/Vue的静态成员从哪里来的?
从入口文件反推,找到引入的地方
...
// # src/platforms/web/entry-runtime-with-compiler.js
import Vue from './runtime/index' // Vue引入的地方
...
export default Vue
解析 src/platforms/web/runtime/index.js
- 此脚本主要是 跟web平台相关的,对Vue构造函数进行处理的脚本
- 给Vue注册平台相关指令,给Vue原型上挂载了
$mount
,__patch__
,导出了Vue实例 但是依然没有看到Vue构造函数!
// # platforms/web/runtime/index.js import Vue from 'core/index' ... export default Vue
解析 src/core/index.js
- 继续查找上面引入的Vue
- core下的代码是与平台无关的
- initGlobalAPI(Vue) 给Vue构造函数添加静态方法
- 但是依然没有看到Vue构造函数!
import Vue from './instance/index'
...
initGalobalAPI(Vue)
...
export default vue
解析 src/core/instance/index.js
- 与平台无关的.终于有Vue了
- 此处不用 class 而用构造函数,原因是因为方便后续给Vue原型上挂成员方法
- 对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')
}
// 在 initMixin 中有这个方法
this._init(options)
}
...
总结:
四个导出Vue的模块
src/platforms/web/entry-runtime-with-compiler.js
- web平台相关的入口
- 重写了平台相关的 $mount()方法
- 注册了Vue.compile()方法,传递一个HTML字符串返回render 函数
src/platforms/web/runtime/index.js
- web 平台相关
- 注册和平台相关的全局指令:v-model、v-show
- 注册和平台相关的全局组件:v-transition、v-transition-group
全局方法:
- _patch_:把虚拟DOM转换成真实DOM
- $mount: 挂载方法
src/core/index.js
- 与平台无关
- 设置了Vue的静态方法,initGlobalAPI(Vue)
src/core/instance/index.js
- 与平台无关
- 定义了构造函数,调用了this._init(options)方法
- 给Vue中混入了常用的实例成员
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。