初见 Rollup 的十大常见问题

文章目录

  • 初见 Rollup 的十大常见问题
    • 1. 超神奇的 Rollup 英文解释!
    • 2. 为什么 ESM 要比 CommonJS 要好呢?
    • 3. 什么是 tree-shaking ?
    • 4. 如何使用 Rollup 处理 CommonJS?
    • 5. 为什么 node-resolve 不是一个内置功能?
    • 6. 为什么在进行代码分割时,入口块中会出现额外的导入?
    • 7. 如何将 polyfills 添加到 Rollup 包中?
    • 8. Rollup 是用来构建库还是应用程序?
    • 9. Rollup 和 Webpack 有什么区别呢?
    • 10. 如何在浏览器中运行 Rollup?
    • 写在最后

初见 Rollup 的十大常见问题

有看到社区记录了非常多的 Rollup 相关的一些问题,有些也是我刚接触 Rollup 时会疑惑的地方,在这里做一个记录和分享,希望你会喜欢。

在这里插入图片描述

1. 超神奇的 Rollup 英文解释!

如果打开 Rollup 官网,你会发现这样一段英文,好吧,上面图片就有。

rollup.js
The JavaScript module bundlerCompile small pieces of code into something larger and more complex

前面两句好像没什么,Rollup 是一个 JavaScript 的模块打包器,但第二句就神奇了:可以将小块代码编译成大块且复杂的代码

哇!这什么东东,把小的东西整成复杂的?这难道就是传说中真正的高手:简单问题复杂化吗?不知道你是否用同样的疑惑哈,反正我是没太懂。

解释来了:Rollup 是一个 JavaScript 模块打包器,它的主要作用是将多个小的相互依赖的 JavaScript 文件(也就是通常说的 “模块”)合并成一个或多个大的、更复杂的 JavaScript 文件。这些大的文件通常被称为 chunk,可以被浏览器或其他 JavaScript 运行环境直接执行。

这背后的最大原因是:浏览器或其他 JavaScript 运行环境无法解析工程化下的模块

例如,你可能有一个项目,其中包含许多小的 JavaScript 模块文件,每个文件都执行一个特定的任务。使用 Rollup,你可以将这些小的模块文件打包成一个大的 JavaScript 文件,这样在浏览器或 Node.js 环境中就能够执行了。这样做既利用了工程化带来的收益,也让执行环境能正常工作了。

所以,当我们说 Rollup 可以 “将小块代码编译成大块复杂的代码” 时,其意思是它可以将许多小的、相互依赖的模块文件合并成一个大的、包含所有模块代码的文件。

2. 为什么 ESM 要比 CommonJS 要好呢?

好吧,其实这个问题与 Rollup 没有直接的关系,只是常问,也是一个需要了解的点。

ESM 是 JavaScript 工程化结构的官方标准,有着明确发展方向;而 CommonJS 可以说是历史遗留规范,在 ES 模块提出之前用作权宜之计,官方在正式出 ESM 之前,社区几乎都采用的是 CommonJS 规范。

ES 模块允许进行静态分析,这有助于进行诸如 tree-shaking 和作用域提升之类的优化,同时还提供循环引用和实时绑定之类的高级功能。

3. 什么是 tree-shaking ?

Tree-shaking,也被称为"live code inclusion",是 Rollup 用于剔除在项目中未被真正使用代码的一种处理方式。

live code inclusion: 仅包含活代码(有效的代码)

它是一种 死代码消除方式,但就输出大小而言,它比其他方法更有效。名称源自模块的抽象语法树,算法会首先标记所有相关的语句,然后 “摇动语法树” 以删除所有死代码。它的理念类似于标记和清除垃圾收集算法。尽管这个算法并不局限于 ESM,但是 ESM 让 Rollup 可以将所有模块一起视为一个大的并且具有共享绑定的抽象语法树,所以会使得这个算法更加高效。

4. 如何使用 Rollup 处理 CommonJS?

