这是xue源码学习记录,如有错误请指出,谢谢!相互学习相互进步。

vue源码目录为


vue
├── src #vue源码
├── flow #flow定义的数据类型库(vue通过flow来检测数据类型是否正确)
├── examples #demo
├── scripts #vue构建命令
├── ...

vue内部代码模块比较清晰,这边主要分析scripts内部代码,讲解vue是如何进行构建的.
首先你必须要懂一些rollup,vue内部是通过rollup来进行构建的,rollup是一款js的构建工具,
将各个小模块打包成一个总的模块(只针对js文件,比较轻量,不会有css,img等压缩,比较适合开发插件,
如果是ui组件库的话,还是webpack构建会比较好。)
rollup说明文档:https://rollupjs.cn/

文件主要是scripts下的alias.js,config.js和build.js三个文件组成

alias

主要就是提供文件对应的路径


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'),
weex: resolve('src/platforms/weex'),
server: resolve('src/server'),
entries: resolve('src/entries'),
sfc: resolve('src/sfc'),
test: resolve('src/test') // 这个是测试目录是自己添加的
}

其中test是我自己加的,为了测试打包

config

config是为了提供打包的基础配置(即rollup打包配置文件格式),由于打包内容比较多,
所以做成可配置的


const path = require('path')
const buble = require('rollup-plugin-buble')
// 提供modules名称的 alias 和reslove 功能
const alias = require('rollup-plugin-alias')
// 将CommonJS模块转换为 ES2015供Rollup 处理
const cjs = require('rollup-plugin-commonjs')
// 变量替换,可以将动态设置的变量提取出来在配置文件中设置
const replace = require('rollup-plugin-replace')
// 帮助 Rollup 查找外部模块,然后安装
const node = require('rollup-plugin-node-resolve')
const flow = require('rollup-plugin-flow-no-whitespace')
const version = process.env.VERSION || require('../package.json').version
// 下面是weex服务器端代码,不需要管
// const weexVersion = process.env.WEEX_VERSION || require('../packages/weex-vue-framework/package.json').version // 这边是打包完成后模块外部首行注释代码
const banner =
`/*
* test-vue.js v${version}
* (C) 2014-${new Date().getFullYear()} Enan You
* @author zhengjie
*/
`
// 获取文件夹路径别名
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)
}
}
// 设置打包参数
// 这边把原先vue打包文件去除,替换成知己的一个测试文件
const builds = {
'test-cjs': {
entry: resolve('test/main.js'),
dest: resolve('dist/test-cjs.js'),
format: 'cjs', // csj格式 module.exports
banner
},
'test-es': {
entry: resolve('test/main.js'),
dest: resolve('dist/test-es.js'),
format: 'es', // es格式 export default
banner
},
'test-umd': {
entry: resolve('test/main.js'),
dest: resolve('dist/test-umd.js'),
format: 'umd', // 浏览器格式 return
banner
}
} // 根据上面builds打包转换成rollup打包格式
function getConfig(name) {
const opts = builds[name]
const config = {
input: opts.entry,
external: opts.external,
plugins: [
replace({
__WEEX__: !!opts.weex,
__WEEX_VERSION__: null,
__VERSION__: version
}),
flow(),
buble(),
alias(Object.assign({}, aliases, opts.alias))
].concat(opts.plugins || []),
output: {
file: opts.dest,
format: opts.format,
banner: opts.banner,
name: opts.moduleName || 'Vue'
}
}
// 如果是开发模式
if (opts.env) {
config.plugins.push(replace({
'process.env.NODE_ENV': JSON.stringify(opts.env)
}))
}
// 增加属性
Object.defineProperty(config, '_name', {
enumerable: false,
value: name
}) return config
} if (process.env.TARGET) {
module.exports = getConfig(process.env.TARGET)
} else {
exports.getBuild = getConfig
exports.getAllBuilds = () => Object.keys(builds).map(getConfig)
}

其中里面的builds已被替换成我自己的测试文件,用于测试打败es,模块化和浏览器的不同格式。

