Rollup基础知识
Vue.js
通过rollup
构建工具进行构建,它是一个类似于webpack
的打包工具,区别于webpack
它更适合一个Library
库的打包。在学习Vue.js
源码之前,我们有必要知道Vue.js
是如何构建不同版本的。
核心概念
同webpack
一样,rollup
也有以下几大核心概念:
input
:入口文件,类比于webpack
的entry
,它指明了我们库文件入口位置。output
:输出位置,它指明了打包后的输出信息,包括:输出目录,打包文件名等。plugins
:插件,rollup
在构建过程中,插件可提供一些辅助功能,例如:alias
别名解析、转义ES6
等。external
:当我们的库依赖于其它第三方库时,我们不需要把这些第三方库一起打包,而是应该把依赖写在external
里面。
同webpack
一样,rollup
同样适合使用配置文件的做法来配置打包的选项,例如:
// rollup.config.js
export default {
input: 'src/main.js',
output: [
{ file: 'dist/vue.js', format: 'umd', name: 'Vue' },
{ file: 'dist/vue.common.js', format: 'cjs', name: 'Vue' },
{ file: 'dist/vue.esm.js', format: 'es', name: 'Vue' }
]
}
构建版本说明:
umd
:此选项构建出来的库文件主要适用于Web
端,可以通过不同的方式去使用:script
标签引入,ES Module
规范引入和CommonJs
规范引入等。cjs
: 此选项构建出来的库文件主要为CommonJs
规范,可在Node
环境中使用。es
:此版本构建出来的库文件主要为ES Module
规范,可在支持ES Module
也就是import/export
的环境中使用。
有了以上配置文件,我们可以在package.json
中进行如下修改:
{
"name": "Vue",
"version": "1.0.0",
"scripts": {
"dev": "rollup -w -c scripts/rollup.config.dev.js",
"build": "rollup -c scripts/rollup.config.prod.js"
}
}
参数说明:
-c
:为--config
的缩写,表示设置rollup
打包的配置。-w
:为--watch
的缩写,在本地开发环境添加-w
参数可以监控源文件的变化,自动重新打包。
常用插件
rollup
并不像webpack
那样强大,它需要和其它插件配合使用才能完成特定的功能,常用的插件有:
@rollup/plugin-json
: 支持从.json
读取信息,配合rollup
的Tree Shaking
可只打包.json
文件中我们用到的部分。@rollup/plugin-commonjs
:将CommonJs
规范的模块转换为ES6
提供rollup
使用。@rollup/plugin-node-resolve
:与@rollup/plugin-commonjs
插件一起使用,配合以后就可以使用node_modules
下的第三方模块代码了。@rollup/plugin-babel
:把ES6
代码转义成ES5
代码,需要同时安装@babel/core
和@babel/preset-env
插件。注意:如果使用了高于ES6
标准的语法,例如async/await
,则需要进行额外的配置。rollup-plugin-terser
:代码压缩插件,另外一种方案是rollup-plugin-uglify
+uglify-es
进行代码压缩,不过更推荐第一种方案。
以上插件使用方式如下:
// rollup.config.js
import commonjs from '@rollup/plugin-commonjs'
import json from '@rollup/plugin-json'
import resolve from '@rollup/plugin-node-resolve'
import babel from '@rollup/plugin-babel'
import { terser } from 'rollup-plugin-terser'
const config = {
input: 'src/index.js',
output: [
{ file: 'dist/vue.js', format: 'umd', name: 'Vue' },
{ file: 'dist/vue.common.js', format: 'cjs', name: 'Vue', exports: 'auto' },
{ file: 'dist/vue.esm.js', format: 'es', name: 'Vue', exports: 'auto' }
],
plugins: [
json(),
resolve(),
babel(),
commonjs(),
terser()
]
}
export default config
区分生产环境和开发环境
正如你在上面看到的那样,我们可以像webpack
一样进行开发环境和生产环境的配置区分,我们把和rollup
构建相关的文件都放在scripts
目录下:
|-- scripts
| |-- rollup.config.base.js # 公共配置
| |-- rollup.config.dev.js # 开发环境配置
| |-- rollup.config.prod.js # 生产环境配置
根据我们的拆分逻辑,rollup.config.base.js
代码如下:
import commonjs from '@rollup/plugin-commonjs'
import json from '@rollup/plugin-json'
import resolve from '@rollup/plugin-node-resolve'
import babel from '@rollup/plugin-babel'
const config = {
input: 'src/index.js',
plugins: [
json(),
resolve(),
babel(),
commonjs()
]
}
export default config
rollup.config.dev.js
代码如下:
import baseConfig from './rollup.config.base.js'
import serve from 'rollup-plugin-serve'
import { name } from '../package.json'
const config = {
...baseConfig,
output: [
{ file: 'dist/vue.js', format: 'umd', name },
{ file: 'dist/vue.common.js', format: 'cjs', name, exports: 'auto' },
{ file: 'dist/vue.esm.js', format: 'es', name, exports: 'default' }
],
plugins: [
...baseConfig.plugins,
serve({
open: true,
port: '4300',
openPage: '/example/index.html',
contentBase: ''
})
]
}
export default config
配置说明:本地开发环境下,我们可以有选择的添加rollup-plugin-serve
插件,它类似于webpack-dev-server
,能在开发环境下起一个服务方便我们进行开发和代码调试。
rollup.config.prod.js
代码如下:
import baseConfig from './rollup.config.base.js'
import { terser } from 'rollup-plugin-terser'
import { name } from '../package.json'
const config = {
...baseConfig,
output: [
{ file: 'dist/vue.min.js', format: 'umd', name },
{ file: 'dist/vue.common.min.js', format: 'cjs', name, exports: 'auto' },
{ file: 'dist/vue.esm.min.js', format: 'es', name, exports: 'default' }
],
plugins: [
...baseConfig.plugins,
terser()
]
}
export default config
配置说明:生产环境下,我们需要对代码进行压缩处理,对ES Module
,CommonJs
和UMD
等规范分别生成其对应的压缩文件。
分别运行npm run dev
和npm run build
之后,我们可以得到如下的目录:
|-- dist
| |-- vue.js # UMD未压缩版本
| |-- vue.min.js # UMD压缩版本
| |-- vue.esm.js # ES Module未压缩版本
| |-- vue.esm.min.js # ES Module压缩版本
| |-- vue.common.js # CommonJs未压缩版本
| |-- vue.common.min.js # CommonJs压缩版本
最后,如果我们像Vue.js
一样构建的是一个库文件,那么我们还需要在package.json
进行如下配置:
{
"main": "dist/vue.common.js",
"module": "dist/vue.esm.js"
}
Vue中的Rollup构建
在阅读Vue.js
源码时,我们首先应该去看其package.json
文件内容,在Vue.js
项目中其精简掉与compiler
、weex
和ssr
相关的内容以后,如下所示:
{
"name": "vue",
"version": "2.6.11",
"main": "dist/vue.runtime.common.js",
"module": "dist/vue.runtime.esm.js",
"scripts": {
"dev": "rollup -w -c scripts/config.js --environment TARGET:web-full-dev",
"dev:cjs": "rollup -w -c scripts/config.js --environment TARGET:web-runtime-cjs-dev",
"dev:esm": "rollup -w -c scripts/config.js --environment TARGET:web-runtime-esm",
"dev:ssr": "rollup -w -c scripts/config.js --environment TARGET:web-server-renderer",
"build": "node scripts/build.js"
}
}
我们可以从上面很容易的发现,其精简后的内容和我们在rollup
基础知识里面的配置十分相似,其构建脚本同样放置在scripts
目录下。在scripts
目录下,我们需要重点关注下面几个文件:
alias.js
:与rollup
构建别名相关的配置。config.js
:与rollup
构建不同版本相关的代码。build.js
:rollup
构建不同压缩版本Vue.js
文件相关代码。
alias别名
我们在开发Vue
应用时,经常会用到@
别名,其中@
代表src
目录:
// 使用别名
import HelloWorld from '@/components/HelloWorld.vue'
// 相当于
import HelloWorld from 'src/components/HelloWorld.vue'
在scripts/alias.js
中,我们可以发现其别名配置代码如下:
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'),
sfc: resolve('src/sfc')
}
以core
别名为例,在Vue.js
源码中,我们通过别名进行如下引入:
// 使用core别名
import Vue from 'core/instance/index.js'
// 相当于
import Vue from 'src/core/instance/index.js'
其中alias.js
文件是在config.js
中引入并使用的:
// config.js文件
import alias from 'rollup-plugin-alias'
import aliases from './alias.js'
function genConfig () {
const config = {
plugins: [
alias(Object.assign({}, aliases))
])
}
return config
}
注意:由于Vue.js
中使用rollup
主版本以及其周边插件的版本较低,如果你使用了最新的rollup
版本或者其周边的插件,需要按照最新插件的配置要求来,这里以最新的@rollup/plugin-alias
插件为例:
const path = require('path')
const resolve = p => path.resolve(__dirname, '../', p)
module.exports = [
{ file: 'vue', replacement: resolve('src/platforms/web/entry-runtime-with-compiler') },
{ file: 'compiler', replacement: resolve('src/compiler') },
{ file: 'core', replacement: resolve('src/core') },
{ file: 'shared', replacement: resolve('src/shared') },
{ file: 'web', replacement: resolve('src/platforms/web' },
{ file: 'weex', replacement: resolve('src/platforms/weex') },
{ file: 'server', replacement: resolve('src/server') },
{ file: 'sfc', replacement: resolve('src/sfc') }
]
其在config.js
新的使用方式同样需要做调整,如下:
// config.js文件
import alias from '@rollup/plugin-alias'
import aliases from './alias.js'
function genConfig () {
const config = {
plugins: [
alias({ entries: aliases })
])
}
return config
}
config.js
首先我们从package.json
打包命令中可以看到,在development
环境下它通过-c
指定了rollup
的配置文件,所以会使用到scripts/config.js
文件,并且打包命令还提供了一个叫做TARGET
的环境变量:
{
"scripts": {
"dev": "rollup -w -c scripts/config.js --environment TARGET:web-full-dev",
"dev:cjs": "rollup -w -c scripts/config.js --environment TARGET:web-runtime-cjs-dev",
"dev:esm": "rollup -w -c scripts/config.js --environment TARGET:web-runtime-esm",
}
}
那么在scripts/config.js
文件下,我们可以看到它是通过module.exports
导出的一个对象:
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,
name: opts.moduleName || 'Vue'
},
onwarn: (msg, warn) => {
if (!/Circular/.test(msg)) {
warn(msg)
}
}
}
return config
}
if (process.env.TARGET) {
module.exports = genConfig(process.env.TARGET)
} else {
exports.getBuild = genConfig
exports.getAllBuilds = () => Object.keys(builds).map(genConfig)
}
在以上代码中,我们可以看到module.exports
导出的对象,主要是通过genConfig()
函数返回的,其中这个函数接受的参数正是我们在打包命令中提供的环境变量TARGET
。我们再来粗略的看一下genConfig()
函数,它的主要作用依然是生成rollup
几大核心配置,然后返回配置完毕后的对象。
我们再来看一个叫做builds
的对象,由于在源码中它的内容非常多,为了节省篇幅我们精简后其代码如下:
const builds = {
// 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',
},
'web-full-cjs-prod': {
entry: resolve('web/entry-runtime-with-compiler.js'),
dest: resolve('dist/vue.common.prod.js'),
format: 'cjs',
env: 'production'
},
// 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'
},
// 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'
},
// 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'
}
}
我们可以发现它的键名正好是我们打包命令中提供的环境变量TARGET
的值,这里以web-full-dev
为例,它通过web-full-dev
这个键可以得到一个对象:
{
entry: resolve('web/entry-runtime-with-compiler.js'),
dest: resolve('dist/vue.js'),
format: 'umd',
env: 'development'
}
然后配合resolve
函数和上面我们已经提到过的别名配置,就可以构造下面这样的rollup
配置对象:
{
// 省略其它
input: 'src/platforms/web/entry-runtime-with-compiler.js',
output: {
dest: 'dist/vue.js',
format: 'umd',
name: 'Vue'
}
}
build.js
srcipts/build.js
文件的作用就是通过配置然后生成不同版本的压缩文件,其中它获取配置的方式同样是在scripts/config.js
文件中,其中关键代码为:
// config.js中导出
exports.getAllBuilds = () => Object.keys(builds).map(genConfig)
// build.js中引入
let builds = require('./config').getAllBuilds()
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!