Rollup 致力于实现 ESM 规范,而不在 Node.js、NPM、require() 和 CommonJS 的行为,所以这些模块的加载并不包含在 Rollup 的核心中;但 Rollup 提供了灵活的插件机制,加载 CommonJS 和使用 Node 的模块位置解析逻辑都均可使用插件来实现,只需 npm install commonjs 和 node-resolve 插件,然后通过 rollup.config.js 文件启用它们,就应该可以开始使用了。除此之外,如果模块导入存在 JSON 文件,引入 json 插件即可。

import { nodeResolve } from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import json from '@rollup/plugin-json';export default {input: 'src/main.js',output: {file: 'bundle.js',format: 'cjs'},plugins: [nodeResolve(),commonjs(),json()]
};

5. 为什么 node-resolve 不是一个内置功能?

这主要有两个原因:

  • 从哲学角度来看,这是因为 Rollup 本质上是对 Node 和浏览器中的原生模块加载器的一种 polyfill。在浏览器中,import foo from 'foo' 是无法工作的,因为浏览器并不使用 Node 的解析算法,所以如果 Rollup 直接内置了 node-resolve 的话,这可能导致一些误解。

  • 从实际层面来看,如果一个问题能够通过良好的 API 或者插件进行分离,那么开发软件就会变得容易得多。Rollup 的核心相当大,那么任何任何让它变得更大的设计都需要慎重地权衡。保持 Rollup 的精简,不仅技术债务的可能小更小,修复错误和添加功能也会更容易。

请参阅这个 issue 以获取更详细的解释。

6. 为什么在进行代码分割时,入口块中会出现额外的导入?

默认情况下,当创建多个块时,入口块的依赖项的导入将作为空导入添加到入口块本身。例如:

// input
// main.js
import value from './other-entry.js';
console.log(value);// other-entry.js
import externalValue from 'external';
export default 2 * externalValue;// output
// main.js
import 'external'; // this import has been hoisted from other-entry.js
import value from './other-entry.js';
console.log(value);// other-entry.js
import externalValue from 'external';
var value = 2 * externalValue;
export default value;

实际上,这并不会影响代码执行的顺序或行为,但它会加快你的代码的加载和解析速度。没有这个优化,JavaScript 引擎需要执行以下步骤来运行 main.js

  1. 加载并解析 main.js。在最后,将发现 other-entry.js 的导入。
  2. 加载并解析 other-entry.js。在最后,将发现 external 的导入。
  3. 加载并解析 external
  4. 执行main.js。

有了这个优化,JavaScript 引擎在解析入口模块后将发现所有传递依赖项,避免了瀑布式加载:

  1. 加载并解析 main.js。在最后,将发现导入到 other-entry.jsexternal 的导入。
  2. 加载并解析 other-entry.jsexternal。从 other-entry.js 导入的 external 已经被加载和解析。
  3. 执行main.js。

可能有些情况下你不希望这种优化,这种情况下,你可以通过 output.hoistTransitiveImports 选项关闭它。当使用 output.preserveModules 选项时,也不会应用这种优化。

7. 如何将 polyfills 添加到 Rollup 包中?

尽管Rollup通常会在打包时尽量保持精确的模块执行顺序,但在两种情况下并非总是如此:代码分割和外部依赖。这个问题在外部依赖中最为明显,参见以下示例:

// main.js
import './polyfill.js';
import 'external';
console.log('main');// polyfill.js
console.log('polyfill');

可以看到,执行顺序是 polyfill.jsexternalmain.js。但如果你将其打包,你会得到:

import 'external';
console.log('polyfill');
console.log('main');

执行顺序会是 externalpolyfill.jsmain.js。哇,怎么回事对吧,这并非是 Rollup 将导入包语句 import 'external' 放在顶部导致的问题,因为无论导入语句位于文件的哪个位置,总是会首先执行的。

这个问题可以通过创建多个 chunk 来解决,比如如果 polyfill.js 最终在与_main.js_ 不同的 chunk 中,那么就会得到正确的执行顺序。然而,Rollup 还没有自动的方式来做到这一点。对于代码分割,情况也是类似,因为 Rollup 始终会试图创建尽可能少的 chunk

对于大多数代码来说,这不是问题,因为Rollup可以保证:如果模块 A 导入模块 B,并且没有循环导入的话,那么 B 总是在 A 之前执行的。

