vlambda博客
学习文章列表

Vue源码思考(一、门外观望,屋里这么热闹弄啥哩)


Vue3.0的Alpha预览版已经发布,完整版很快也会出来,前端项目又要升级了,前端同学又要学习了。你还学得动吗?如何应对快速迭代升级的前端框架库?读源码。

还记得上学时老师说过,要理解记忆,把书读薄。现在想来真是说的太对了。我们把vue源码看明白,然后把它串联起来。那我们学习vue的使用方法和文档时,会很快的理解为什么要这么用。而且,读源码,领悟作者巧妙的思想、设计模式、编码规范,对于我们基础能力的提升也是大有益处的。

vue的v2.6.10版本是v3.0正式可以使用前(预计到2020年了)的最新稳定版本,研究分析它,我们可以更快的熟悉v3.0的更新点和更新原因。

1、获取vue项目源码

Vue源码思考(一、门外观望,屋里这么热闹弄啥哩)



如上图,可以看到完整项目比我们平时使用vue开发项目时下载到的vue模块要多很多内容。

顺路看下我们平时使用的:

Vue源码思考(一、门外观望,屋里这么热闹弄啥哩)


 

即使我们下载到这些文件,我们平时开发web应用时也只是使用dist下的文件和types下的文件,types下也不常用,那是对开发typescript语法的web项目的支持。这里面的src文件夹就是,vue的核心代码块的源码。虽然我们开发应用时也没用上src,作者也把src下的它们放进去,大概也是想让我们更多的了解参考下源码吧。这就是开源的精神啊。

2、源码项目结构分析

前面下载到了完整的源码项目,那目录下那么多文件夹都是做啥用的哈?这个疑问肯定已经在大家心里了。

先大概逐一介绍下,不进行太深入的解析,因为我们本文宗旨是门外观望,太深入钻牛角尖的话,他的复杂度会把我们吓跑的。我们后面逐层剥玉米解析,逐步深入,让复杂的问题水到渠成,迎刃而解。

 

Vue源码思考(一、门外观望,屋里这么热闹弄啥哩)

这是CI持续集成相关,里面有持续集成的配置文件,CI对于项目开发的好处是会节省很多测试阶段的发布流程,有兴趣的同学可以去百度CICD了。vue作为先进的前端库,他的自身的产生过程,也使用了很多先进的思想、工具、流程等。

 

Vue源码思考(一、门外观望,屋里这么热闹弄啥哩)


里面是Vuegithub上被大家拉取分支、开发贡献、请求作者合并代码、提出问题等的一些规范和说明。

Vue源码思考(一、门外观望,屋里这么热闹弄啥哩)


 

里面是使用vue开发的一些特殊例子,大家可以看到vue性能和兼容测试的试验结果。

Vue源码思考(一、门外观望,屋里这么热闹弄啥哩)


 

这里面是对vue源码进行打包好后的文件,类似于我们开发应用时的dist,包含多种版本,前面也说了,我们平时开发web应用引用的vue库就在里面。

 

Vue源码思考(一、门外观望,屋里这么热闹弄啥哩)

看名字就知道了,一些使用vue开发的简单demo页面。

 

Vue源码思考(一、门外观望,屋里这么热闹弄啥哩)

这个很关键,一个概念要理解,就是静态类型检查,js本身是弱类型语言,java是强类型语音。尽管js不强制我们严格类型使用,但是开发大型项目时,变量等的类型不确定性会让我们很头疼,出现不易排查的问题,因此静态类型检查对于发现和排查这些问题很有用。下面,明星来了,flow就是帮助我们静态类型检查的工具库。这个文件夹下,是vue源码使用的各种自定义类型的定义,可以让flow按我们的规定检查我们使用这些类型的代码是否可靠。

 

Vue源码思考(一、门外观望,屋里这么热闹弄啥哩)

可单独发布的一些模块,里面模块的核心代码也是从src打包来的,只是加些架子成了单独的npm模块作为插件用。这些模块有:

 

Vue源码思考(一、门外观望,屋里这么热闹弄啥哩)

跳出子目录,回到根目录,我们继续

 

Vue源码思考(一、门外观望,屋里这么热闹弄啥哩)

这里面是打包的配置和打包逻辑代码,上面说的dist全部文件和packages目录下核心文件,都是从这里执行打包后产生的。

 

