vue2源码学习(2)Vue的来源

85 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第 6 天,点击查看活动详情

2.Vue的来源

start

我最开始学习Vue.js的时候,在引入Vue.js之后,会通过 new Vue() 的方式来使用我们引入的Vue,那么这个 Vue是哪里来的呢?对应源码的出处是哪里?

我们怀着问题,去查看一下我们的 Vue项目

1. dev 命令

在 Vue项目的 package.json 中有 scripts 属性 ,script 中有一个 dev 属性,是这样的:

rollup -w -c scripts/config.js --environment TARGET:web-full-dev

看到这个命令有这么一个路径 scripts/config.js;

我们去看看这个文件;

2. scripts/config.js

scripts/config.js

// 以下代码经过精简// 7. builds[name] = builds['web-full-dev']
const builds = {
  // 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,
  },
}
​
// 3. 归根到底,返回的就是 genConfig函数执行之后的返回值
function genConfig(name) {
  // 6. 所有的数据来自 build
  const opts = builds[name]
​
  // 5. config本身是一个对象,对象的详细内容来自 opts
  const config = {
    input: opts.entry,
    external: opts.external,
    plugins: [flow(), alias(Object.assign({}, aliases, opts.alias))].concat(
      opts.plugins || []
    ),
    output: {
      file: opts.dest,
      format: opts.format,
      banner: opts.banner,
      name: opts.moduleName || 'Vue',
    },
    onwarn: (msg, warn) => {
      if (!/Circular/.test(msg)) {
        warn(msg)
      }
    },
  }
​
  // 4. 返回了 config
  return config
}
​
// 1. 如果存储环境变量TARGET
if (process.env.TARGET) {
  // 2. 导出 genConfig
  module.exports = genConfig(process.env.TARGET)
} else {
  exports.getBuild = genConfig
  exports.getAllBuilds = () => Object.keys(builds).map(genConfig)
}

可以结合上述的注释,可以了解到:scripts/config.js 主要作用是返回一个配置对象。

运行dev命令的时候 ,由于还传入--environment TARGET:web-full-dev

所以返回了一个指定的配置对象;

 '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,
  },

这个对象中有这么一个路径:

entry: resolve("web/entry-runtime-with-compiler.js"),    
// entry 入口的意思

我们就沿着这个路径,开始去寻找 Vue 的来源。

这里的resolve,代码如下,相当于在路径上拼接了这几个属性 src/platfroms/

// resolve函数
const resolve = (p) => {
  // "web/entry-runtime.js"
  const base = p.split("/")[0]; // 第一个参数 例如  web server

  // web并不是我们需要找到的文件路径,需要借助 aliases
  if (aliases[base]) {
    return path.resolve(aliases[base], p.slice(base.length + 1)); // resolve('src/platforms/web'),
  } else {
    return path.resolve(__dirname, "../", p);
  }
};


// alias.js
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')
}

3. 查找文件

下面的示例,就是沿着文件的引入逻辑去寻找我们的 Vue出处:

3.1 src/platfroms/web/entry-runtime-with-compiler.js

import Vue from './runtime/index'
/* ... */
export default Vue

3.2 src/platfroms/web/runtime/index.js

import Vue from 'core/index'
/* ... */
export default Vue

3.3 src/core/index.js

import Vue from './instance/index'
/* ... */
export default Vue

3.4 src/core/instance/index.js

function Vue(options) {
  // 判断是不是使用 new 关键词定义
  if (process.env.NODE_ENV !== 'production' && !(this instanceof Vue)) {
    warn('Vue is a constructor and should be called with the `new` keyword')
  }
  // 实例化时会调用 _init 方法
  this._init(options)
}
​
export default Vue

沿着文件的引入逻辑,我们最终找到了 Vue的出处:在src/core/instance/index.js中定义。

写到这里,我们可以见到Vue的庐山真面目了

Vue本身是一个函数,在 new Vue()的时候,会执行 this._init方法。

end

  • 本节主要记录了 Vue 在源码的出处。
  • Vue 就是一个函数,在 new Vue()的时候,会执行 this._init方法。