然而,对于 polyfills 来说,这将会是一个问题,因为它们通常需要先执行,但又不希望在每个模块中都放置一个 polyfills 的导入。幸运的是,这并不需要:

  • 如果所有的外部依赖均不依赖 polyfill,那么只需将 polyfill 导入作为每个静态入口点的第一个语句即可。
  • 否则,将 polyfill 作为单独的入口或手动块,就可以确保它始终先执行。

8. Rollup 是用来构建库还是应用程序?

Rollup 已经被许多的 JavaScript 库使用,当然也可以用来构建绝大多数应用程序。然而,如果你想在旧的浏览器上使用代码分割或动态导入,那可能需要一个额外的运行时来处理加载就浏览器缺失的一些 chunk。我们推荐使用 SystemJS Production Build,因为它很好地与 Rollup 格式的输出集成在一起,能够正确处理所有的 ESM 实时绑定和重新导出边缘情况。或者,你也可以使用 AMD 加载器。

9. Rollup 和 Webpack 有什么区别呢?

Rollup 和 Webpack 都是 JavaScript 模块打包器,但它们的关注点和使用场景有所不同:

  1. 设计理念:Rollup 更专注于 JavaScript 模块打包,特别是 ES6 模块,它的设计目标是提供更高效的代码打包和更好的代码优化(如tree-shaking)。而 Webpack 则是一个更通用的模块打包器,它不仅可以处理 JavaScript,还可以处理各种类型的资源,如 CSS、图片、字体等。
  2. 代码分割和动态导入:Webpack 对代码分割和动态导入的支持更为成熟,这使得 Webpack 在构建大型、复杂的前端应用程序时更为强大。而 Rollup 虽然也支持代码分割和动态导入,但可能需要更多的配置和插件。
  3. 输出格式:Rollup 支持更多的输出格式,包括ES模块、CommonJS、AMD、IIFE、UMD等,这使得 Rollup 更适合用于构建库。而Webpack 主要输出为自定义的模块格式,更适合构建应用程序。
  4. 开发服务器和热模块替换:Webpack 内置了开发服务器,并支持热模块替换(HMR),这对于开发环境非常有用。而Rollup则需要额外的插件或工具来提供这些功能。

上面所描述的点两者其实均可以做到,只是所侧重点不同。总的来说,Rollup和Webpack各有优势,选择哪一个取决于你的具体需求。

10. 如何在浏览器中运行 Rollup?

好吧,这个问题其实挺意外的,绝大部分情况都不会想在浏览器里面运行 Rollup 吧。

虽然常规的 Rollup 构建依赖于 Node 的一些特性,但 Rollup 也提供了一个用于在浏览器构建的版本,你可以通过以下方式安装它:

npm install @rollup/browser

在你的脚本中,通过以下方式导入它:

import { rollup } from '@rollup/browser';

或者,你可以从 CDN 导入,例如 ESM:

import * as rollup from 'https://unpkg.com/@rollup/browser/dist/es/rollup.browser.js';

UMD:

<script src="https://unpkg.com/@rollup/browser/dist/rollup.browser.js"></script>

这将创建一个全局变量 window.rollup。由于浏览器构建无法访问文件系统,因此需要提供解析和加载你想要打包的所有模块的插件。如下示例:

const modules = {'main.js': "import foo from 'foo.js'; console.log(foo);",'foo.js': 'export default 42;'
};rollup.rollup({input: 'main.js',plugins: [{name: 'loader',resolveId(source) {if (modules.hasOwnProperty(source)) {return source;}},load(id) {if (modules.hasOwnProperty(id)) {return modules[id];}}}]}).then(bundle => bundle.generate({ format: 'es' })).then(({ output }) => console.log(output[0].code));

这个例子支持了两个导入,main.jsfoo.js。下面这个例子是另一个使用绝对 URL 作为入口点并支持相对导入的例子。在这种情况下,我们只是重新打包 Rollup 本身,便可使它能用于任何其他 ESM 的URL:

