您的浏览器不支持JavaScript或者JavaScript的运行被您禁止了。

Vue2.5.16源码解读一:确定阅读入口

准备粗略地阅读下Vue,跟网上别人家的源码解读文章不同的是,这个系列是完全以第一次去读代码的视角带大家一起去读的,而非看完源码后以上帝的总结视角来写的系列文章。

要看我们就直接找比较新的版本看,fork vue代码到我们自己的仓库上,clone到本地后,执行git tag 发现最新的版本是2.5.16,所以在本地新开一个tag-v2.5.16分支方便阅读以及后续commit(如果要commit的话):

git checkout -b tag-v2.5.16

执行完,我们的本地项目就已经切换到新的tag-v2.5.16 分支上了。

拿到一个项目,我们首先看一下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: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.json",

"test:ssr": "npm run build:ssr && jasmine JASMINE_CONFIG_PATH=test/ssr/jasmine.json",

"test:sauce": "npm run sauce -- 0 && npm run sauce -- 1 && npm run sauce -- 2",

"test:types": "tsc -p ./types/test/tsconfig.json",

"lint": "eslint --fix 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"

},

mmp,但是英雄无所畏惧,因为我打算只看build 命令,所以我们的入口文件就是scripts/build.js 这个文件了。

接下来我们采用调试代码的方式进行阅读。我用的是webstorm这个IDE,先点右上角edit configuration,然后按下图进行配置:

保存后再点右上角的甲壳虫进行debug。

scripts/build.js 文件开头部分内容如下:

const fs = require('fs')
const path = require('path')
const zlib = require('zlib')
const rollup = require('rollup')
const uglify = require('uglify-js')

if (!fs.existsSync('dist')) {

fs.mkdirSync('dist')

}

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 {

// filter out weex builds by default builds = builds.filter(b => {

return b.output.file.indexOf('weex') === -1 })

}

我们就将断点打到if (!fs.existsSync('dist')) { 这一行,然后开始往下一点点走(step over)。

下面就单独对这个文件添加一些注释方便读者阅读:

const fs = require('fs')
const path = require('path')
const zlib = require('zlib')
const rollup = require('rollup')
const uglify = require('uglify-js')

// 如果项目根目录下不存在dist目录,则同步创建dist目录 if (!fs.existsSync('dist')) {

fs.mkdirSync('dist')

}

// 拿到各种build情况对应的配置参数 let builds = require('./config').getAllBuilds()

// 通过命令行参数来判断需要针对哪些build情况进行打包,直接`node scripts/build.js`的话,`process.argv`拿到的数组长度为2,故下面的判断流程会进入else分支 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 {

// 直接`node scripts/build.js`会进入这个分支,默认会过滤掉weex相关的build,不对weex相关的build情况进行打包

builds = builds.filter(b => {

return b.output.file.indexOf('weex') === -1 })

}

// 根据过滤后剩下的build案例对应的配置参数,使用rollup库进行打包 build(builds)

function build (builds) {

let built = 0 const total = builds.length const next = () => {

buildEntry(builds[built]).then(() => {

built++

if (built < total) {

next()

}

}).catch(logError)

}

next()

}

function buildEntry (config) {

const output = config.output const { file, banner } = output const isProd = /min\.js$/.test(file)

return rollup.rollup(config)

.then(bundle => bundle.generate(output))

.then(({ code }) => {

if (isProd) {

var minified = (banner ? banner + '\n' : '') + uglify.minify(code, {

output: {

ascii_only: true },

compress: {

pure_funcs: ['makeMap']

}

}).code return write(file, minified, true)

} else {

return write(file, code)

}

})

}

function write (dest, code, zip) {

return new Promise((resolve, reject) => {

function report (extra) {

console.log(blue(path.relative(process.cwd(), dest)) + ' ' + getSize(code) + (extra || ''))

resolve()

}

fs.writeFile(dest, code, err => {

if (err) return reject(err)

if (zip) {

zlib.gzip(code, (err, zipped) => {

if (err) return reject(err)

report(' (gzipped: ' + getSize(zipped) + ')')

})

} else {

report()

}

})

})

}

function getSize (code) {

return (code.length / 1024).toFixed(2) + 'kb'

}

function logError (e) {

console.log(e)

}

function blue (str) {

return '\x1b[1m\x1b[34m' + str + '\x1b[39m\x1b[22m'

}

 

好了,大概的打包流程是这样的,anyway我们是要读源码,所以我们的关注点应该是这里打包时对应的入口文件,从那个文件开始着手阅读代码。

根据let builds = require('./config').getAllBuilds() 这行代码,我们跳转到config.js 文件,发现:

// Runtime+compiler development build (Browser)

'web-full-dev': {

entry: resolve('web/entry-runtime-with-compiler.js'),

dest: resolve('dist/vue.js'),

format: 'umd',

env: 'development',

alias: { he: './entity-decoder' },

banner },

// Runtime+compiler production build (Browser)

'web-full-prod': {

entry: resolve('web/entry-runtime-with-compiler.js'),

dest: resolve('dist/vue.min.js'),

format: 'umd',

env: 'production',

alias: { he: './entity-decoder' },

banner },

因为我们如果直接通过在html里用script标签引用vue.js进行开发的时候,一般都是引用vue.js的,所以这里我们就看这个web-full-dev 就可以了(它的dest 字段对应的是vue.js 文件)。然后我们通过entry 字段判断我们要看的入口文件为:src/platforms/web/entry-runtime-with-compiler.js 这个文件。

InnoDB: Cannot allocate memory for the buffer pool