build

build文件就是根据配置文件进行打包,打包模式分为全部打包,或者是可配置打包,
如果运行npm run build,将会打包所有的配置,
而运行npm run build '参数', 则根据参数配置进行打包


const fs = require('fs')
const path = require('path')
const zlib = require('zlib')
const rollup = require('rollup')
const uglify = require('uglify-js')
// 检测是否有dist文件
if (!fs.existsSync('dist')) {
fs.mkdirSync('dist')
} let builds = require('./config').getAllBuilds() // build后面输入的参数
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 {
// 这边过滤出weex,不需要管
builds = builds.filter(b => {
return b.output.file.indexOf('weex') === -1
})
}
// 把需要打包的打包出来
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\.js$/.test(file)
return rollup.rollup(config)
.then(bundle => bundle.generate(output))
.then(({code}) => {
// 压缩我文件
if (isProd) {
var minified = (banner ? banner + '\n' : '') + uglify.minify(code, {
output: {
ascii_only: true
},
compress: {
pure_funcs: ['makeMap']
}
}).code
return write(file, minified, true)
} else {
return write(file, code)
}
})
} function write(dest, code, zip) {
return new Promise((resolve, reject) => {
function report (extra) {
console.log(blue(path.relative(process.cwd(), dest)) + ' ' + getSize(code) + (extra || ''))
resolve()
} fs.writeFile(dest, code, err => {
if (err) return reject(err)
if (zip) {
zlib.gzip(code, (err, zipped) => {
if (err) return reject(err)
report(' (gzipped: ' + getSize(zipped) + ')')
})
} else {
report()
}
})
})
}
// 计算文件大小
function getSize (code) {
return (code.length / 1024).toFixed(2) + 'kb'
}
// 输入错误信息
function logError (e) {
console.log(e)
}
function blue (str) {
return '\x1b[1m\x1b[34m' + str + '\x1b[39m\x1b[22m'
}

测试文件

main.js


import foo from './foo';
export default function () {
console.log(foo)
}

foo.js


export default "hello rollup"

通过npm run build打包测试,会在dist文件打包出test-cjs.js,test-es.js,test-umd.js
文件内容如下:
test-cjs.js


/*
* test-vue.js v1.0.0
* (C) 2014-2018 Enan You
* @author zhengjie
*/ 'use strict'; var foo = "hello rollup" function main () {
console.log(foo);
} module.exports = main;

test-es.js


/*
* test-vue.js v1.0.0
* (C) 2014-2018 Enan You
* @author zhengjie
*/ var foo = "hello rollup" function main () {
console.log(foo);
} export default main;

test-umd.js


/*
* test-vue.js v1.0.0
* (C) 2014-2018 Enan You
* @author zhengjie
*/ (function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global.Vue = factory());
}(this, (function () { 'use strict'; var foo = "hello rollup" function main () {
console.log(foo);
} return main; })));

这个构建的过程不难,比起webpack的配置文件要容易懂很多
懂得了vue的构建,接下来就可以开始vue源码的学习了

原文地址:

