前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Rollup打包基本概念及使用--vite

Rollup打包基本概念及使用--vite

原创
作者头像
江拥羡橙
发布于 2023-11-19 12:22:34
发布于 2023-11-19 12:22:34
74100
代码可运行
举报
文章被收录于专栏:前端二次元前端二次元
运行总次数:0
代码可运行

快速上手

首先让我们用npm init -y新建一个项目,然后安装 rollup 依赖:

代码语言:typescript
AI代码解释
复制
pnpm i rollup

接着新增 src/index.jssrc/util.jsrollup.config.js 三个文件,目录结构如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
.
├── package.json
├── pnpm-lock.yaml
├── rollup.config.js
└── src
    ├── index.js
    └── util.js

文件的内容分别如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// src/index.js
import { add } from "./util";
console.log(add(1, 2));

// src/util.js
export const add = (a, b) => a + b;

export const multi = (a, b) => a * b;
// rollup.config.js
// 以下注释是为了能使用 VSCode 的类型提示
/**
 * @type { import('rollup').RollupOptions }
 */
const buildOptions = {
  input: ["src/index.js"],
  output: {
    // 产物输出目录
    dir: "dist/es",
    // 产物格式
    format: "esm",
  },
};

export default buildOptions;

你可以在package.json中加入如下的构建脚本:

代码语言:json
AI代码解释
复制
{
  // rollup 打包命令,`-c` 表示使用配置文件中的配置
  "build": "rollup -c"
}

接着在终端执行一下npm run build,可以看到命令行

OK,现在你已经成功使用 Rollup 打出了第一份产物! 我们可以去 dist/es 目录查看一下产物的内容:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// dist/es/index.js
// 代码已经打包到一起
const add = (a, b) => a + b;

console.log(add(1, 2));

同时你也可以发现,util.js中的multi方法并没有被打包到产物中,这是因为 Rollup 具有天然的 Tree Shaking 功能,可以分析出未使用到的模块并自动擦除。

所谓 Tree Shaking(摇树),也是计算机编译原理中DCE(Dead Code Elimination,即消除无用代码) 技术的一种实现。由于 ES 模块依赖关系是确定的,和运行时状态无关。因此 Rollup 可以在编译阶段分析出依赖关系,对 AST 语法树中没有使用到的节点进行删除,从而实现 Tree Shaking。

常用配置解读

1. 多产物配置

在打包 JavaScript 类库的场景中,我们通常需要对外暴露出不同格式的产物供他人使用,不仅包括 ESM,也需要包括诸如CommonJSUMD等格式,保证良好的兼容性。那么,同一份入口文件,如何让 Rollup 给我们打包出不一样格式的产物呢?我们基于上述的配置文件来进行修改:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// rollup.config.js
/**
 * @type { import('rollup').RollupOptions }
 */
const buildOptions = {
  input: ["src/index.js"],
  // 将 output 改造成一个数组
  output: [
    {
      dir: "dist/es",
      format: "esm",
    },
    {
      dir: "dist/cjs",
      format: "cjs",
    },
  ],
};

export default buildOptions;

从代码中可以看到,我们将output属性配置成一个数组,数组中每个元素都是一个描述对象,决定了不同产物的输出行为。

2. 多入口配置

除了多产物配置,Rollup 中也支持多入口配置,而且通常情况下两者会被结合起来使用。接下来,就让我们继续改造之前的配置文件,将 input 设置为一个数组或者一个对象,如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
  input: ["src/index.js", "src/util.js"]
}
// 或者
{
  input: {
    index: "src/index.js",
    util: "src/util.js",
  },
}

通过执行npm run build可以发现,所有入口的不同格式产物已经成功输出

如果不同入口对应的打包配置不一样,我们也可以默认导出一个配置数组,如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// rollup.config.js
/**
 * @type { import('rollup').RollupOptions }
 */
const buildIndexOptions = {
  input: ["src/index.js"],
  output: [
    // 省略 output 配置
  ],
};

/**
 * @type { import('rollup').RollupOptions }
 */
const buildUtilOptions = {
  input: ["src/util.js"],
  output: [
    // 省略 output 配置
  ],
};

export default [buildIndexOptions, buildUtilOptions];

