这是我参与更文挑战的第7天,活动详情查看: 更文挑战
在执行
npm run build
之后项目的构建过程
所有代码
const fs = require('fs')
const path = require('path')
const zlib = require('zlib')
const rollup = require('rollup')
const terser = require('terser')
if (!fs.existsSync('dist')) {
fs.mkdirSync('dist')
}
let builds = require('./config').getAllBuilds()
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)
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)
}
})
}
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'
}
代码分析
-
if (!fs.existsSync('dist')) { fs.mkdirSync('dist') }
- 判断是否已经存在了
dist
目录,不存在就创建一个目录
- 判断是否已经存在了
-
let builds = require('./config').getAllBuilds()
-
获取
./config
文件中的所有的配置数据,并将其转换成符合rollup
适用的格式 -
配置文件
config.js
-
exports.getAllBuilds = () => Object.keys(builds).map(genConfig) 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) } } } const builds = { 'web-runtime-cjs-dev': { entry: resolve('web/entry-runtime.js'), // 入口文件 dest: resolve('dist/vue.runtime.common.dev.js'),// 出口文件 format: 'cjs', // 是common.js 或是 es6 啥的格式 env: 'development', banner // 文件上面的注释 }, .....其他配置数据 } }
genConfig
主要是对builds
中的数据进行配置,使得其符合rollup
的所需的个格式
-
-
-
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 { builds = builds.filter(b => { return b.output.file.indexOf('weex') === -1 }) }
process
是node
的一个进程相关的全局变量,其中process.argv[0]
表示启动进程的可执行文件所在的路径,process.argv[1]
表示当前执行的js文件路径 ,process.argv[2]
表示其他的命令行参数node scripts/build.js "web-runtime-cjs,web-server-renderer"
其中process.argv[2]
就是web-runtime-cjs,web-server-renderer
- 在执行
npm run build
的时候其实是在执行node node scripts/build.js
;那么当前获取到的process.argv[2]
是空的,就执行else
中的内容,对获取到的build
数据进行过滤,过滤掉build
的输出文件中包含weex
的对象
-
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() }
- 依次对
builds
中的配置执行buildEntry
,这个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) } }) }
- 获取到配置对象输出的文件名称
file
和banner
文件警告 - 判断文件名称是否需要进行压缩,需要就将文件进行压缩之后在写入文件
- 否则的话直接将代码写入就可,其中压缩代码主要是使用的
zlib.gzip
进行
- 获取到配置对象输出的文件名称