(一)打包构建工具
说到 构建打包工具,我首先第一反应是 webpack,而在 vue 源码中,是使用 rollup 来打包构建的
(二)打包构建发生了啥
在package.json 的 scripts 中,我们看到了三条关于构建相关的命令
// 正常的打包,没区分端
"build": "node scripts/build.js",
// 服务端 ssr 的打包
"build:ssr": "npm run build -- web-runtime-cjs,web-server-renderer",
// weex 多端的打包
"build:weex": "npm run build -- weex",
什么是Weex:
Weex 致力于使开发者能基于通用跨平台的 Web 开发语言和开发经验,来构建 Android、iOS 和 Web 应用。
当 npm run build 构建的时候 执行 scripts/build.js 文件
引入 config.js 文件中,区分环境的时候,每个环境的配置封装成了对象
'web-runtime-cjs-dev': {
entry: resolve('web/entry-runtime.js'),
dest: resolve('dist/vue.runtime.common.dev.js'),
format: 'cjs',
env: 'development',
banner
},
entry:入口文件
dest:出口文件
format:输出格式 在 rollup 中有五种 (amd / es6 / iife / umd / cjs
env:环境
banner:注释
代码:
const fs = require('fs')
const path = require('path')
const zlib = require('zlib')
const rollup = require('rollup')
const terser = require('terser')
// 如果不存在dist文件夹 则创建dist文件夹
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方法
buildEntry(builds[built]).then(() => {
built++ // 计数
if (built < total) {
next()
}
}).catch(logError)
}
next()
}
// 拿到rollup需要的配置 输出output 开始执行write
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)
}
})
}
// 写入 dist 文件下
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'
}
(三)Runtime-Compiler 和 Runtime-Only的区别
参考文章:https://blog.csdn.net/liusixsixsix/article/details/108236185
总之就是 两者将 template 编译成为 render 函数的时机不同,Runtime-Only 是在将 template 打包的时候就编译为 render 函数,Runtime-Compiler 是运行时才编译render 函数,首选 Runtime-Only