如果是比较复杂的打包场景(如 Vite 源码本身的打包),我们需要将项目的代码分成几个部分,用不同的 Rollup 配置分别打包,这种配置就很有用了。

3. 自定义output配置

刚才我们提到了input的使用,主要用来声明入口,可以配置成字符串、数组或者对象,使用比较简单。而output与之相对,用来配置输出的相关信息,常用的配置项如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
output: {
  // 产物输出目录
  dir: path.resolve(__dirname, 'dist'),
  // 以下三个配置项都可以使用这些占位符:
  // 1. [name]: 去除文件后缀后的文件名
  // 2. [hash]: 根据文件名和文件内容生成的 hash 值
  // 3. [format]: 产物模块格式,如 es、cjs
  // 4. [extname]: 产物后缀名(带`.`)
  // 入口模块的输出文件名
  entryFileNames: `[name].js`,
  // 非入口模块(如动态 import)的输出文件名
  chunkFileNames: 'chunk-[hash].js',
  // 静态资源文件输出文件名
  assetFileNames: 'assets/[name]-[hash][extname]',
  // 产物输出格式,包括`amd`、`cjs`、`es`、`iife`、`umd`、`system`
  format: 'cjs',
  // 是否生成 sourcemap 文件
  sourcemap: true,
  // 如果是打包出 iife/umd 格式,需要对外暴露出一个全局变量,通过 name 配置变量名
  name: 'MyBundle',
  // 全局变量声明
  globals: {
    // 项目中可以直接用`$`代替`jquery`
    jquery: '$'
  }
}

4. 依赖 external

对于某些第三方包,有时候我们不想让 Rollup 进行打包,也可以通过 external 进行外部化:

代码语言:typescript
AI代码解释
复制
{
  external: ['react', 'react-dom']
}

在 SSR 构建或者使用 ESM CDN 的场景中,这个配置将非常有用,具体细节我们会在高级应用这一章展开。

5. 接入插件能力

在 Rollup 的日常使用中,我们难免会遇到一些 Rollup 本身不支持的场景,比如兼容 CommonJS 打包注入环境变量配置路径别名压缩产物代码 等等。这个时候就需要我们引入相应的 Rollup 插件了。接下来以一个具体的场景为例带大家熟悉一下 Rollup 插件的使用。

虽然 Rollup 能够打包输出CommonJS 格式的产物,但对于输入给 Rollup 的代码并不支持 CommonJS,仅仅支持 ESM。你可能会说,那我们直接在项目中统一使用 ESM 规范就可以了啊,这有什么问题呢?需要注意的是,我们不光要考虑项目本身的代码,还要考虑第三方依赖。目前为止,还是有不少第三方依赖只有 CommonJS 格式产物而并未提供 ESM 产物,比如项目中用到 lodash 时,打包项目会出现这样的报错

因此,我们需要引入额外的插件去解决这个问题。

首先需要安装两个核心的插件包:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
pnpm i @rollup/plugin-node-resolve @rollup/plugin-commonjs 
  • @rollup/plugin-node-resolve是为了允许我们加载第三方依赖,否则像import React from 'react' 的依赖导入语句将不会被 Rollup 识别。
  • @rollup/plugin-commonjs 的作用是将 CommonJS 格式的代码转换为 ESM 格式

然后让我们在配置文件中导入这些插件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// rollup.config.js
import resolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";

/**
 * @type { import('rollup').RollupOptions }
 */
export default {
  input: ["src/index.js"],
  output: [
    {
      dir: "dist/es",
      format: "esm",
    },
    {
      dir: "dist/cjs",
      format: "cjs",
    },
  ],
  // 通过 plugins 参数添加插件
  plugins: [resolve(), commonjs()],
};

现在我们以lodash这个只有 CommonJS 产物的第三方包为例测试一下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
pnpm i lodash

src/index.js 加入如下的代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import { merge } from "lodash";
console.log(merge);

然后执行 npm run build,你可以发现产物已经正常生成了

在 Rollup 配置文件中,plugins除了可以与 output 配置在同一级,也可以配置在 output 参数里面,如:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// rollup.config.js
import { terser } from 'rollup-plugin-terser'
import resolve from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";

export default {
  output: {
    // 加入 terser 插件,用来压缩代码
    plugins: [terser()]
  },
  plugins: [resolve(), commonjs()]
}

