一、目錄結構
1、src
├── compiler # 編譯相關
├── core # 核心代碼
├── platforms # 不同平臺的支持
├── server # 服務端渲染
├── sfc # .vue 文件解析
├── shared # 共享代碼
core 目錄:包含了 Vue.js 的核心代碼,包括內置組件、全局 API 封裝,Vue 實例化、觀察者、虛擬 DOM、工具函數等等。這裏的代碼可謂是 Vue.js 的靈魂
platform目錄:Vue.js 是一個跨平臺的 MVVM 框架,它可以跑在 web 上,也可以配合 weex 跑在 natvie 客戶端上。platform 是 Vue.js 的入口,2 個目錄代表 2 個主要入口,分別打包成運行在 web 上和 weex 上的 Vue.js。比如現在比較火熱的mpvue框架其實就是在這個目錄下面多了一個小程序的運行平臺相關內容。
2、new Vue() --->inti---$mount---compile---render---vnode---patch---DOM
3、當調用new Vue的時候,事實上就調用的Vue原型上的_init方法.
4、vue中的雙向數據是通過數據劫持(Object.defineProperty())
結合發佈者-訂閱者模式來實現的,Object.defineProperty()方法會直接在一個對象上定義一個新屬性,
或者修改一個已經存在的屬性, 並返回這個對象。
二、文件說明
1、.circleci 持續部署 持續集成
2、benchmarks 性能監控
3、dist 最終打包出來的結果
4、examples 例子
5、flow vue2採用的是flow 裏面有很多的declare,就是flow的聲明 安裝flow language support 插件
6、pageages 主要就是vue裏面寫的幾個包,
服務端渲染-vue-server-renderer
模板渲染 vue-server-renderer 把模板編譯成render函數
weex-template-compiler
weex-vue-framework
7、secript 主要的作用是構建使用的 比如rollup vue內容也是用rollup來進行打包的
8、src 源碼
9、test 測試 unit單元測試 modules 工具方法 observer
10、types 是ts的中type的聲明文件
三、src
-- "main": "dist/vue.runtime.common.js",
"build": "node scripts/build.js", //打包命令文件 這個就是vue打包執行的語句 核心是node
// rollup 打包,打包工具只能打包webpack 打包內庫
四、build.js
vue-dev\scripts\build.js
const fs = require('fs')
const path = require('path')
const zlib = require('zlib')
const rollup = require('rollup')
const terser = require('terser')
//創建dist目錄 1、查看打包vue的時候,是以那個文件作爲入口的。
if (!fs.existsSync('dist')) { // 創建一個輸出目錄
fs.mkdirSync('dist')
}
// 通過配置來進行打包
// 獲取所有的配置項 是一個通過自定義的對象生成的roll up配置
let builds = require('./config').getAllBuilds()
// filter builds via command line arg
if (process.argv[2]) { //過濾生產的配置和參數
// web-runtime-cjs,web-server-renderer 逗號分隔,filters 過濾
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(builds) //
// 異步遞歸方法next 這個以後會用的很多的哦!!!!
// 循環調用roll up打包
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) {
// minified 壓縮
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)
}
})
}
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'
}
五、config.js
vue-dev\scripts\config.js
const path = require('path')
const buble = require('rollup-plugin-buble')
const alias = require('rollup-plugin-alias')
const cjs = require('rollup-plugin-commonjs')
const replace = require('rollup-plugin-replace')
const node = require('rollup-plugin-node-resolve')
const flow = require('rollup-plugin-flow-no-whitespace')
const version = process.env.VERSION || require('../package.json').version
const weexVersion = process.env.WEEX_VERSION || require('../packages/weex-vue-framework/package.json').version
const featureFlags = require('./feature-flags')
const banner =
'/*!\n' +
` * Vue.js v${version}\n` +
` * (c) 2014-${new Date().getFullYear()} Evan You\n` +
' * Released under the MIT License.\n' +
' */'
const weexFactoryPlugin = {
intro () {
return 'module.exports = function weexFactory (exports, document) {'
},
outro () {
return '}'
}
}
// web/entry-runtime-with-compiler.js
const aliases = require('./alias')
const resolve = p => { // resolve 方法,根據'/'來分割
const base = p.split('/')[0]
if (aliases[base]) { // aliases[base] 中去取web
// aliases 中去取web
return path.resolve(aliases[base], p.slice(base.length + 1))
} else {
return path.resolve(__dirname, '../', p)
}
}
// builds 是自己維護的一個打包對象,不是rollup打包的配置
//builds 代表的是rollup的配置, 這裏有n個配置,
// filter \ builds \ via \ common and arg 過濾要打包的結果
const builds = {
// Runtime only (CommonJS). Used by bundlers e.g. Webpack & Browserify
// cjs---CommonJS vue 分爲兩種類型 Runtime only(); 這裏不寫 體積小
// runtime-with-compiler 用戶可以寫template 編譯原理
// .vue template 中vue-loader來編譯的。
// 打包平臺的不同 web week
// compiler+runtime=full;
// runtime 裏面沒有compiler, 在開發的時候不能使用template語法 <template></template>
// .vue文件 使用vue-loader來處理的。 和compiler 無關
// compiler 可以將模板轉化成render函數
// esm:es6的模塊 umd:是amd和common.js的集合體 common規範:
// 三個不同:平臺不同(web和week)、打包出來的結果不同(compiler和runtime)、打包的格式不同(common.js,esm,umd)
// entry-runtime.js
'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+compiler CommonJS build (CommonJS)
'web-full-cjs-dev': {
entry: resolve('web/entry-runtime-with-compiler.js'),
dest: resolve('dist/vue.common.dev.js'),
format: 'cjs',
env: 'development',
alias: { he: './entity-decoder' },
banner
},
'web-full-cjs-prod': {
entry: resolve('web/entry-runtime-with-compiler.js'),
dest: resolve('dist/vue.common.prod.js'),
format: 'cjs',
env: 'production',
alias: { he: './entity-decoder' },
banner
},
// Runtime only ES modules build (for bundlers)
'web-runtime-esm': {
entry: resolve('web/entry-runtime.js'),
dest: resolve('dist/vue.runtime.esm.js'),
format: 'es',
banner
},
// Runtime+compiler ES modules build (for bundlers)
//
'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+compiler ES modules build (for direct import in browser)
'web-full-esm-browser-dev': {
entry: resolve('web/entry-runtime-with-compiler.js'),
dest: resolve('dist/vue.esm.browser.js'),
format: 'es',
transpile: false,
env: 'development',
alias: { he: './entity-decoder' },
banner
},
// Runtime+compiler ES modules build (for direct import in browser)
'web-full-esm-browser-prod': {
entry: resolve('web/entry-runtime-with-compiler.js'),
dest: resolve('dist/vue.esm.browser.min.js'),
format: 'es',
transpile: false,
env: 'production',
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', // 統一模塊規範, 包括commonJS amd和cmd
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
},
// 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)
},
// Web compiler (UMD for in-browser use).
'web-compiler-browser': {
entry: resolve('web/entry-compiler.js'),
dest: resolve('packages/vue-template-compiler/browser.js'),
format: 'umd',
env: 'development',
moduleName: 'VueTemplateCompiler',
plugins: [node(), cjs()]
},
// Web server renderer (CommonJS).
'web-server-renderer-dev': {
entry: resolve('web/entry-server-renderer.js'),
dest: resolve('packages/vue-server-renderer/build.dev.js'),
format: 'cjs',
env: 'development',
external: Object.keys(require('../packages/vue-server-renderer/package.json').dependencies)
},
'web-server-renderer-prod': {
entry: resolve('web/entry-server-renderer.js'),
dest: resolve('packages/vue-server-renderer/build.prod.js'),
format: 'cjs',
env: 'production',
external: Object.keys(require('../packages/vue-server-renderer/package.json').dependencies)
},
'web-server-renderer-basic': {
entry: resolve('web/entry-server-basic-renderer.js'),
dest: resolve('packages/vue-server-renderer/basic.js'),
format: 'umd',
env: 'development',
moduleName: 'renderVueComponentToString',
plugins: [node(), cjs()]
},
'web-server-renderer-webpack-server-plugin': {
entry: resolve('server/webpack-plugin/server.js'),
dest: resolve('packages/vue-server-renderer/server-plugin.js'),
format: 'cjs',
external: Object.keys(require('../packages/vue-server-renderer/package.json').dependencies)
},
'web-server-renderer-webpack-client-plugin': {
entry: resolve('server/webpack-plugin/client.js'),
dest: resolve('packages/vue-server-renderer/client-plugin.js'),
format: 'cjs',
external: Object.keys(require('../packages/vue-server-renderer/package.json').dependencies)
},
// Weex runtime factory
'weex-factory': {
weex: true,
entry: resolve('weex/entry-runtime-factory.js'),
dest: resolve('packages/weex-vue-framework/factory.js'),
format: 'cjs',
plugins: [weexFactoryPlugin]
},
// Weex runtime framework (CommonJS).
'weex-framework': {
weex: true,
entry: resolve('weex/entry-framework.js'),
dest: resolve('packages/weex-vue-framework/index.js'),
format: 'cjs'
},
// Weex compiler (CommonJS). Used by Weex's Webpack loader.
'weex-compiler': {
weex: true,
entry: resolve('weex/entry-compiler.js'),
dest: resolve('packages/weex-template-compiler/build.js'),
format: 'cjs',
external: Object.keys(require('../packages/weex-template-compiler/package.json').dependencies)
}
}
function genConfig (name) {
const opts = builds[name] // 獲取到每個key對應的配置。 獲取聲明的對象
const config = { // rollup的真正的配置,input、output rollup的真實配置,
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
})
// 做了一堆配置,最好把config返回了。
return config
}
if (process.env.TARGET) {
module.exports = genConfig(process.env.TARGET)
} else {
exports.getBuild = genConfig
// 獲取所有打包的配置
//將對象所有的key 轉化成數組 map方法返回的是一個數組。
// genConfig 生成rollup的配置文件
exports.getAllBuilds = () => Object.keys(builds).map(genConfig)
}