Vue.js 源码构建

Vue.js 源码是基于 Rollup 构建的,它的构建相关配置都在 scripts 目录下。

构建脚本

通常一个基于 NPM 托管的项目都会有一个 package.json 文件,它是对项目的描述文件,它的内容实际上是一个标准的 JSON 对象。
我们通常会配置 script 字段作为 NPM 的执行脚本,Vue.js 源码构建的脚本如下:

{"script": {"build": "node scripts/build.js","build:ssr": "npm run build -- web-runtime-cjs,web-server-renderer","build:weex": "npm run build --weex"}
}

这里总共有 3 条命令,作用都是构建 Vue.js,后面 2 条是在第一条命令的基础上,添加一些环境参数。
当在命令行运行 npm run build 的时候,实际上就会执行 node scripts/build.js,接下来我们来看看它实际是怎么构建的。

构建过程

我们对于构建过程分析是基于源码的,先打开构建的入口 JS 文件,在 scripts/build.js 中:

let builds = require('./config').getAllBuilds()// 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 defaultbuilds = builds.filter(b => {return b.output.file.indexOf('weex') === -1})
}build(builds)

这段代码逻辑非常简单,先从配置文件读取配置,再通过命令行参数对构建配置做过滤,这样就可以构建出不同用途的 Vue.js 了。接下来我们看一下配置文件,在 scripts/config.js 中:

const builds = {// Runtime only (CommonJS). Used by bundlers e.g. Webpack & Browserify'web-runtime-cjs': {entry: resolve('web/entry-runtime.js'),dest: resolve('dist/vue.runtime.common.js'),format: 'cjs',banner},// Runtime+compiler CommonJS build (CommonJS)'web-full-cjs': {entry: resolve('web/entry-runtime-with-compiler.js'),dest: resolve('dist/vue.common.js'),format: 'cjs',alias: { he: './entity-decoder' },banner},// Runtime only (ES Modules). Used by bundlers that support ES Modules,// e.g. Rollup & Webpack 2'web-runtime-esm': {entry: resolve('web/entry-runtime.js'),dest: resolve('dist/vue.runtime.esm.js'),format: 'es',banner},// Runtime+compiler CommonJS build (ES Modules)'web-full-esm': {entry: resolve('web/entry-runtime-with-compiler.js'),dest: resolve('dist/vue.esm.js'),format: 'es',alias: { he: './entity-decoder' },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': {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},// ...
}

这里列举了一些 Vue.js 构建的配置,关于还有一些服务端渲染 webpack 插件以及 weex 的打包配置就不列举了。
对于单个配置,它是遵循 Rollup 的构建规则的。其中 entry 属性表示构建的入口 JS 文件地址,dest 属性表示构建后的 JS 文件地址。format 属性表示构建的格式,cjs 表示构建出来的文件遵循 CommonJS 规范,es 表示构建出来的文件遵循 ES Module 规范。 umd 表示构建出来的文件遵循 UMD 规范。
以 web-runtime-cjs 配置为例,它的 entry 是
resolve(‘web/entry-runtime.js’),先来看一下 resolve 函数的定义。
源码目录:scripts/config.js

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

这里的 resolve 函数实现非常简单,它先把 resolve 函数传入的参数 p 通过 / 做了分割成数组,然后取数组第一个元素设置为 base。在我们这个例子中,参数 p 是 web/entry-runtime.js,那么 base 则为 web。base 并不是实际的路径,它的真实路径借助了别名的配置,我们来看一下别名配置的代码,在 scripts/alias 中:

const path = require('path')module.exports = {vue: path.resolve(__dirname, '../src/platforms/web/entry-runtime-with-compiler'),compiler: path.resolve(__dirname, '../src/compiler'),core: path.resolve(__dirname, '../src/core'),shared: path.resolve(__dirname, '../src/shared'),web: path.resolve(__dirname, '../src/platforms/web'),weex: path.resolve(__dirname, '../src/platforms/weex'),server: path.resolve(__dirname, '../src/server'),entries: path.resolve(__dirname, '../src/entries'),sfc: path.resolve(__dirname, '../src/sfc')
}

很显然,这里 web 对应的真实的路径是 path.resolve(__dirname, ‘…/src/platforms/web’),这个路径就找到了 Vue.js 源码的 web 目录。然后 resolve 函数通过 path.resolve(aliases[base], p.slice(base.length + 1)) 找到了最终路径,它就是 Vue.js 源码 web 目录下的 entry-runtime.js。因此,web-runtime-cjs 配置对应的入口文件就找到了。
它经过 Rollup 的构建打包后,最终会在 dist 目录下生成 vue.runtime.common.js。
Runtime Only VS Runtime+Compiler
通常我们利用 vue-cli 去初始化我们的 Vue.js 项目的时候会询问我们用 Runtime Only 版本的还是 Runtime+Compiler 版本。下面我们来对比这两个版本。
Runtime Only
我们在使用 Runtime Only 版本的 Vue.js 的时候,通常需要借助如 webpack 的 vue-loader 工具把 .vue 文件编译成 JavaScript,因为是在编译阶段做的,所以它只包含运行时的 Vue.js 代码,因此代码体积也会更轻量。
Runtime+Compiler
我们如果没有对代码做预编译,但又使用了 Vue 的 template 属性并传入一个字符串,则需要在客户端编译模板,如下所示:
// 需要编译器的版本
new Vue({
template: ‘

{{ hi }}


})