当然,你可以将上述的 terser 插件放到最外层的 plugins 配置中。

需要注意的是,output.plugins中配置的插件是有一定限制的,只有使用Output 阶段相关钩子(具体内容将在下一节展开)的插件才能够放到这个配置中,大家可以去这个站点查看 Rollup 的 Output 插件列表。

另外,这里也给大家分享其它一些比较常用的 Rollup 插件库:

JavaScript API 方式调用

以上我们通过Rollup的配置文件结合rollup -c完成了 Rollup 的打包过程,但有些场景下我们需要基于 Rollup 定制一些打包过程,配置文件就不够灵活了,这时候我们需要用到对应 JavaScript API 来调用 Rollup,主要分为rollup.rolluprollup.watch两个 API,接下来我们以具体的例子来学习一下。

首先是 rollup.rollup,用来一次性地进行 Rollup 打包,你可以新建build.js,内容如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// build.js
const rollup = require("rollup");

// 常用 inputOptions 配置
const inputOptions = {
  input: "./src/index.js",
  external: [],
  plugins:[]
};

const outputOptionsList = [
  // 常用 outputOptions 配置
  {
    dir: 'dist/es',
    entryFileNames: `[name].[hash].js`,
    chunkFileNames: 'chunk-[hash].js',
    assetFileNames: 'assets/[name]-[hash][extname]',
    format: 'es',
    sourcemap: true,
    globals: {
      lodash: '_'
    }
  }
  // 省略其它的输出配置
];

async function build() {
  let bundle;
  let buildFailed = false;
  try {
    // 1. 调用 rollup.rollup 生成 bundle 对象
    bundle = await rollup.rollup(inputOptions);
    for (const outputOptions of outputOptionsList) {
      // 2. 拿到 bundle 对象,根据每一份输出配置,调用 generate 和 write 方法分别生成和写入产物
      const { output } = await bundle.generate(outputOptions);
      await bundle.write(outputOptions);
    }
  } catch (error) {
    buildFailed = true;
    console.error(error);
  }
  if (bundle) {
    // 最后调用 bundle.close 方法结束打包
    await bundle.close();
  }
  process.exit(buildFailed ? 1 : 0);
}

build();

主要的执行步骤如下:

    1. 通过 rollup.rollup方法,传入 inputOptions,生成 bundle 对象;
    1. 调用 bundle 对象的 generate 和 write 方法,传入outputOptions,分别完成产物和生成和磁盘写入。
    1. 调用 bundle 对象的 close 方法来结束打包。

接着你可以执行node build.js,这样,我们就可以完成了以编程的方式来调用 Rollup 打包的过程。

除了通过rollup.rollup完成一次性打包,我们也可以通过rollup.watch来完成watch模式下的打包,即每次源文件变动后自动进行重新打包。你可以新建watch.js文件,内容入下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// watch.js
const rollup = require("rollup");

const watcher = rollup.watch({
  // 和 rollup 配置文件中的属性基本一致,只不过多了`watch`配置
  input: "./src/index.js",
  output: [
    {
      dir: "dist/es",
      format: "esm",
    },
    {
      dir: "dist/cjs",
      format: "cjs",
    },
  ],
  watch: {
    exclude: ["node_modules/**"],
    include: ["src/**"],
  },
});

// 监听 watch 各种事件
watcher.on("restart", () => {
  console.log("重新构建...");
});

watcher.on("change", (id) => {
  console.log("发生变动的模块id: ", id);
});

watcher.on("event", (e) => {
  if (e.code === "BUNDLE_END") {
    console.log("打包信息:", e);
  }
});

现在你可以通过执行node watch.js开启 Rollup 的 watch 打包模式,当你改动一个文件后可以看到如下的日志,说明 Rollup 自动进行了重新打包,并触发相应的事件回调函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
发生生变动的模块id: /xxx/src/index.js
重新构建...
打包信息: {
  code: 'BUNDLE_END',
  duration: 10,
  input: './src/index.js',
  output: [
    // 输出产物路径
  ],
  result: {
    cache: { /* 产物具体信息 */ },
    close: [AsyncFunction: close],
    closed: false,
    generate: [AsyncFunction: generate],
    watchFiles: [
      // 监听文件列表
    ],
    write: [AsyncFunction: write]
  }
}