rollup.rollup({input: 'https://unpkg.com/rollup/dist/es/rollup.js',plugins: [{name: 'url-resolver',resolveId(source, importer) {if (source[0] !== '.') {try {new URL(source);// If it is a valid URL, return itreturn source;} catch {// Otherwise make it externalreturn { id: source, external: true };}}return new URL(source, importer).href;},async load(id) {const response = await fetch(id);return response.text();}}]}).then(bundle => bundle.generate({ format: 'es' })).then(({ output }) => console.log(output));

写在最后

Rollup 在社区可以说一直是翘首,大量的库都在用 Rollup 打包,更不用说如今的红人 vite 了,更是以 Rollup 为底层。所以试着去了解一下也是蛮有价值的,当然,社区还有非常多的打包工具,包括 esbuild、tsup、gulp 等等。

不过万变不离其宗,其实打包工具底层基本都是一致的,只是可能在设计理念或者架构上有些差异,但始终绕不开这个范式,也很期待未来前端工程化发展能够有超越当前范式的模式和工具出现哇。

好吧,这是我从 LLM 学到,LLM 的出现就是 AI 在范式上的超越

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/27523.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何警用root用户登录ssh

使用tail指令&#xff0c;可以动态查看日志信息。 &#xff08;tail -f /var/log/secure或messages&#xff09; 使用>符号&#xff0c;可以清空日志内容&#xff0c;不删除文件本身。 禁用root用户为以下步骤&#xff1a; 首先使用useradd创建用户&#xff08;可以修改为其…

STM32HAL-最简单的时间片论法

目录 概述 一、开发环境 二、STM32CubeMx配置 三、编码 四、运行结果 五、总结 概述 本文章使用最简单的写法时间片论法框架,非常适合移植各类型单片机,特别是资源少的芯片上。接下来将在stm32单片机上实现,只需占用1个定时器作为tick即可。(按键框架+时间片论法)…

20240613每日前端--------聊聊根据面试简历面试的一位高级前端开发工程师

项目经验 封装了通用的表单组件&#xff0c;支持多表单结构&#xff0c;如&#xff1a;富文本编辑器、文件上传等封装了 Echarts 图表组件&#xff0c;可以展示各种报表数据封装了通用的表格组件&#xff0c;支持多条件搜索及分页功能封装了 svg 图标上传组件&#xff0c;将下…

【数据结构之B树的讲解】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

【乐吾乐2D可视化组态编辑器】开关、阀门、报警状态切换

开关状态 开关的断开与闭合&#xff1a;将电力组件的“开”与“关”2个组件重叠在一起&#xff0c;右键选择“组合为状态”&#xff0c;属性面板中就可以任意切换状态。 视频教程&#xff1a;开关阀门多状态控制 乐吾乐2D可视化组态编辑器地址&#xff1a;https://2d.le5le.co…

【python】python指南(三):使用正则表达式re提取文本中的http链接

一、引言 对于算法工程师来说&#xff0c;语言从来都不是关键&#xff0c;关键是快速学习以及解决问题的能力。大学的时候参加ACM/ICPC一直使用的是C语言&#xff0c;实习的时候做一个算法策略后台用的是php&#xff0c;毕业后做策略算法开发&#xff0c;因为要用spark&#x…

开发指南030-常用的工具网站

1、下载jdk https://mirrors.huaweicloud.com/java/jdk/ 2、在线解析二维码 http://cdn.malu.me/qrdecode/ 3、Properties和Yaml格式互转 https://www.toyaml.com/index.html 4、生成banner https://devops.datenkollektiv.de/banner.txt/index.html 5、二维码生成器 http…

js编程环境配置-vscode

1、安装Node.js 官网下载 选择适合你Windows系统架构&#xff08;32位或64位&#xff09;的安装包。windows系统选择“Windows Installer (.msi)”或“Windows Binary (.exe)”进行下载。 双击下载的.msi或.exe文件进行安装。 在cmd中输入node --version和npm --version&…

MySQL为root用户添加IP地址连接权限

需求 部署在本地的MySQL数据库&#xff0c;默认主机是localhost&#xff0c;这样局域网内的其他电脑就会连接不到&#xff0c;如果想要其他的电脑也可以访问的话&#xff0c;需要将主机名设置为本机IP。 解决方案 MySQL语句&#xff1a; GRANT ALL PRIVILEGES ON *.* TO 用户…

numpy数组transpose方法的基本原理

背景&#xff1a;记录一下numpy数组维度顺序操作 一、具体示例 transpose方法用于交换数组的轴&#xff0c;改变数组的维度顺序。方法的参数是一个代表新轴顺序的元组。 假设你有一个三维数组&#xff0c;其形状是 (a, b, c)&#xff0c;即有 a 个块&#xff0c;每个块中有 b…

2-4 基于matlab的洛伦兹系统分岔图实现

基于matlab的洛伦兹系统分岔图实现。通过2种方法&#xff0c;最大值法&#xff0c;庞加莱截面法进行输出分岔图。可直接运行。 2-4 洛伦兹系统分岔图 最大值法 - 小红书 (xiaohongshu.com)

前端常用排序算法

1.时间复杂度 n*n&#xff1a;冒泡排序、选择排序、插入排序nlogn&#xff1a;快速排序、归并排序、堆排序 2.冒泡排序 定义&#xff1a;每次都是相邻元素比较&#xff0c;第一个元素比第二个元素大则交换位置直到最后一个元素为最大&#xff0c;继续循环代码实现&#xff1…

圆锥曲线的分类

有一个圆锥 C C C&#xff0c;以及一个不过圆锥顶点的平面 Q Q Q。用解析几何证明&#xff1a;当平面平行于圆锥的轴时&#xff0c;交线是双曲线&#xff1b;当平面平行于圆锥的母线时&#xff0c;交线是抛物线&#xff1b;其它情况下&#xff0c;交线为椭圆&#xff08;包括圆…

Unity Maximum Allowed Timestep的说明

Maximum Allowed Timestep的说明 关于Maximum Allowed Timestep这个配置的说明&#xff0c;Unity有一份官方的说明。 Time-maximumDeltaTime - Unity 脚本 API 结合Unity的函数执行顺序&#xff0c;我们可以简单理解为&#xff1a; FixedUpdate在1次Update可能会执行N次&am…

如何平衡安全访问和办公效率?零信任安全×统一身份才是解决之道

在远程办公、混合办公、跨团队协作日益频繁的今天&#xff0c;企业的业务开展需要支持多种访问接入的需求和场景。如何平衡企业数据的安全访问和办公效率将成为挑战。 在业务的多种接入场景上&#xff0c;企业引入零信任&#xff08;Zero Trust&#xff0c;ZT&#xff09;产品…

ESP-IDF OTA升级过程中遇到的“esp_transport_read returned:-1 and errno:128”问题(4)

接前一篇文章:ESP-IDF OTA升级过程中遇到的“esp_transport_read returned:-1 and errno:128”问题(3) 上一回讲到,笔者准备第二天围绕信号强度展开进一步测试。实际上没等到第二天,笔者在当天下午下班时间(18点)以后就进行了相关测试(不过测试倒并不是完全针对于信号强…

手机是如何实现多个应用程序同时运行的?

想要理解这个问题&#xff0c;我们要先了解一下操作系统以及进程相关的知识&#xff1a; 操作系统的功能有很多&#xff0c; 例如&#xff1a; 进程管理&#xff08;Process Management&#xff09;&#xff1a; 功能&#xff1a;创建和终止进程&#xff0c;进程调度&#xf…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 连续区间和(100分) - 三语言AC题解(Python/Java/Cpp)

🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 📎在线评测链接 连续区间和(100分) 🌍 评测功能需要订阅专栏后私信联系清隆…

深入了解 Redis 五种类型命令与如何在 Java 中操作 Redis

Redis 是一个开源的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。Redis 支持五种主要的数据类型:字符串(string)、哈希(hash)、列表(list)、集合(sets)、有序集合(sorted sets)。下面我们将深入了解这五种类型的命令,并探讨如何在 Java 中操作…

Hive数仓——用户行为数据中的一些特定术语含义

目录 一、页面信息 用户行为分析 转化率优化 页面优化 个性化体验 营销策略制定 用户流量路径分析 二、动作记录 用户行为分析 转化率优化 个性化推荐 广告定向 A/B 测试 安全审计 三、曝光记录 用户行为分析 内容推荐 广告优化 转化率分析 用户分群…