// 这种情况不需要
new Vue({
render (h) {
return h(‘div’, this.hi)
}
})
因为在 Vue.js 2.0 中,最终渲染都是通过 render 函数,如果写 template 属性,则需要编译成 render 函数,那么这个编译过程会发生运行时,所以需要带有编译器的版本。
很显然,这个编译过程对性能会有一定损耗,所以通常我们更推荐使用 Runtime-Only 的 Vue.js。
总结
通过这一节的分析,我们可以了解到 Vue.js 的构建打包过程,也知道了不同作用和功能的 Vue.js 它们对应的入口以及最终编译生成的 JS 文件。尽管在实际开发过程中我们会用 Runtime Only 版本开发比较多,但为了分析 Vue 的编译过程,我们这门课重点分析的源码是 Runtime+Compiler 的 Vue.js。
任务
请仔细阅读本文档,为下面学习视频内容做准备。

vue源码解析(3)—— Vue.js 源码构建相关推荐

  1. vue add element报错_Vue 源码解析 -- new Vue -gt; mountComponent 001

    这一系列文章的学习出处于Vue.js 技术揭秘 | Vue.js 技术揭秘,有兴趣的伙伴自行阅览 本文涉及到vue源码文件中的 src/core/instance/index.js ==> ne ...

  2. 谷歌BERT预训练源码解析(二):模型构建

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/weixin_39470744/arti ...

  3. Mybatis 源码解析 -- 基于配置的源码解析(二)

    为什么80%的码农都做不了架构师?>>>    mapper解析 接着上篇的配置,本篇主要讲解mappers标签 <?xml version="1.0" e ...

  4. 开源中国(OSChina)源码解析(1)——源码导入

    1.前言 一直有想带大家一起分析开源中国源码的一个计划.但是因为这些或者那些的原因,都被搁浅了.接下来呢,我们一步一步的抽丝剥茧,对源码进行分析,希望给大家能带来一些成长. 2.源码 2.1.下载源码 ...

  5. vue源码解析:vue生命周期方法$destory方法的实现原理

    我们知道vue生命周期的最后一个阶段是销毁阶段,那么vue会调用自己的destory函数,那么$destory函数的实现原理是什么?且往下看. 用法: vm.$destroy() 作用: 完全销毁一个 ...

  6. 【Vue源码解析】Vue虚拟dom和diff算法

    Vue虚拟dom和diff算法 1. 简介 2. 搭建环境 1. 安装snabbdom 2. 安装webpack5并配置 3.函数 3.1 虚拟节点vnode的属性 3.2 使用h函数 创建虚拟节点 ...

  7. vue扫二维码一维码,浏览器H5实现js扫码,含uniapp实现方式

    扫码需求 准备工作 希望在h5端直接使用扫码 调用js库 使用框架 vue 或者 uniapp yarn add @zxing/library 这里我使用的版本是 ^0.19.1 可以直接带上版本号下 ...

  8. beaninfo详解源码解析 java_【Spring源码分析】Bean加载流程概览

    代码入口 之前写文章都会啰啰嗦嗦一大堆再开始,进入[Spring源码分析]这个板块就直接切入正题了. 很多朋友可能想看Spring源码,但是不知道应当如何入手去看,这个可以理解:Java开发者通常从事 ...

  9. android项目源码解析04:新浪微博客户端源码解析

    本文主要介绍如何构建新浪微博客户端.以网上流传weiboSina源码为例介绍,其下载地址为: http://download.csdn.net/detail/ryzhanglu/3453875. 1. ...

  10. Tensorflow源码解析1 -- 内核架构和源码结构

    1 主流深度学习框架对比 当今的软件开发基本都是分层化和模块化的,应用层开发会基于框架层.比如开发Linux Driver会基于Linux kernel,开发Android app会基于Android ...

最新文章

  1. listview在java中的使用_我的Android开发之路——ListView的使用
  2. 自定义jackson序列化_Jackson中的自定义反序列化程序和验证
  3. 2021数学建模C题题目
  4. VSCode内npm run build编译打包时候报错:code ELIFECYCLE - (已解决)
  5. MatLab GUI Change Size 改变界面大小
  6. iPhone 12的4G/5G信号又翻车了:不少用户吐槽无网络服务
  7. 8 个弱点助我成为更好的开发人员!
  8. 心理测试软件需求分析报告,大学生心理测试软件心理测评档案管理系统
  9. 【数据分析报告】携程客户分析与流失预测
  10. [Note] 多项式全家桶 小球与盒子 分拆数
  11. 微信小程序rich-text图片不显示及图片过大问题解决办法
  12. 图片怎么转文字?这些方法值得收藏
  13. 实时网速监测app_实时网速app下载-实时网速下载1.0.0安卓版-西西软件下载
  14. 微pe工具箱+软碟通 制作 U盘启动盘
  15. ExpandableListView讲解
  16. ATFX:5年期LPR利率大降15基点,USDCNH涨破年内高点
  17. 北上资金近1周流入排行榜
  18. python 私有变量和函数
  19. STM32CubeMX+FreeRTOS 嵌入式系统学习
  20. 赫夫曼树及求解最小WPL的实现

热门文章

  1. 【手写源码-设计模式6】-适配器模式-基于IPhoneX手机充电场景
  2. IBM MQ通道常用知识列举(一)
  3. linux命令查询cpu,Linux查看CPU信息方法(超简单)
  4. Adboe全家桶办公软件
  5. 说说这些年命理上遇到的婚姻情感问题?
  6. Ubuntu--(8)段错误Segmentation fault (core dumped)
  7. 深度gdh精简CD版V1
  8. handlebars-API
  9. 运维堡垒机是什么?有什么作用?
  10. 第 46 章 设置 FLASH 的读写保护及解除