有专业做网站优化的吗,姓名logo设计在线生成,分销 社交 电商系统,机关网站建设方案大家好#xff0c;我是若川。持续组织了6个月源码共读活动#xff0c;感兴趣的可以点此加我微信 ruochuan12 参与#xff0c;每周大家一起学习200行左右的源码#xff0c;共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列Rollu… 大家好我是若川。持续组织了6个月源码共读活动感兴趣的可以点此加我微信 ruochuan12 参与每周大家一起学习200行左右的源码共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。历史面试系列Rollup 是一个 JavaScript 模块打包器它将小块的代码编译并合并成更大、更复杂的代码比如打包一个库或应用程序。它使用的是 ES Modules 模块化标准而不是之前的模块化方案如 CommonJS 和 AMD。ES 模块可以让你自由、无缝地使用你最喜爱库中那些最有用的独立函数而让你的项目无需包含其他未使用的代码。近期在团队内组织学习 Rollup 专题在着重介绍了 Rollup 核心概念和插件的 Hooks 机制后为了让小伙伴们能够深入了解 Rollup 在实际项目中的应用。我们就把目光转向了优秀的开源项目之后就选择了尤大的 Vue/Vite/Vue3 项目接下来本文将先介绍 Rollup 在 Vue 中的应用。dev 命令在 vue-2.6.14 项目根目录下的 package.json 文件中我们可以找到 scripts 字段在该字段内定义了如何构建 Vue 项目的相关脚本。{name: vue,version: 2.6.14,sideEffects: false,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 命令为例来介绍一下与 rollup 相关的配置项-c指定 rollup 打包的配置文件-w开启监听模式当文件发生变化的时候会自动打包--environment设置环境变量设置后可以通过 process.env 对象来获取已配置的值。由 dev 命令可知 rollup 的配置文件是 scripts/config.js// scripts/config.js
// 省略大部分代码
if (process.env.TARGET) {module.exports genConfig(process.env.TARGET)
} else {exports.getBuild genConfigexports.getAllBuilds () Object.keys(builds).map(genConfig)
}观察以上代码可知当 process.env.TARGET 有值的话就会根据 TARGET 的值动态生成打包配置对象。// scripts/config.js
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)}}}// 省略部分代码return config
}在 genConfig 函数内部会从 builds 对象中获取当前目标对应的构建配置对象。当目标为 web-full-dev 时它对应的配置对象如下所示// scripts/config.js
const builds { web-runtime-cjs-dev: { ... },web-runtime-cjs-prod: { ... },// Runtimecompiler 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},
}在每个构建配置对象中会定义 entry入口文件、dest 输出文件、format输出格式等信息。当获取构建配置对象后就根据 rollup 的要求生成对应的配置对象。需要注意的是在 Vue 项目的根目录中是没有 web 目录的该项目的目录结构如下所示├── BACKERS.md
├── LICENSE
├── README.md
├── benchmarks
├── dist
├── examples
├── flow
├── package.json
├── packages
├── scripts
├── src
├── test
├── types
└── yarn.lock那么 web/entry-runtime-with-compiler.js 入口文件的位置在哪呢其实是利用了 rollup 的 rollup/plugin-alias 插件为地址取了个别名。具体的映射规则被定义在 scripts/alias.js 文件中// 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)
}根据以上的映射规则我们可以定位到 web 别名对应的路径该路径对应的文件结构如下├── compiler
├── entry-compiler.js
├── entry-runtime-with-compiler.js
├── entry-runtime.js
├── entry-server-basic-renderer.js
├── entry-server-renderer.js
├── runtime
├── server
└── util到这里结合前面介绍的 builds 对象相信你也知道了 Vue 是如何打包不同类型的文件以满足不同场景的需求比如含有编译器和不包含编译器的版本。分析完 dev 命令的处理流程下面我来分析 build 命令。build 命令同样在根目录下 package.json 的 scripts 字段我们可以找到 build 命令的定义{name: vue,version: 2.6.14,sideEffects: false,scripts: {build: node scripts/build.js,...
}当你运行 build 命令时会使用 node 应用程序执行 scripts/build.js 文件// scripts/build.js
let builds require(./config).getAllBuilds()// filter builds via command line arg
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 defaultbuilds builds.filter(b {return b.output.file.indexOf(weex) -1})
}build(builds)在 scripts/build.js 文件中会先获取所有的构建目标然后根据进行过滤操作最后再调用 build 函数进行构建操作该函数的处理逻辑也很简单就是遍历构建列表然后调用 buildEntry 函数执行构建操作。// scripts/build.js
function build (builds) {let built 0const total builds.lengthconst next () {buildEntry(builds[built]).then(() {builtif (built total) {next()}}).catch(logError)}next()
}当 next 函数执行时就会开始调用 buildEntry 函数在该函数内部就是根据传入了配置对象调用 rollup.rollup API 进行构建操作// scripts/build.js
function buildEntry (config) {const output config.outputconst { file, banner } outputconst 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]}}).codereturn write(file, minified, true)} else {return write(file, code)}})
}当打包完成后下一个环节就是生成文件。在 buildEntry 函数中是通过调用 write 函数来生成文件// scripts/build.js
const fs require(fs)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()}})})
}write 函数内部是通过 fs.writeFile 函数来生成文件该函数还支持 zip 参数用于输出经过 gzip 压缩后的大小。现在我们已经分析完了 dev 和 build 命令最后我们来简单介绍一下构建过程中所使用的一些核心插件。rollup 插件在 package.json 文件中我们可以看到 Vue2 项目中用到的 rollup 插件// package.json
{name: vue,version: 2.6.14,devDependencies: {rollup-plugin-alias: ^1.3.1,rollup-plugin-buble: ^0.19.6,rollup-plugin-commonjs: ^9.2.0,rollup-plugin-flow-no-whitespace: ^1.0.0,rollup-plugin-node-resolve: ^4.0.0,rollup-plugin-replace: ^2.0.0,}
}其中rollup-plugin-alias 插件在前面我们已经知道它的作用了。而其他插件的作用如下rollup-plugin-buble该插件使用 buble 转换 ES2015 代码它已经被移到新的仓库 rollup/plugin-bublerollup-plugin-commonjs该插件用于把 CommonJS 模块转换为 ES6 Modules它已经移到新的仓库 rollup/plugin-commonjsrollup-plugin-flow-no-whitespace该插件用于移除 flow types 中的空格rollup-plugin-node-resolve该插件用于支持使用 node_modules 中第三方模块会使用 Node 模块解析算法来定位模块。它也被移动到新的仓库 rollup/plugin-node-resolverollup-plugin-replace该插件用于在打包时执行字符串替换操作它也被移动到新的仓库 rollup/plugin-replace。除了以上的插件在实际的项目中你也可以使用 Rollup 官方仓库提供的插件来实现对应的功能具体如下图所示仅包含部分插件来源https://github.com/rollup/plugins总结本文只是简单介绍了 Rollup 在 Vue 2 中的应用很多细节并没有展开介绍感兴趣的小伙伴可以自行学习一下。如果遇到问题的话欢迎跟我一起交流哈。另外你们也可以自行分析一下在 Vue 3 和 Vite 项目中是如何利用 Rollup 进行打包的。················· 若川简介 ·················你好我是若川毕业于江西高校。现在是一名前端开发“工程师”。写有《学习源码整体架构系列》20余篇在知乎、掘金收获超百万阅读。从2014年起每年都会写一篇年度总结已经写了7篇点击查看年度总结。同时最近组织了源码共读活动帮助3000前端人学会看源码。公众号愿景帮助5年内前端人走向前列。识别上方二维码加我微信、拉你进源码共读群今日话题略。分享、收藏、点赞、在看我的文章就是对我最大的支持~