代码地址:vue2.5.0
参考资料:
- Vue源码探秘系列
- Vue.js 技术揭秘
Flow
在 Vue.js
的主目录下有 .flowconfig
文件, 它是 flow
的配置文件。其中的[libs]
用来描述包含指定库定义的目录,这里指向的是项目根目录下的flow
文件夹。打开此目录,可以发现文件结构如下:
flow
├── compiler.js # 编译相关
├── component.js # 组件数据结构
├── global-api.js # Global API 结构
├── modules.js # 第三方库定义
├── options.js # 选项相关
├── ssr.js # 服务端渲染相关
├── vnode.js # 虚拟 node 相关
Vue源码目录设计
-
complier
├── compiler # 模板解析相关 ├── codegen # 代码生成,把 AST(抽象语法树)转换为 render 函数 ├── directives # 转换为 render 函数前要执行的指令 ├── parser # 把模板解析为 AST
-
core
├── core # Vue 核心代码 ├── components # 全局通用组件 Keep-Alive ├── global-api # 全局 api,即 Vue 对象上的方法,如 extend,mixin,use 等 ├── instance # Vue 实例化相关代码,如初始化,事件,渲染,生命周期等 ├── observer # 响应式数据修改代码 ├── util # 工具函数 ├── vdom # 虚拟 DOM 相关代码
-
platforms
├── platforms # 平台相关代码 ├── web # web 平台 ├── compiler # 编译时相关 ├── runtime # 运行时相关 ├── server # 服务端渲染相关 ├── util # 工具函数 ├── weex # 配合 weex 运行在 native 平台
Rollup构建Vue
Webpack
功能相比 Rollup
更加强大,它可以将各种静态资源(包括 css
,js
,图片
等)通通打包成一个或多个 bundle
,并按需加载;同时正因为 Webpack
功能强大,打包出来的文件体积也较大。因此 Webpack
更适用于应用的开发。而 Rollup
相对于 Webpack
更加轻量,它只处理 js
文件而不处理其他静态资源文件,打包出来的文件体积也更小,因此 Rollup
更适用于像类库这种只有 js
代码的项目构建。所以大部分类库例如 Vue
,React
,Angular
等都采用 Rollup
来打包。
打包vue的命令在package.json
的script
下:
{
"build": "node scripts/build.js",
"build:ssr": "npm run build -- web-runtime-cjs,web-server-renderer",
"build:weex": "npm run build -- weex",
}
build
构建 web 平台相关build:ssr
构建服务端渲染相关build:weex
构建的是weex
平台相关。
接下来学习build.js
文件:
// scripts/build.js
// 引入所需模块
const fs = require('fs')
const path = require('path')
const zlib = require('zlib')
const rollup = require('rollup')
const terser = require('terser')
// 检查是否存在dist目录,不存在则创建dist目录
if (!fs.existsSync('dist')) {
fs.mkdirSync('dist')
}
[1]
let builds = require('./config').getAllBuilds()
[2]
// 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
})
}
build(builds)
// build函数声明
function build (builds) {
}
// scripts/config.js
if (process.env.TARGET) {
module.exports = genConfig(process.env.TARGET)
} else {
exports.getBuild = genConfig
exports.getAllBuilds = () => Object.keys(builds).map(genConfig)
}
[1] 这里 getAllBuilds
函数的处理是取出 builds
对象的所有属性组成的数组在 genConfig
函数处理后返回。即把builds里面的配置对象转换为一个Rollup对应需要的配置项并返。
[2] 通过判断是否有额外的命令参数判断是那条命令,并对builds数组做对应的过滤处理,把不需要Rollup配置项过滤掉。
最后build
函数其实就是让 builds
数组每一项都执行 buildEntry
这个函数,这里 buildEntry
函数调用了 rollup.rollup
进行编译,最终得到一个结果 output
,然后判断这个 output
是否是生产版本来决定是否压缩,然后调用 write
函数。write
函数的作用就是调用 fs.writeFile
生成对应的 js
文件放在 dist
目录下。
总结
学习了flow,vue源码的编写依靠flow来进行类型断言,确保了编译的严谨性;因为Rollup比webpack轻量,专门打包js,所以vue、react等框架都使用了Rollup;在vue中,通过运行build.js文件,将各个函数处理成rollup对应需要的配置项,且根据不同环境判断是否要压缩。