Vue源码思考(一、门外观望,屋里这么热闹弄啥哩)

这个不用说了,前面说了,vue的真正核心源码,其他都是为了开发他或者帮助使用他服务的。

 

Vue源码思考(一、门外观望,屋里这么热闹弄啥哩)

单元测试和自动测试的配置等。

 

Vue源码思考(一、门外观望,屋里这么热闹弄啥哩)

前面说了,是对typescript应用的支持版本,源码里目录下还包含ts版本的测试流程配置。

 

Vue源码思考(一、门外观望,屋里这么热闹弄啥哩)

Babel的配置文件

 

Vue源码思考(一、门外观望,屋里这么热闹弄啥哩)

 官网是这么介绍EditorConfig的,“EditorConfig帮助开发人员在不同的编辑器和IDE之间定义和维护一致的编码样式。EditorConfig项目由用于定义编码样式的文件格式和一组文本编辑器插件组成,这些插件使编辑器能够读取文件格式并遵循定义的样式。EditorConfig文件易于阅读,并且与版本控制系统配合使用。

 

 

Vue源码思考(一、门外观望,屋里这么热闹弄啥哩)

ESLint是一个语法规则和代码风格的检查工具,这里面是是检查设置和忽视检查的目录的名单。

 

Vue源码思考(一、门外观望,屋里这么热闹弄啥哩)

Flow的配置,里面配置忽略静态检查的目录、检查使用的库,并且配置哪儿些目录下的哪儿些文件需要用我们上面flow文件夹下定义的类型去做对应检查。

 

Vue源码思考(一、门外观望,屋里这么热闹弄啥哩)

这个就不说了,常见的。

Vue源码思考(一、门外观望,屋里这么热闹弄啥哩)


 

码云仓库上的该项目的介绍。

Vue源码思考(一、门外观望,屋里这么热闹弄啥哩)


 

软件证书协议,The MIT License (MIT)

 

Vue源码思考(一、门外观望,屋里这么热闹弄啥哩)

这个文件作用大家都明白,但是里面所有配置的作用,大家很难说全。后续我们详细说vue源码使用到的配置的作用。

 

Github上该项目的介绍。

 

yarn替换npm安装项目时,会用到。看来这作者们习惯使用yarn

官方对 yarn.lock 文件的说明如下:

为了跨机器安装得到一致的结果,Yarn 需要比你配置在 package.json 中的依赖列表更多的信息。Yarn 需要准确存储每个安装的依赖是哪个版本。

为了做到这样,Yarn 使用一个你项目根目录里的 yarn.lock 文件。这可以媲美其他像 Bundler 或 Cargo 这样的包管理器的 lockfiles。它类似于 npm 的 npm-shrinkwrap.json,然而它并不是有损的并且它能创建可重现的结果。npm-shrinkwrap.json,那 npm-shrinkwrap.json 又是什么呢?

通过查资料,简单来说,它是由命令 npm shrinkwrap 生成的,它的作用和 package-lock.json 的作用是一样的,都是用来锁定版本用的。现在有了 package-lock.json 之后就不怎么用 npm-shrinkwrap.json 了。