vue源码构建代码分析的更多相关文章

  1. vue源码逐行注释分析+40多m的vue源码程序流程图思维导图 (diff部分待后续更新)

    vue源码业余时间差不多看了一年,以前在网上找帖子,发现很多帖子很零散,都是一部分一部分说,断章的很多,所以自己下定决定一行行看,经过自己坚持与努力,现在基本看完了,差ddf那部分,因为考虑到自己要换 ...

  2. vue源码入口文件分析

    开发vue项目有段时间了, 之前用angularjs 后来用 reactjs 但是那时候一直没有时间把自己看源码的思考记录下来,现在我不想再浪费这 来之不易的思考, 我要坚持!! 看源码我个人感觉非常 ...

  3. Vue 源码学习(1)

    概述 我在闲暇时间学习了一下 Vue 的源码,有一些心得,现在把它们分享给大家. 这个分享只是 Vue源码系列 的第一篇,主要讲述了如下内容: 寻找入口文件 在打包的过程中 Vue 发生了什么变化 在 ...

  4. vue源码分析—Vue.js 源码构建

    Vue.js 源码是基于 Rollup 构建的,它的构建相关配置都在 scripts 目录下.(Rollup 中文网和英文网) 构建脚本 通常一个基于 NPM 托管的项目都会有一个 package.j ...

  5. 深入vue - 源码目录及构建过程分析

     公众号原文链接:深入vue - 源码目录及构建过程分析   喜欢本文可以扫描下方二维码关注我的公众号 「前端小苑」 ​“ 本文主要梳理一下vue代码的目录,以及vue代码构建流程,旨在对vue源码整 ...

  6. 前端Vue 源码分析-逻辑层

    Vue 源码分析-逻辑层 预期的效果: 监听input的输入,input在输入的时候,会触发 watch与computed函数,并且会更新原始的input的数值.所以直接跟input相关的处理就有3处 ...

  7. Vue源码分析(一) : new Vue() 做了什么

    Vue源码分析(一) : new Vue() 做了什么 author: @TiffanysBear 在了解new Vue做了什么之前,我们先对Vue源码做一些基础的了解,如果你已经对基础的源码目录设计 ...

  8. Vue.js 源码构建(三)

    Vue.js 源码是基于 Rollup 构建的,它的构建相关配置都在 scripts 目录下. 构建脚本 通常一个基于 NPM 托管的项目都会有一个 package.json 文件,它是对项目的描述文 ...

  9. Elasticsearch源码分析 - 源码构建

    原文地址:https://mp.weixin.qq.com/s?__biz=MzU2Njg5Nzk0NQ==&mid=2247483694&idx=1&sn=bd03afe5a ...

随机推荐

  1. UML建模 | Rose | 没有跳出可选择新建RUP的对话框解决方法

  2. [題解](單調隊列dp)【2016noip福建夏令營】探險

    P1917 -- 探险 时间限制:1000MS      内存限制:131072KB 题目描述(explore.cpp) π+e去遗迹探险,遗迹里有 N 个宝箱,有的装满了珠宝,有的装着废品. π+e ...

  3. oratop

    1.下载: 目前,Oratop是在MOS上免费下载.每个db 版本和 os 版本都有对应的程序:The tool is a compiled c program. 不需要编译,直接运行.   (下载文 ...

  4. [已读]精通AngularJS

    觉得可以看第二遍,内容其实还不错啦,就是翻译会有点生硬.

  5. I/O————File对象

    File文件对象 文件和文件夹都是用File代表 创建一个文件对象,(并不会有真正的文件或文件夹被创建) File f1 = new File("d:/lolfilder"); S ...

  6. spring mvc添加静态资源访问时@Controller无效的解决

    web.xml中的url-pattern设置为/,添加mvc:resources访问静态资源时,@Controller无效的问题 web.xml: <servlet> <servle ...

  7. 登录界面点击登录后如何延迟提示成功的div的显示时间并跳转

    需求: 在登录页面点击sign in跳转到下个页面之前,我需要显示成功的窗口2秒然后自动关闭 那我们来研究下setTimeout: 关于这个setTimeout首先下面的代码实现的是两秒之后再显示Su ...

  8. 关于如何用jq定位到某个元素的索引

    在点击事件触发时候,通常如果有同样的className的列表我们都需获取它的索引来知道到底点击的是那一个 $('.info_content').mousemove(function(){ var ro ...

  9. [BZOJ2434][Noi2011]阿狸的打字机 AC自动机+树状数组+离线

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2434 题目中这种多个串匹配的问题,一下子就想到了AC自动机.然后发现如果要建立AC自动机, ...

  10. MFC命令行及CCommandLineInfo类

    获取命令行的方法: 1.GetCommandLine() 获取输入的所有信息,包括程序所在路径及参数 2.AfxGetApp()->m_lpCmdLine 只包含参数 一般情况下,获取到命令行后 ...