【实战篇】最详细的Rollup打包项目教程

news2025/1/25 7:02:42

介绍

本文带你一起使用 Rollup 打包项目,实现以下功能:

  • 自动将 dependencies 依赖声明为 externals
  • 支持处理外部 npm 依赖
  • 支持基于 CommonJS 模块引入
  • 支持 typescript,并导出声明文件
  • 支持 scss,并添加前缀
  • 支持自动清除调试代码
  • 打包输出文件保留原始模块结构
  • 支持按需加载

一、什么是 rollup

rollup 是一个 JavaScript 模块打包器,可以将小块代码编译成大块复杂的代码,例如 library 或应用程序。

二、为什么是 rollup

为什么是 rollup 而不是 webpack 呢?

rollup的特色是 ES6 模块和代码 Tree-shaking,这些 webpack 同样支持,除此之外 webpack 还支持热模块替换、代码分割、静态资源导入等更多功能。

当开发应用时当然优先选择的是 webpack,但是若你项目只需要打包出一个简单的 bundle 包,并是基于 ES6 模块开发的,可以考虑使用 rollup

rollup 相比 webpack,它更少的功能和更简单的 api,是我们在打包类库时选择它的原因。

三、支持打包的文件格式

rollup 支持的打包文件的格式有 amd, cjs, es\esm, iife, umd。其中,amd 为 AMD 标准,cjs 为 CommonJS 标准,esm\es 为 ES 模块标准,iife 为立即调用函数, umd 同时支持 amd、cjs 和 iife。

四、快速开始

1. 安装

npm install --global rollup 

2. 基础打包

新增文件 src/main.js

// src/main.js
import foo from "./foo.js";
export default function () {console.log(foo);
} 

新增文件 src/foo.js

export default "hello world!"; 

项目根目录下新增文件 rollup.config.js

export default {input: "src/main.js",output: {file: "bundle.js",format: "cjs",},
}; 

运行命令:

rollup -c 

得到产物 bundle.js

"use strict";

var foo = "hello world!";

// src/main.js
function main() {console.log(foo);
}

module.exports = main; 

这时我们使用 Rollup 将 src/main.jssrc/foo.js打包成功,完成了第一个 bundle,。

3. 引入外部资源

更新 src/main.js,添加外部资源 lodash-es 引入:

// src/main.js
import foo from "./foo.js";

import { sum } from "lodash-es";

export default function () {console.log(foo);console.log(sum[(1, 2)]);
} 

再次打包 rollup -c,发现有报错 (!) Unresolved dependencies

这是因为当项目中引入外部资源时,如 npm 包,rollup 不知道如何打破常规去处理这些依赖。

有 2 种方法引入外部资源:

  • 添加插件 @rollup/plugin-node-resolve 将我们编写的源码与依赖的第三方库进行合并;
  • 配置 external 属性,告诉 rollup.js 哪些是外部的类库。

3.1 resolve 插件

@rollup/plugin-node-resolve 插件让 rollup 能够处理外部依赖。

安装:

yarn add @rollup/plugin-node-resolve -D 

更新 rollup.config.js

import resolve from "@rollup/plugin-node-resolve";
export default {plugins: [resolve()],
}; 

重新打包得到产物,已经包含了 lodash-es

"use strict";

var foo = "hello world!";

/**
 * This method returns the first argument it receives.
 *
 * @static
 * @since 0.1.0
 * @memberOf _
 * @category Util
 * @param {*} value Any value.
 * @returns {*} Returns `value`.
 * @example
 *
 * var object = { 'a': 1 };
 *
 * console.log(_.identity(object) === object);
 * // => true
 */
function identity(value) {return value;
}

/**
 * The base implementation of `_.sum` and `_.sumBy` without support for
 * iteratee shorthands.
 *
 * @private
 * @param {Array} array The array to iterate over.
 * @param {Function} iteratee The function invoked per iteration.
 * @returns {number} Returns the sum.
 */
function baseSum(array, iteratee) {var result,index = -1,length = array.length;while (++index < length) {var current = iteratee(array[index]);if (current !== undefined) {result = result === undefined ? current : result + current;}}return result;
}

/**
 * Computes the sum of the values in `array`.
 *
 * @static
 * @memberOf _
 * @since 3.4.0
 * @category Math
 * @param {Array} array The array to iterate over.
 * @returns {number} Returns the sum.
 * @example
 *
 * _.sum([4, 2, 8, 6]);
 * // => 20
 */
