源码构建
-
介绍
版本:2.5.17
-
项目Rollup介绍
官网:https://github.com/rollup/rollup
Vue.js 源码是基于 Rollup 构建的,它的构建相关配置都在 scripts 目录下。-
Rollup和webpack都是区别
-
webpack更加强大 可以将图片,css等都解析为js。
rollup 更适合于js库的编译,只适用于js部分,别的文件是不管的,并且更加友好
-
构建脚本
通常一个基于 NPM 托管的项目,在它的根目录下都会有一个 package.json 文件,它是对项目的描述文件,它的内容实际上是一个标准的 JSON 对象。
vue的 package.json我们将其简写为:
{
"name": "vue",
"version": "2.5.17-beta.0",
"description": "Reactive, component-oriented view layer for modern web interfaces.",
"main": "dist/vue.runtime.common.js",
"module": "dist/vue.runtime.esm.js",
"script": {
"build": "node scripts/build.js",
"build:ssr": "npm run build -- web-runtime-cjs,web-server-renderer",
"build:weex": "npm run build --weex"
}
当在命令行运行 npm run build 的时候,实际上就会执行 node scripts/build.js
-
构建过程
构建运行 node scripts/build.js
-
scripts文件下build.js 中
- 主要过程
1.通过let builds = require(‘./config’).getAllBuilds()拿到每一种vue.js的相关配置
2.对所有的配置进行过滤,将package.json中的命令,例如npm run build – web-runtime-cjs,web-server-renderer,就是过滤掉不是web-runtime-cjs,web-server-renderer的,如果没有传参数,例如npmrun build 那么就只将weex过滤,只打包web平台
// 拿到所有的构建的配置 let builds = require('./config').getAllBuilds() // 将配置进行过滤,将package.json中的命令,例如npm run build -- web-runtime-cjs,web-server-renderer, // 就是过滤掉不是web-runtime-cjs,web-server-renderer的,如果没有传参数,例如npm run build 那么就只将weex过滤,只打包web平台 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(builds)
3.对过滤后的vue.js文件进行build,文件中用的就是build函数
4.build.js完整代码
// 引入包 const fs = require('fs') const path = require('path') const zlib = require('zlib') const rollup = require('rollup') const uglify = require('uglify-js') if (!fs.existsSync('dist')) { fs.mkdirSync('dist') } // 拿到所有的构建的配置 let builds = require('./config').getAllBuilds() // 将配置进行过滤,将package.json中的命令,例如npm run build -- web-runtime-cjs,web-server-renderer,就是过滤掉不是web-runtime-cjs,web-server-renderer的,如果没有传参数,例如npm run build 那么就只将weex过滤,只打包web平台 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) // build 在去调用buildEntry函数 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 }) => { // 如果是 min.js 结尾的js就再进行一次压缩 if (isProd) { var minified = (banner ? banner + '\n' : '') + uglify.minify(code, { output: { ascii_only: true }, compress: { pure_funcs: ['makeMap'] } }).code // 调用write方法 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方法将文件生成到dist目录下 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) {} function logError (e) {} function blue (str) {}
-
scripts文件下config.js
-
build.js在该文件中拿到了每一种vue.js的相关配置
大致过程 :
1.通过const aliases = require(‘./alias’),拿到大部分文件的路径
2.对resolve方法进行封装,配合aliases文件,其实就是获取文件的路径,如下面的entry入口文件
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)
}
}
3.const builds = {},不同版本vue.js的配置
4.function genConfig (name){} 真正的构建工具rollup的配置,每一种vue.js就会对用不同的配置
5.将通过vue.js的配置而得到的rollup的具体配置输出
if (process.env.TARGET) {
module.exports = genConfig(process.env.TARGET)
} else {
exports.getBuild = genConfig
exports.getAllBuilds = () => Object.keys(builds).map(genConfig)
}
具体代码
引入的文件或组件
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 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 '}'
}
}
// 引入./alias文件
const aliases = require('./alias')
// 对resolve方法进行封装,其实就是获取文件的路径,如下面的entry入口文件
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.js的配置
const builds = {
// Runtime only (CommonJS). Used by bundlers e.g. Webpack & Browserify
'web-runtime-cjs': {
// 入口文件,resolve函数调用aliases文件,最终拼接该s文件真正的路径,如果aliases文件中没有定义,那么就会走resolve函数的else
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 production build (Browser)
'web-runtime-prod': {
},
// Runtime+compiler development build (Browser)
'web-full-dev': {
},
// Runtime+compiler production build (Browser)
'web-full-prod': {
},
// Web compiler (CommonJS).
'web-compiler': {
},
// Web compiler (UMD for in-browser use).
'web-compiler-browser': {
},
// Web server renderer (CommonJS).
'web-server-renderer': {
},
'web-server-renderer-basic': {
},
'web-server-renderer-webpack-server-plugin': {
},
'web-server-renderer-webpack-client-plugin': {
},
// Weex runtime factory
'weex-factory': {
},
// Weex runtime framework (CommonJS).
'weex-framework': {
},
// Weex compiler (CommonJS). Used by Weex's Webpack loader.
'weex-compiler': {
}
}
// 构建工具rollup真正的配置,上面的是每一中版本的vue.js的配置,下面才是构建工具rollup真正的配置
function genConfig (name) {
const opts = builds[name]
const config = {
input: opts.entry,
external: opts.external,
plugins: [
replace({
__WEEX__: !!opts.weex,
__WEEX_VERSION__: weexVersion,
__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 = genConfig(process.env.TARGET)
} else {
exports.getBuild = genConfig
exports.getAllBuilds = () => Object.keys(builds).map(genConfig)
}
-
scripts文件下alias.js
真实路径的映射, 例如 config.js 中的builds对象
entry: resolve('web/entry-runtime.js'),
web指的就是alias.js中 的
web: resolve('src/platforms/web'),
完整代码:
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')
-
完整过程
npm run build
执行
script/build.js
build.js————-引入config.js,将配置进行过滤,过滤后再通过build函数进行真正的构建过程
config.js————引入alias.js,配置不同vue.js的配置,根据不同vue.js的配置输出不同构建工具rollup真正的配置
alias.js————–提供文件的路径映射
学习文档:https://ustbhuangyi.github.io/vue-analysis/components/lifecycle.html