基于如上的两个 JavaScript API 我们可以很方便地在代码中调用 Rollup 的打包流程,相比于配置文件有了更多的操作空间,你可以在代码中通过这些 API 对 Rollup 打包过程进行定制,甚至是二次开发。

我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
纯CSS实现iOS风格打开关闭选择框
在html中,<label>标签通常和<input>标签一起使用,<label>标签为input元素定义标注(标记)。label 元素不会向用户呈现任何特殊效果,<label>标签的作用是为鼠标用户改进了可用性,当用户点击<label>标签中的内容时,浏览器就会自动将焦点转到和该标签相关联的控件上;<label>标签在单选按钮和复选按钮上经常被使用,使用该标签后,你点击label标签内的内容,也可以选中对应的单选按钮或复选按钮。
AlbertYang
2020/09/08
1.1K0
纯CSS实现iOS风格打开关闭选择框
使用HTML和CSS编写无JavaScript的Todo应用
本文介绍了一个使用HTML、CSS和JavaScript实现的无JavaScript的Todo应用。通过使用CSS的伪类选择器,可以实现添加、删除、编辑和标记任务的功能。同时,通过存储和访问数据,可以在不依赖JavaScript的情况下进行实时更新。
IMWeb前端团队
2017/12/29
3.8K0
使用HTML和CSS编写无JavaScript的Todo应用
使用 CSS Checkbox Hack 技术制作一个手风琴组件
在本篇文章里,我们一起学习下如何使用 CSS checkbox hack 技巧制作一个响应式的手风琴组件,这个组件完全基于CSS,没有JavaScript脚本,基于窗口大小进行水平和垂直之间进行切换。为了让大家更好理解,我将和大家一起一步步的进行完成。
前端达人
2019/12/23
5.5K0
使用 CSS Checkbox Hack 技术制作一个手风琴组件
CSS(CSS3)选择器(2)
该部分主要为CSS3新增的选择器 接上一篇 CSS(CSS3)选择器(1) 一.通用兄弟选择器:                         24:E ~ F,匹配任何E元素之后的同级F元素。 div ~ p{ background-color:#00FF00; } 二.属性选择器:                         25:E[att ^= val],匹配属性att的值以”val“开头的元素。 [id ^= start]{ background-color:red; ]
zaking
2018/05/02
1K0
css3实战汇总(附源码)
利用css3的新特性可以帮助我们实现各种意想不到的特效,接下来的几个案例我们来使用css3的box-shdow来实现,马上开始吧!
徐小夕
2019/09/25
7660
css3实战汇总(附源码)
CSS设置复选框和开关的样式
我可能不是唯一一个对浏览器的默认设置感到沮丧的开发人员<input type="checkbox">。
哈德森sir
2024/05/16
7030
CSS设置复选框和开关的样式
分享15个高级前端开发小技巧
我们将提供真实世界的示例,并将它们与旧的基于 JavaScript 的方法进行比较,展示现代 Web 技术的力量。
前端达人
2024/03/25
4240
分享15个高级前端开发小技巧
Imooc之Html与CSS
1、ID选择器只能在文档中使用一次。与类选择器不同,在一个HTML文档中,ID选择器只能使用一次,而且仅一次。而类选择器可以使用多次。
ZHaos
2019/02/27
6.9K0
【Java 进阶篇】JQuery 案例:全选全不选,为选择添彩
在前端的舞台上,用户交互是一场精彩的表演,而全选全不选的功能则是其中一段引人入胜的剧情。通过巧妙运用 JQuery,我们可以为用户提供便捷的全选和全不选操作,让页面更富交互性。本篇博客将深入探讨 JQuery 中全选全不选的实现原理和实际应用,为你揭开这段前端小剧场的神秘面纱。
繁依Fanyi
2023/11/15
4360
【Java 进阶篇】JQuery 案例:全选全不选,为选择添彩
如何使用纯 CSS 制作四子连珠游戏
实验是学习新技巧、思考新想法、并突破自身极限的有趣的方式。“纯 CSS”演示很早就有了,但是随着浏览器和CSS的发展,新的挑战又出现了。CSS 和 HTML 预处理器也促进了纯 CSS 演示的发展。有时候,预处理程序用于硬编码每个可能的场景,比如 :checked 的长字符串和相邻兄弟选择器。
叙帝利
2018/09/28
2K0
如何使用纯 CSS 制作四子连珠游戏
iOS开关按钮,纯CSS给你安排上了
今早搭完电梯出来信号不太好,切换飞行模式重启信号,发现iOS的「开关按钮」挺好玩的,顺便用纯CSS实现一番。
JowayYoung
2020/09/18
1.8K0
学习jQuery?这篇文章就够了
jQuery 使用户能更方便地处理 HTML(标准通用标记语言下的一个应用)、events、实现动画效果,并且方便地为网站提供 AJAX 交互。 jQuery 的语法设计可以使开发者更加便捷,例如操作文档对象、选择 DOM 元素、制作动画效果、事件处理、使用 AJAX 以及其他功能。
上分如喝水
2021/08/16
12.4K0
使用 CSS Checkbox Hack 技术纯手工撸一个手风琴组件
在本篇文章里,我们将一起学习下如何使用 CSS checkbox hack 技术纯手工撸一个响应式的手风琴组件,这个组件完全基于CSS,没有JavaScript脚本,同时又基于窗口大小进行水平和垂直之间进行样式切换。为了让大家更好理解本案例,我将和大家一起一步步的完成。
前端达人
2019/12/25
3.3K0
使用 CSS Checkbox Hack 技术纯手工撸一个手风琴组件
CSS3新特性应用之用户体验
一、光标 新增加not-allowed光标,不允许访问 隐藏光标,在触模应用上很有用,css2.1需要一个透明的图片来实现,而css3直接用cursor:none即可。 完整代码: curosr: url(transparent.gif'); cursor: none; 二、扩大热区 应用在小按钮的情况下,不好被鼠标点击到 代码如下: .btn{ position: relative; cursor: pointer; } .btn:after{ position: absolute
sam dragon
2018/01/17
8550
从0开始编写一个开关组件
开关按钮似乎是开发人员和设计师最喜欢的展示他们的动画、设计和双关语技能的方式。甚至还有一个专门用于开关按钮的Codepen集合。
coder_koala
2020/08/27
2.5K0
从0开始编写一个开关组件
【QT】QT界面的美容院 -- QSS
🔥 在网页前端开发领域中,CSS 是一个至关重要的部分,描述了一个网页的 “样式”,从而起到对网页 美化 的作用。
IsLand1314
2025/04/15
2570
【QT】QT界面的美容院 -- QSS
纯CSS改写radio和checkbox,单选框、复选框样式优化
CSS: 将单选框或者复选框隐藏,在其后面写一个 span 利用 CSS 的相邻兄弟选择器  input + span 选中它,对它的样式进行美化。
德顺
2019/11/13
5.5K0
纯CSS改写radio和checkbox,单选框、复选框样式优化
动手练一练,用纯 CSS 制作一款侧滑显示留言面板的网页组件
大家好,不知道你们是否和我一样存在这样的困惑呢,虽然css入门容易,但是其内容太多,好多属性看了似是而非,觉得自己看懂了,到自己用的时候又很犯难了,看到漂亮的效果还是无从下手,这主要还是自己对新属性实践太少了,不能进行灵活应用,CSS总让一些人找不到感觉。其实学好CSS真的没有太多捷径,和JS编程一样,要重视对待,要多看和多练,因为现在的CSS不再是以前的CSS啦。
前端达人
2020/02/18
1.1K0
动手练一练,用纯 CSS 制作一款侧滑显示留言面板的网页组件
前端之form表单与css(1)
form表单用于用户界面向服务器传输数据,实现用户和web服务器的交互。表单包含input系列标签如文本字段、复选框、单选框、提交按钮等。
GH
2019/12/16
2K0
前端之form表单与css(1)
Vue表单输入绑定
  表单控件的数据绑定就是用v-model指令实现的,它会根据控件类型自动选取正确的方法更新元素。由于表单控件有不同的类型,如文本输入框、复选框、单选按钮、选择框等,v-model指令在不同的表单控件上应用时也会有所差异。
别团等shy哥发育
2023/02/25
7.6K0
Vue表单输入绑定
推荐阅读
相关推荐
纯CSS实现iOS风格打开关闭选择框
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档