function sum(array) {return array && array.length ? baseSum(array, identity) : 0;
}

// src/main.js

function main() {console.log(foo);console.log(sum([1, 2]));
}

module.exports = main; 

成功运行:

3.2 external 属性

有些场景下,虽然我们使用了 resolve 插件,但可能我们仍然想要某些库保持外部引用状态,这时我们就需要使用 external 属性,来告诉 rollup.js 哪些是外部的类库。

更新 rollup.config.js

import commonjs from "@rollup/plugin-commonjs";
import { nodeResolve } from "@rollup/plugin-node-resolve";

export default {input: "src/main.js",output: {file: "bundle.js",format: "esm",name: "test",},plugins: [nodeResolve(), commonjs()],external: ["react"],
}; 

3.3 external 插件

每个类库都要手动添加至 externals 未免太麻烦,这时候可以用 rollup-plugin-node-externals 插件,自动将外部类库声明为 externals。

安装:

yarn add rollup-plugin-node-externals -D 

更新 rollup.config.js

import externals from "rollup-plugin-node-externals";

export default [{plugins: [externals({devDeps: false, // devDependencies 类型的依赖就不用加到 externals 了。}),],},
]; 

4. 引入 CommonJs 模块

4.1 CommonJs 插件

rollup.js 编译源码中的模块引用默认只支持 ES6+的模块方式 import/export。然而大量的 npm 模块是基于 CommonJS 模块方式,这就导致了大量 npm 模块不能直接编译使用。

需要添加 @rollup/plugin-commonjs 插件来支持基于 CommonJS 模块方式 npm 包。

安装:

yarn add @rollup/plugin-commonjs -D 

更新 rollup.config.js:

import commonjs from "@rollup/plugin-commonjs";

export default {plugins: [commonjs()],
}; 

更新 src/foo.js:

module.exports = {text: "hello world!",
}; 

重新打包,打包成功:

5. 引入 Sass 资源

rollup-plugin-postcss 默认集成了对 scss、less、stylus 的支持。

5.1 打包支持 sass 文件

新增 src/foo.scss

body {background-color: red;display: flex;
} 

更新 src/main.js

// src/main.js
import foo from "./foo.js";
import "./foo.scss";

export default function () {console.log(foo.text);
} 

安装:

yarn add rollup-plugin-postcss -D 

更新 rollup.config.js:

import commonjs from "@rollup/plugin-commonjs";
import { nodeResolve } from "@rollup/plugin-node-resolve";
import postcss from "rollup-plugin-postcss";

export default {input: "src/main.js",output: {file: "bundle.js",format: "esm",name: "test",},plugins: [nodeResolve(), commonjs(), postcss()],external: ["react"],
}; 

打包产物:

"use strict";

var foo = {text: "hello world!",
};

function styleInject(css, ref) {if (ref === void 0) ref = {};var insertAt = ref.insertAt;if (!css || typeof document === "undefined") {return;}var head = document.head || document.getElementsByTagName("head")[0];var style = document.createElement("style");style.type = "text/css";if (insertAt === "top") {if (head.firstChild) {head.insertBefore(style, head.firstChild);} else {head.appendChild(style);}} else {head.appendChild(style);}if (style.styleSheet) {style.styleSheet.cssText = css;} else {style.appendChild(document.createTextNode(css));}
}

var css_248z = "body {\nbackground-color: red;\n}";
styleInject(css_248z);

// src/main.js

function main() {console.log(foo.text);
}

module.exports = main; 

效果如图:

5.2 css 加前缀

安装:

yarn add autoprefixer -D 

更新 packages.json:

 "browserslist": ["defaults","not ie < 8","last 2 versions","> 1%","iOS 7","last 3 iOS versions"] 

更新 rollup.config.js:

import commonjs from "@rollup/plugin-commonjs";
import { nodeResolve } from "@rollup/plugin-node-resolve";
import autoprefixer from "autoprefixer";
import postcss from "rollup-plugin-postcss";

export default {input: "src/main.js",output: {file: "bundle.js",format: "umd",name: "test",},plugins: [nodeResolve(),commonjs(),postcss({plugins: [autoprefixer()],}),],external: ["react"],
}; 

效果如图:

5.3 css 压缩

安装:

yarn add cssnano -D 

更新 rollup.config.js:

import commonjs from "@rollup/plugin-commonjs";
import { nodeResolve } from "@rollup/plugin-node-resolve";
import autoprefixer from "autoprefixer";
import cssnano from "cssnano";
import postcss from "rollup-plugin-postcss";

export default {input: "src/main.js",output: {file: "bundle.js",format: "umd",name: "test",},plugins: [nodeResolve(),commonjs(),postcss({plugins: [autoprefixer(), cssnano()],}),],external: ["react"],
}; 

效果如图:

5.4 抽离单独的 css 文件

更新 rollup.config.js

export default [{plugins: [postcss({plugins: [autoprefixer(), cssnano()],extract: "css/index.css",}),],},
]; 

效果如图:

6. 引入 Typescript 资源

6.1 typescript 插件

修改 src/foo.js -> src/foo.ts

export default {text: "hello world!",
}; 

更新 src/main.js

// src/main.js
import foo from "./foo.ts";
import "./foo.scss";

export default function () {console.log(foo.text);
} 

安装:

yarn add @rollup/plugin-typescript -D 

更新 rollup.config.js:

import typescript from "@rollup/plugin-typescript";
export default [{plugins: [typescript()];}
]; 

成功支持 Ts 文件导出:

6.2 导出类型声明文件

更新 rollup.config.js:

import typescript from "@rollup/plugin-typescript";
export default [{plugins: [typescript({outDir: "dist",declaration: true,declarationDir: "dist",})];}
]; 

成功支持类型声明文件导出:

7. 打包产物清除调试代码

插件 @rollup/plugin-strip 用于从代码中删除 debugger 语句和函数。包括 assert.equal、console.log 等等。

安装:

yarn add @rollup/plugin-strip -D 

更新 rollup.config.js:

import strip from "@rollup/plugin-strip";
export default [{plugins: [strip()];}
]; 

8. 打包输出文件保留原始模块结构

上面我们的 output 配置是这样的:

output: {dir: path.dirname('dist/bundle.js'),format: 'es',} 

打包产物如下:

那么怎么才能把 index.js、index2.js 改成 foo/index.js、hello/index.js 呢?

修改 output,更新 rollup.config.js:

output: {dir: path.dirname('dist/bundle.js'),format: 'es',exports: 'named', // 指定导出模式(自动、默认、命名、无)preserveModules: true, // 保留模块结构preserveModulesRoot: 'src', // 将保留的模块放在根级别的此路径下}, 

这时打包产物就和源码的结构一致了:

9. 按需加载

rollup 支持输出格式为 es 模块化,就会按模块输出。

所以我们上面的配置已经实现了按需加载了。

五、一个真实的组件库的 rollup 打包配置

项目地址:github.com/jiaozitang/…

该项目支持:

  • 打包输出文件保留原始模块结构
  • 自动将 dependencies 依赖声明为 externals
  • 支持处理外部 npm 依赖
  • 支持基于 CommonJS 模块引入
  • 支持 typescript,并导出声明文件
  • 支持 scss,并添加前缀
  • 支持自动清除调试代码
  • 支持按需加载

1. 安装

npm i rollup -g

yarn add @rollup/plugin-commonjs @rollup/plugin-node-resolve @rollup/plugin-strip @rollup/plugin-typescript rollup-plugin-postcss rollup-plugin-node-externals autoprefixer -D 

2. 配置

项目根目录下新增 rollup.config.js

import commonjs from "@rollup/plugin-commonjs";
import resolve from "@rollup/plugin-node-resolve";
import strip from "@rollup/plugin-strip";
import typescript from "@rollup/plugin-typescript";
import autoprefixer from "autoprefixer";
import path from "path";
import externals from "rollup-plugin-node-externals";
import postcss from "rollup-plugin-postcss";

import pkg from "./package.json";

export default [{input: "./src/index.ts", // 入口文件output: [{// 出口文件dir: path.dirname(pkg.module),format: "es", // es模块导出,支持按需加载name: pkg.name,exports: "named", // 指定导出模式(自动、默认、命名、无)preserveModules: true, // 保留模块结构preserveModulesRoot: "src", // 将保留的模块放在根级别的此路径下},],plugins: [// 自动将dependencies依赖声明为 externalsexternals({devDeps: false,}),// 处理外部依赖resolve(),// 支持基于 CommonJS 模块引入commonjs(),// 支持 typescript,并导出声明文件typescript({outDir: "es",declaration: true,declarationDir: "es",}),// 支持 scss,并添加前缀postcss({plugins: [autoprefixer()],}),// 清除调试代码strip(),],},
]; 

更新 packages.json:

{"module": "es/index.js","types": "es/index.d.ts","files": ["es"]
} 

项目结构:

打包产物:

小结

本文介绍了 rollup 的各个功能的使用方法,rollup 自身能力较弱,依靠插件完成完整的组件库打包。

可以直接拷贝文中配置,实现一个按需加载的组件库打包。

项目地址:github.com/jiaozitang/…

希望能对你有所帮助,感谢阅读~

最后

最近找到一个VUE的文档,它将VUE的各个知识点进行了总结,整理成了《Vue 开发必须知道的36个技巧》。内容比较详实,对各个知识点的讲解也十分到位。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

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

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

相关文章

怒肝最新保姆级前端学习路线,速成贴心全面!

这份学习路线并不完美&#xff0c;也不会有最终形态&#xff0c;正如前端不可预见、永无止境的未来。 大家好&#xff0c;我是鱼皮&#xff0c;肝了几天终于完成了这份保姆级前端学习路线。 &#x1f482; &#x1f4bb; &#x1f474;&#x1f3fd; 先放一张图&#xff1a…

JS原型与原型链详细解释

文章目录一、JS原型链简要解释二、JS原型链详细解释1.构造函数2.原型对象3.__proto__4.原型链总结一、JS原型链简要解释 原型是function对象上的一个属性, 它表示构造函数构造出来的对象的共有祖先, 被通过构造函数构造出来的对象上有一个__proto__属性指向该函数的prototype,…

JSON.parse和JSON.stringify的用法

平时我们在接收后端返回的json对象通常是一个字符串类型的object&#xff0c;所以一般我们要对这个object进行类型转化后&#xff0c;我们才能使用object里面的数据&#xff0c;而这其中涉及到两个必不可少的方法就是JSON.parse和JSON.stringify JSON.parse()JSON.parse()方法将…

vue 控制元素的显示和隐藏

方法&#xff1a; 使用 v-if 指令&#xff0c;通过动态的向DOM树内添加或者删除DOM元素的方式来显示或隐藏元素&#xff1b;使用 v-show 指令&#xff0c;通过设置DOM元素的display样式属性来控制显隐。v-if 指令与 v-show 指令都可以根据值动态控制DOM元素显示隐藏&#xff0…

文档库开发之-vite打包优化

背景 首次进行组件库文档打包&#xff0c;遇到了一些ts打包报错和css打包警告&#xff0c;记录下处理过程。并且发现打包后的主包的体积过大&#xff0c;有一定优化空间 ts报错处理 当时有好奇为什么开发环境下都不报错&#xff0c;构建才产生这么多ts错误。大致猜想可能vite…

英雄联盟轮播图自动轮播

六月过去了&#xff0c;七月还会远吗&#xff1f;不知不觉到了六月底的最后一天。你好&#xff0c;七月&#xff01; 大家好&#xff0c;我是小陈陈呀&#xff0c;上次写了一篇英雄联盟轮播图手动轮播&#xff0c;当天晚上有很多大朋友小朋友私信小陈陈&#xff1a;可以在上次…

【微信小程序】一文读懂页面导航

&#x1f381;写在前面&#xff1a; 观众老爷们好呀&#xff0c;这里是前端小刘不怕牛牛频道&#xff0c;小程序系列又更新了呀&#xff0c;今天的内容是微信小程序的页面导航&#xff0c;非常重要&#xff0c;赶紧拿起小本本记起来呀&#xff01; 文章目录一&#xff0c;页面导…

【项目问题定位】前端请求不到资源报错ERR_CONTENT_LENGTH_MISMATCH的解决

文章目录问题简述问题背景问题定位初始报错定位好像是网络问题ERR_CONTENT_LENGTH_MISMATCH 200 是什么原因&#xff1f;原来是Nginx报错了为何没有权限&#xff1f;nobody的原因问题解决原因总结知识点问题简述 前端页面加载资源时&#xff0c;出现ERR_CONTENT_LENGTH_MISMAT…

前端异常:“Uncaught SyntaxError: missing ) after argument list“真的只是参数列表后面缺少 “)”?

案发现场 我们在写JS的时候&#xff0c;有时候报错"Uncaught SyntaxError: missing ) after argument list"&#xff0c;字面翻译过来的意思&#xff1a;语法错误: 参数列表后面缺少 )。 这真的就是缺少括号的意思吗&#xff1f;然而只是真的缺少括号才会出现这样的…

HTML的常见标签及用法

一、注释标签 形如&#xff1a;<!-- -->的格式就叫做注释标签&#xff0c;在代码中起到解释说明的作用。 二、标题标签 在HTML中有六种格式的标题标签类型&#xff0c;分别是h1,h2,h3,h4,h5,h6。对应的形式为&#xff1a; 三、段落标签 当文章需要分段时&#xff0c;使…

js除法取整(js除法向上取整)

Javascript取整问题。要求只要有小数存在就进一位。例如&#xff1a;2.1取3&#xff0c;3.1取4 var a 2.0; function parseNumber(number, splitChar) { var n number ; var s splitChar nullvar a 2.1; var b parseInt(a) 1; // b will be 3 parseInt是截掉尾数&#…

vxe-table表格合并单元格和编辑

//这是在vue上面引用vxe-table插件实现的&#xff0c;主要方法都设置在table中&#xff0c;mergeCells&#xff0c;tableData都是在vue页面的data初使化数据&#xff0c; :footer-method“footerMethod”&#xff1a;尾部数据&#xff0c;:merge-footer-items“mergeCells”&am…

vue通过url方式展示PDF方法总结

最近vue项目中遇到预览pdf出现乱码问题&#xff0c;尝试了各种办法受尽折磨&#xff0c;以此记录一下使用的几种方法 1.使用pdfjs-dist 插件&#xff0c;通过iframe标签显示 首先 npm install pdfjs-dist --save npm直接下载插件 npm install --save pdfjs-dist2.0.943&…

【vue 项目】有关cascader任选一级、字段名不同、同时获取value和label值、回显(推父节点)等问题解决

文章目录选择任意一级选项字段名转换最后一级数据为空显示暂无数据问题同时获取cascader的value和label值选择时双击两次才显示被选中&#xff08;单选选择任意一级组件&#xff09;Error in callback for watcher “options“: “TypeError: Cannot read property ‘level‘ o…

表单元素盘点第二弹<form><textarea>元素详细介绍

博主有话说&#xff1a;如果有描述错误之处请大家纠正。让我们可以一起学习一起进步。 个人主页&#xff1a;GUIDM主页 内容专栏&#xff1a;干货 此块内容为纯纯的干货&#xff0c;略显乏味枯燥&#xff0c;是笔记向的blog。如果觉得还不错&#xff0c;希望你可以一键三连&…

Vue2的响应式原理

--------Vue2响应式原理---------- 原理&#xff1a;通过数据劫持 defineProperty 发布订阅者模式&#xff0c;当 vue 实例初始化后 observer 会针对实例中的 data 中的每一个属性进行劫持并通过 defineProperty() 设置值后在 get() 中向发布者添加该属性的订阅者&#xff0c…

基于RuoYi若依vue的数据分页功能的前后端代码详解

目录 1.前端代码 1.1首先在前端会有一个 组件&#xff0c;为分页组件 1.2前端获取列表函数以及访问后端的URL与请求方式 1.3开发者工具查看前端访问后端信息 1.4开发者工具查看前端接收到后端的回应信息 2.后端代码 2.1接口 2.2接口内方法的代码 2.3后端Log输出如下 1.前…

IntersectionObserver API详解

过去&#xff0c;要检测一个元素是否可见或者两个元素是否相交并不容易&#xff0c;比如实现图片懒加载、内容无限滚动等功能时&#xff0c;都需要通过​getBoundingClientRect()​写大量的逻辑计算或者依靠scroll事件监听等性能很差方式来实现。 现在&#xff0c;依靠Interse…

Object.prototype.toString.call()的原理

今天在项目中看到了用Object.prototype.toString.call()这个方法封装的检测数据类型的工具。 但是浏览器搜索相关原理的好回答凤毛麟角&#xff0c;故而想记录一下&#xff0c;万一可以帮助到更多的新手呢&#xff1f;我的文章都是非常通俗易懂的&#xff0c;因为我写文章的时…

HTML页面知识点小总结(巨详细)

HTML基础知识点总结 文章目录HTML基础知识点总结一、 HTML页面主要的三大标签。二、 外部的CSS文件。三、外部的JavaScript文件。四、< body >标签中存放的内容。如果觉得写的不错的话点个赞支持鼓励一下吧&#xff0c;欢迎交流&#xff0c;谢谢啦~~~一、 HTML页面主要的…