随着Vue3.0的发布,可以看到如今Vue在现如今的前端开发上占据着越来越重要的地位,那么如果我们了解vue的底层原理,了解其工作机制,无疑会加深我们对他的印象,这样在之后的使用过程中,遇到问题就能从一个更广阔的角度去分析问题产生的原因,而实现这些最好的方式就是看源码。因为Vue3.0发布时间不长,所以我们首先先来分析vue2.x的源码,因为vue2.x版本和vue3.0版本有很多方法的实现方式是类似的,我们先学习了上一个版本的知识,更有助于我们与新的版本产生对比,分析它改动了哪里,而又为什么要改变,那么废话不多说,让我们先从vue的入口开始
vue入口在哪里?
这里介绍的是Runtime+Complier构建出来的vue,那么这有是什么意思呢?vue主要分为两种:一种是Runtime only,一种是上面的,前者当使用vue-loader或vueify时,vue内部模板会预编译成javascript,所以最终打好的包是不需要编译器的,这样的话运行时版本会比完整版体积要小30%,所以比较推荐使用Runtime only版本的vue,但是这里是在进行源码解析,所以还是要挑完整的来。
那么进入正题,首先要先找到入口文件,通过npm托管的项目会有一个package.json的文件用来对项目进行描述,我们在其中找到script字段,我们只关心build开头的三个命令,如下:
"build": "node scripts/build.js",
"build:ssr": "npm run build -- web-runtime-cjs,web-server-renderer",
"build:weex": "npm run build -- weex",
于是我们知道了构建入口的js文件,是scripts文件夹下的builds文件,我们先只关心下面这段代码(注释是我在看源码时加上的):
let builds = require('./config').getAllBuilds()
//对配置进行过滤
// filter builds via command line arg
if (process.argv[2]) {
const filters = process.argv[2].split(',')//过滤掉不需要的
builds = builds.filter(b => {
return filters.some(f => b.output.file.indexOf(f) > -1 || b._name.indexOf(f) > -1)
})
} else {
//没有则过滤掉week
// filter out weex builds by default
builds = builds.filter(b => {
return b.output.file.indexOf('weex') === -1
})
}
// 构建函数
build(builds)
然后我们来看配置文件config,我们先只看builds变量(代码较长,做了缩减):
//format表格式即cmd,amd之类
//banner注释
const builds = {
// Runtime only (CommonJS). Used by bundlers e.g. Webpack & Browserify
'web-runtime-cjs-dev': {
entry: resolve('web/entry-runtime.js'),
dest: resolve('dist/vue.runtime.common.dev.js'),
format: 'cjs',
env: 'development',
banner
},
......
}
这里主要是Vue.js构建的一些配置,其中entry表示构建的入口js文件地址,dest表示构建后的文件地址,我们以web-runtime-cjs-dev为例,先看entry,调用了resolve函数。
//解析路径
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)
}
}
这个函数首先将参数p分割成了数组,然后将数组首项作为base,所以之前的例子中base为web,之后去alias中去寻找alias[web]的值:
const path = require('path')
const resolve = p => path.resolve(__dirname, '../', p)
//地址映射
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')
}
这里可以看到其对应的为 src/platforms/web 之后resolve函数通过path.resolve函数进行拼接,于是我们就可以找到用例的入口文件为src/platforms/web/entry-runtime.js,同理我们也能找到带编译的入口文件为src/platforms/web/entry-runtime-with-compiler.js
下一篇会接着介绍入口文件,并且会找出vue的庐山真面目,之后会补上链接。