3、package.json文件配置解释

 
  
    
    
  
{ // 名称 "name": "vue", // 版本 "version": "2.6.10", // 描述 "description": "Reactive, component-oriented view layer for modern web interfaces.",   // npm包项目的主要入口文件,commonjs module引入需要的如文件 "main": "dist/vue.runtime.common.js",   // es module引入需要的入口文件 "module": "dist/vue.runtime.esm.js",   //umd,带编译器的版本 "unpkg": "dist/vue.js", // jsdelivr cdn公共库 "jsdelivr": "dist/vue.js", // TypeScript 引入时的入口文件 "typings": "types/index.d.ts", // 当你发布package时,具体那些文件会发布上去 "files": [ "src", "dist/*.js", "types/*.d.ts" ], // 声明该模块是否包含 sideEffects(副作用),从而可以为 tree-shaking 提供更大的优化空间。 "sideEffects": false, "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" },   //git提交前代码质量检查,自动化注释模板 "gitHooks": { "pre-commit": "lint-staged", "commit-msg": "node scripts/verify-commit-msg.js" }, // 代码检查 "lint-staged": { "*.js": [ "eslint --fix", "git add" ] }, // git仓库所在位置 "repository": { "type": "git", "url": "git+https://github.com/vuejs/vue.git" }, // 关键词 "keywords": [ "vue" ], // 作者 "author": "Evan You", // 开源协议 "license": "MIT", // bug地址 "bugs": { "url": "https://github.com/vuejs/vue/issues" }, // 主页 "homepage": "https://github.com/vuejs/vue#readme", // 依赖 "devDependencies": { "@babel/core": "^7.0.0", "@babel/plugin-proposal-class-properties": "^7.1.0", "@babel/plugin-syntax-dynamic-import": "^7.0.0", "@babel/plugin-syntax-jsx": "^7.0.0", "@babel/plugin-transform-flow-strip-types": "^7.0.0", "@babel/preset-env": "^7.0.0", "@babel/register": "^7.0.0", "@types/node": "^10.12.18", "@types/webpack": "^4.4.22", "acorn": "^5.2.1", "babel-eslint": "^10.0.1", "babel-helper-vue-jsx-merge-props": "^2.0.3", "babel-loader": "^8.0.4", "babel-plugin-istanbul": "^5.1.0", "babel-plugin-transform-vue-jsx": "^4.0.1", "babel-preset-flow-vue": "^1.0.0", "buble": "^0.19.3", "chalk": "^2.3.0", "chromedriver": "^2.45.0", "codecov": "^3.0.0", "commitizen": "^2.9.6", "conventional-changelog": "^1.1.3", "cross-spawn": "^6.0.5", "cz-conventional-changelog": "^2.0.0", "de-indent": "^1.0.2", "es6-promise": "^4.1.0", "escodegen": "^1.8.1", "eslint": "^5.7.0", "eslint-plugin-flowtype": "^2.34.0", "eslint-plugin-jasmine": "^2.8.4", "file-loader": "^3.0.1", "flow-bin": "^0.61.0", "hash-sum": "^1.0.2", "he": "^1.1.1", "http-server": "^0.11.1", "jasmine": "^2.99.0", "jasmine-core": "^2.99.0", "karma": "^3.1.1", "karma-chrome-launcher": "^2.1.1", "karma-coverage": "^1.1.1", "karma-firefox-launcher": "^1.0.1", "karma-jasmine": "^1.1.0", "karma-mocha-reporter": "^2.2.3", "karma-phantomjs-launcher": "^1.0.4", "karma-safari-launcher": "^1.0.0", "karma-sauce-launcher": "^2.0.2", "karma-sourcemap-loader": "^0.3.7", "karma-webpack": "^4.0.0-rc.2", "lint-staged": "^8.0.0", "lodash": "^4.17.4", "lodash.template": "^4.4.0", "lodash.uniq": "^4.5.0", "lru-cache": "^5.1.1", "nightwatch": "^0.9.16", "nightwatch-helpers": "^1.2.0", "phantomjs-prebuilt": "^2.1.14", "puppeteer": "^1.11.0", "resolve": "^1.3.3", "rollup": "^1.0.0", "rollup-plugin-alias": "^1.3.1", "rollup-plugin-buble": "^0.19.6", "rollup-plugin-commonjs": "^9.2.0", "rollup-plugin-flow-no-whitespace": "^1.0.0", "rollup-plugin-node-resolve": "^4.0.0", "rollup-plugin-replace": "^2.0.0", "selenium-server": "^2.53.1", "serialize-javascript": "^1.3.0", "shelljs": "^0.8.1", "terser": "^3.10.2", "typescript": "^3.1.3", "webpack": "~4.28.4", "weex-js-runtime": "^0.23.6", "weex-styler": "^0.3.0", "yorkie": "^2.0.0" }, // 设置一些用于npm包的脚本命令会用到的配置参数 "config": {    //日志路径吧     "commitizen": {        "path""./node_modules/cz-conventional-changelog" } } }

 
 

4、总结

我们看到使用vue开发的web项目越来越多,我们看到vue这种渐进式库很强大,他为什么这强大?他的屋里为啥这么热闹,为啥客人源源不断,我们本文先站在门外往里望下他的主人在做什么菜。我们后续会到门口看下,迈过门槛,踏入大堂,品尝食材,后厨观摩,想想都很刺激啊。