Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

浅析 Vue 的定义和构建过程 #28

Open
zenglinan opened this issue Oct 4, 2019 · 0 comments
Open

浅析 Vue 的定义和构建过程 #28

zenglinan opened this issue Oct 4, 2019 · 0 comments

Comments

@zenglinan
Copy link
Owner

zenglinan commented Oct 4, 2019

Vue 的庐山真面目

Vue 项目 web 版中,有 runtime only 版本和 runtime compiler 版

runtime only

runtime only 比较轻量,只包含Vue.js运行时的代码,需要我们借助 vue-loader 进行编译,把 template 编译成 render函数。

比如:

// 待编译
new Vue({
  template: '{{ hi }}'
})

// 编译后
new Vue({
  render (h) {
    return h('div', this.hi)
  }
})

runtime compiler

包含了编译的代码的版本,体积比较大,加之编译时会损耗一定性能,所以尽可能采取不带编译的版本,在离线时进行编译。

这里我们来看看 Vue.js 编译出来的 runtime compiler 版本的文件, 入口文件为
src/platforms/web/entry-runtime-with-compiler.js

可以看到这一句

import Vue from './runtime/index'

我们往下挖,看看 Vue 到底怎么来的

// './runtime/index'
// 这个文件引入了 core/index 的 Vue,并给 Vue 挂载了一些属性
// 我们关注的还是这一句
import Vue from 'core/index'

src/core/index.js 中,引入了 'src/core/instance/index' 中的 Vue,并初始化了 Vue 中的一些全局 API

import Vue from './instance/index'

initGlobalAPI(Vue)  // 初始化全局 API

Object.defineProperty(Vue.prototype, '$isServer', {
  get: isServerRendering
})

Object.defineProperty(Vue.prototype, '$ssrContext', {
  get () {
    /* istanbul ignore next */
    return this.$vnode && this.$vnode.ssrContext
  }
})

//...

src/core/instance/index.js 中,终于找到了 Vue 的定义。

function Vue (options) {
  if (process.env.NODE_ENV !== 'production' &&
    !(this instanceof Vue)
  ) {
    warn('Vue is a constructor and should be called with the `new` keyword')
  }
  this._init(options)
}

可以看到,这里的 Vue 实际上就是一个函数(类),但是为什么不用 class 定义呢?

往下看会发现:

initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)

这个文件引入了许多外部的方法,给 Vue 这个类添加静态方法。

使用函数定义类可以使代码拆分到多个文件,有利于代码维护。

Vue 源码构建:

package.json 里,我们可以找到 build 的命令

"build": "node scripts/build.js"

build.js 中,需要导入一些配置,对配置进行一些处理,然后根据配置进行构建

if (!fs.existsSync('dist')) {  // 是否存在 dist 目录(作为输出目录)
  fs.mkdirSync('dist')
}

let builds = require('./config').getAllBuilds()  // 引入所需配置 config

if (process.argv[2]) {  // 获取 script 的命令参数, 过滤掉不需要 build 的文件
  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 {
// 默认过滤掉 weex 版本的文件
  builds = builds.filter(b => {
    return b.output.file.indexOf('weex') === -1
  })
}

build(builds) // 构建

// ...

这里我们看一下导入的配置:

let builds = require('./config').getAllBuilds() 

scripts/config.js 导出了配置

exports.getAllBuilds = () => Object.keys(builds).map(genConfig)

这里获取了 builds 这个对象的键,将这个数组 map 遍历,将每个键传给 genConfig 函数genConfig 函数 的作用是: 将 builds 配置转换成 rollup( Vue 的打包工具 ) 所需的配置格式。

builds 这个配置对象保存的就是各个版本的配置,这里截取一个键值看看:

'web-runtime-cjs-dev': {
  entry: resolve('web/entry-runtime.js'),
  dest: resolve('dist/vue.runtime.common.dev.js'),  // 输出目录
  format: 'cjs',  // 输出文件后缀
  env: 'development', // 环境变量
  banner  // 用来打印的注释信息
},

这里在处理路径时,为了能够跨平台,用了 resolve 方法,将路径用 path.resolve 处理成绝对路径。

这里的 resolve 方法简单包装了一层

// aliases
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')
}
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)
  }
}

以上述的 entry 为例:web/entry-runtime.js 的前缀 web,如果在 alias 的键中,则按原路径解析为绝对路径,否则就将路径解析到上一层的绝对路径。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant