Flow
vue 框架使用了 Flow 作为类型检查, 来保证项目的可读性和维护性. vue.js 的主目录下有 Flow 的配置. flowconfig 文件, 还有 flow 目录, 指定了各种自定义类型.
在学习源码前可以先看下 Flow 的语法 官方文档 https://flow.org/en/docs/config/
目录结构
vue.JS 源码主要在 src 下
src
├── compiler # 编译相关
├── core # 核心代码
├── platforms # 不同平台的支持
├── server # 服务端渲染
├── sfc # .vue 文件解析
├── shared # 共享代码
compiler
template 的编译
core
core
├── components # 内置组件
├── global-API # 全局 API 封装
├── instance # Vue 实例化, 生命周期
├── observer # 观察者, 响应式
├── util # 工具函数
├── vdom # virtual DOM
platform
存放 2 个主要入口, 分别打包运行在 web 和 weex 上的 vue.JS
server
支持了服务端渲染
sfc
把. vue 文件内容解析成 JS 对象
shared
存放共享方法
vue.JS 构建
vue 是基于 Rollup 构建的, 类似于 webpack 首先来看下 package.JSON 文件, 先看下 script 字段:
- {
- "script":{
- "build": "node scripts/build.js",
- "build:ssr": "npm run build -- web-runtime-cjs,web-server-renderer",
- "build:weex": "npm run build -- weex",
- }
- }
这 3 条都是构建 vue 的命令, 后 2 条是根据需求添加对应环境参数. 运行 NPM run build 时会执行 node scripts/build.JS
构建过程
构建过程比较复杂, 这里会简化下构建过程, 只分析主线流程
进入到 scripts/build.JS,
- // 从配置文件读取配置, 拿到所有构建的 path
- let builds = require('./config').getAllBuilds()
- // 过滤 builds
- build(builds)
再看下配置文件 scripts.config.JS,
- let builds= {
- 'web-runtime-esm': {
- entry: resolve('web/entry-runtime.js'),
- dest: resolve('dist/vue.runtime.esm.js'),
- format: 'es',
- banner
- },
- }
entry 属性表示构建的入口 JS 文件地址, dest 属性表示构建后的 JS 文件地址. format 属性表示构建的格式, cjs 表示构建出来的文件遵循 CommonJS 规范, es 表示构建出来的文件遵循 ES Module 规范. umd 表示构建出来的文件遵循 UMD 规范.
resolve
看下 resovle 方法的定义
- 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)
- }
- }
用到了 path.resolve([... paths]), path.resolve 是 node.JS 提供的路径解析方法, 可以看下官方文档了解下, 主要是从右到左处理给定的路径序列, 直到构造出绝对路径.
用 resolve('web/entry-runtime.js') 作分析, base 是 Web , 找到 aliases[base] 即真实路径 '../src/platforms/web' ,
entry: resolve('web/entry-runtime.js')
所以最终入口路径是 ../src/platforms/Web/entry-runtime.JS, 构建生成文件路径是../dist/vue.runtime.esm.JS
genConfig()
输入 builds 前要先将 builds 转换成 rollup 打包所对应的配置结构
- if (process.env.TARGET) {
- module.exports = genConfig(process.env.TARGET)
- } else {
- exports.getBuild = genConfig
- // 返回 config 组成的数组
- exports.getAllBuilds = () => Object.keys(builds).map(genConfig)
- }
来源: https://juejin.im/post/5c25e0ff6fb9a049ea39058d