Vue 源码解析-项目

659 阅读2分钟

vue版本:v2.7.10

之前大概看过一次vue dist源码,由于只有一个文件,没有比较好的结构化思路,时间一久很多细节都忘了。现在准备重新看一下整个完整项目,版本选了v2.7.10,包含了组合式API。

这一篇是先从整个项目整体入手。

image.png

整个项目还是比较庞大的,全部都看也不现实,所以还是选择性忽略了benchmarkstestexamples等测试、示例相关的一些目录😆,先列出需要看的目录和文件。

  • compiler-sfc: 单文件组件编译
  • packages:单文件组件编译、模版编译、服务端渲染
  • scripts: 打包脚本
  • src:核心源码
  • types:ts类型相关
  • api-extractor.json、api-extractor.tsconfig.json:感觉是和api文档相关的一些文件,先不看
  • package.json:依赖、打包、测试命令相关配置,得从这里开始入手
  • pnpm-lock.yaml、pnpm-workspace.yaml:pnpm相关的一些配置,pnpm也不熟悉呀,影响不大,先不看
  • tsconfig.json:ts配置,先不看

package.json

image.png

构建版本

main、module、exports里面声明了多个构建版本路径,unpkg、jsdelivr声明了CDN直线的构建版本路径,具体可以参考

scripts

image.png

可以看到三个生产构建结果的命令,ssr和ts类型相关的先不看了,着重看node/builds.js脚本

    "build": "node scripts/build.js",
    "build:ssr": "npm run build -- runtime-cjs,server-renderer",
    "build:types": "rimraf temp && tsc --declaration --emitDeclarationOnly --outDir temp && api-extractor run && api-extractor run -c packages/compiler-sfc/api-extractor.json",

开发环境的命令,使用rollup进行编译。

    "dev": "rollup -w -c scripts/config.js --environment TARGET:full-dev",
    "dev:cjs": "rollup -w -c scripts/config.js --environment TARGET:runtime-cjs-dev",
    "dev:esm": "rollup -w -c scripts/config.js --environment TARGET:runtime-esm",
    "dev:ssr": "rollup -w -c scripts/config.js --environment TARGET:server-renderer",
    "dev:compiler": "rollup -w -c scripts/config.js --environment TARGET:compiler ",

release命令涉及版本更新和发布的流程。

    "release": "node scripts/release.js",

builds.js

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

function build (builds) {
  let built = 0
  const total = builds.length
  const next = () => {
    buildEntry(builds[built]).then(() => {
      built++
      if (built < total) {
        next()
      }
    }).catch(logError)
  }

  next()
}

function buildEntry (config) {
  const output = config.output
  const { file, banner } = output
  const isProd = /(min|prod)\.js$/.test(file)
  return rollup.rollup(config)
    .then(bundle => bundle.generate(output))
    ...
}

从config.js导入的配置列表,通过rollup执行打包任务,再看一下config.js

config.js

const builds = {
    ...
  // Runtime+compiler production build  (Browser)
  'full-prod': {
    entry: resolve('web/entry-runtime-with-compiler.ts'),
    dest: resolve('dist/vue.min.js'),
    format: 'umd',
    env: 'production',
    alias: { he: './entity-decoder' },
    banner
  },
  ...
}

这里只选取full-prod这一项配置,可以看到,其构建后的文件名为vue.min.js,包含运行时和编译器,入口文件为 web/entry-runtime-with-compiler.ts。 再看一下resolve函数和alias配置:

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)
  }
}

alias.js

const path = require('path')

const resolve = p => path.resolve(__dirname, '../', p)

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'),
  server: resolve('packages/server-renderer/src'),
  sfc: resolve('packages/compiler-sfc/src')
}

可以定位到entry-runtime-with-compiler.ts在项目中的具体位置为src/platforms/web/entry-runtime-with-compiler.ts

image.png

入口文件的解析在下一篇文章:Vue 源码-入口