Vue2源码学习笔记 - 2.构建Vue

在上一篇的 index.html 中我们引用了 /vue/dist/vue.js 来构建一个应用,这个 vue.js 是 Vue 使用 rollup 来打包生成的,在源码目录中可以根据 package.json 文件的 scripts 字段查看 Vue 的构建命令。

npm run build

 以上就是 Vue 的构建命令,我们看看它到底执行了 scripts/build.js 里的啥,以下截取部分代码

// 引入当前目录下的 config.js 并调用导出函数 getAllBuilds
// 返回 build 配置对象赋给变量 builds
let builds = require('./config').getAllBuilds()

// 过滤配置内容 builds ,默认不生成 weex 的库
// 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 函数循环生成库
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))
    .then(({ output: [{ code }] }) => {
      if (isProd) {
        const minified = (banner ? banner + '\n' : '') + terser.minify(code, {
          toplevel: true,
          output: {
            ascii_only: true
          },
          compress: {
            pure_funcs: ['makeMap']
          }
        }).code
        return write(file, minified, true)
      } else {
        return write(file, code)
      }
    })
}

在 config.js 文件中定义了一个 builds 对象,存放有各种环境的配置。因为我们只学习带runtime和编译器的 web 版,所以我们只需关注 web-full-dev 的内容

const builds = {
  // Runtime only (CommonJS). Used by bundlers e.g. Webpack & Browserify
  'web-runtime-cjs-dev': {
    entry: resolve('web/entry-runtime.js'),
    dest: resolve('dist/vue.runtime.common.dev.js'),
    format: 'cjs',
    env: 'development',
    banner
  },
  'web-runtime-cjs-prod': {
    entry: resolve('web/entry-runtime.js'),
    dest: resolve('dist/vue.runtime.common.prod.js'),
    format: 'cjs',
    env: 'production',
    banner
  },
  ... 省略很多 ...
  // runtime-only build (Browser)
  'web-runtime-dev': {
    entry: resolve('web/entry-runtime.js'),
    dest: resolve('dist/vue.runtime.js'), 
    format: 'umd',
    env: 'development',
    banner
  },
  // runtime-only production build (Browser)
  'web-runtime-prod': {
    entry: resolve('web/entry-runtime.js'),
    dest: resolve('dist/vue.runtime.min.js'),
    format: 'umd',
    env: 'production',
    banner
  },
  // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  // Runtime+compiler development build (Browser)
  'web-full-dev': {
      // 编译入口文件 src/platforms/web/entry-runtime-with-compiler.js
    entry: resolve('web/entry-runtime-with-compiler.js'), 
    dest: resolve('dist/vue.js'),// 编译后库的输出文件
    format: 'umd',
    env: 'development',
    alias: { he: './entity-decoder' },
    banner
  },
  // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  // Runtime+compiler production build  (Browser)
  'web-full-prod': {
    entry: resolve('web/entry-runtime-with-compiler.js'),
    dest: resolve('dist/vue.min.js'),
    format: 'umd',
    env: 'production',
    alias: { he: './entity-decoder' },
    banner
  },
  // Web compiler (CommonJS).
  'web-compiler': {
    entry: resolve('web/entry-compiler.js'),
    dest: resolve('packages/vue-template-compiler/build.js'),
    format: 'cjs',
    external: Object.keys(require('../packages/vue-template-compiler/package.json').dependencies)
  },
  ... 省略很多 ...
}

function genConfig (name) {
  const opts = builds[name]
  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)
      }
    }
  }

  // built-in vars
  const vars = {
    __WEEX__: !!opts.weex,
    __WEEX_VERSION__: weexVersion,
    __VERSION__: version
  }
  // feature flags
  Object.keys(featureFlags).forEach(key => {
    vars[`process.env.${key}`] = featureFlags[key]
  })
  // build-specific env
  if (opts.env) {
    vars['process.env.NODE_ENV'] = JSON.stringify(opts.env)
  }
  config.plugins.push(replace(vars))

  if (opts.transpile !== false) {
    config.plugins.push(buble())
  }

  Object.defineProperty(config, '_name', {
    enumerable: false,
    value: name
  })

  return config
}

if (process.env.TARGET) {
  module.exports = genConfig(process.env.TARGET)
} else {
  exports.getBuild = genConfig
  // 导出 getAllBuilds 函数供 build.js 调用
  exports.getAllBuilds = () => Object.keys(builds).map(genConfig)
}

总结:

整个构建过程就是执行 npm run build 时调用 scripts/build.js 文件,里面获取 config.js 的配置,取得 web 的入口(src/platforms/web/entry-runtime-with-compiler.js)和库输出文件(dist/vue.js)等信息传参给 rollup 生成 /dist/vue.js 文件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值