前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Rollup模块打包踩坑指南

Rollup模块打包踩坑指南

作者头像
luciozhang
发布于 2023-04-22 08:40:34
发布于 2023-04-22 08:40:34
3K00
代码可运行
举报
文章被收录于专栏:前端lucio前端lucio
运行总次数:0
代码可运行

Rollup是一个轻量级javascript模块打包器。相比于Webpack,Rollup更适合打包library。Rollup基于ES6模块,ES模块允许通过静态分析,实现tree-shaking优化,删除冗余代码。

对于Rollup和Webpack的选择,可以看下Rollup的官方文档:

Rollup 是用来构建库还是应用程序?(Is Rollup meant for building libraries or applications?) Rollup 已被许多主流的 JavaScript 库使用,也可用于构建绝大多数应用程序。但是 Rollup 还不支持一些特定的高级功能,尤其是用在构建一些应用程序的时候,特别是代码拆分和运行时态的动态导入 dynamic imports at runtime. 如果你的项目中更需要这些功能,那使用 Webpack可能更符合你的需求。

本文记录了打包一个js组件,并发布到npm的过程。

这次示例我们打包一个基于mobile-select封装的城市选择组件,先来看下将要被打包的代码。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import CityList from './list'
import MobileSelect from 'mobile-select'

const CitySelector = {}
CitySelector.districtData = null
CitySelector.instance = null
CitySelector.callback = null

/**
 * 初始化方法
 * @param trigger  省份城市控件id
 * @param title  标题
 * @param callback (indexArr, data) data是一个数组
 * @param type 类型 1 选择省市 2 选择省市区
 */
CitySelector.init = function (trigger, callback, title = "请选择省份城市", type = 1) {
    CitySelector.callback = callback

    CitySelector.districtData = CityList
    CitySelector.doInit(trigger, title, type)

}

// ***

export default CitySelector

可以看到,我们的代码import了两个外部库,list是存在本地的城市区划列表,mobile-select是一个开源的选择弹框组件。

1. 初始化项目

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
npm init

会生成一个package.json文件,修改下配置。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
  "name": "tip-city-selector",
  "version": "1.0.5",
  "description": "cn city selection component",
  "main": "dist/tip-city-selector.js",
  "scripts": {
    "build": "rollup -c"
  },
  "author": "luciozhang",
  "license": "ISC",
  "devDependencies": {},
  "dependencies": {}
}

2. ESLint代码检查

通过代码规范,避免不必要的bug。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
npm install --save-dev eslint

3. 安装Rollup

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
npm install --global rollup

4. 安装Babel相关插件

为了使用JavaScript的新特性。

https://www.rollupjs.com/guide/tools/#babel

关于babel的使用,推荐阅读下面这篇文章:

你真的会用 Babel 吗?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
npm i -D rollup-plugin-babel

rollup-plugin-babel插件并不包含babel包,需要安装必要的babel包依赖。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
npm i -D @babel/core @babel/preset-env

配置rollup.config.js

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// rollup.config.js
import babel from 'rollup-plugin-babel';

export default {
  input: 'src/main.js',  //打包入口
  output: {
    file: 'bundle.js',  //输出文件
    format: 'cjs'       //模块化方式
  },
  plugins: [
    babel({
      exclude: 'node_modules/**' // 只编译我们的源代码,忽略第三方代码
    })
  ]
};

创建babel配置.babelrc

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//.babelrc
{
  "presets": [
    ["latest", {
      "es2015": {
        "modules": false //设置"modules": false,否则 Babel 会在 Rollup 有机会做处理之前,将我们的模块转成 CommonJS,导致 Rollup 的一些处理失败
      }
    }]
  ],
  "plugins": ["external-helpers"] //允许 Rollup 在包的顶部只引用一次 “helpers”,而不是每个使用它们的模块中都引用一遍(这是默认行为)
}

安装插件babel-preset-latest和babel-plugin-external-helpers

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
npm i -D babel-preset-latest babel-plugin-external-helpers

运行一下,rollup -c。

报错了!

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[!] (plugin babel) Error: /Users/luciozhang/tip-city-selector/src/main.js: Babel 7.0.0-beta.56 has dropped support for the 'helpersNamespace' utility.If you are using @babel/plugin-external-helpers you will need to use a newer version than the one you currently have installed. If you have your own implementation, you'll want to explore using 'helperGenerator' alongside 'file.availableHelper()'.

看了下rollup-plugin-babel的issues,原来Babel7.x版本不建议使用babel-plugin-external-helpers,也没对其进行支持。

对比了下英文文档,是中文文档翻译不及时的锅。

我们修改下.babelrc文件去掉babel-preset-latest babel-plugin-external-helpers两个插件。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//.babelrc
{
  "presets": [
    ["@babel/env", {"modules": false}]
  ]
}

5. Node 模块位置解析

再次运行rollup -c。

可以了!!

但发现一个WARN

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
(!) Missing global variable name
Use output.globals to specify browser global variable names corresponding to external modules
mobile-select (guessing 'MobileSelect')

我们已经安装了mobile-select模块,但没有被找到。

我们需要rollup-plugin-node-resolve 插件,来告知Rollup怎么查找外部模块,安装它

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
npm install -D rollup-plugin-node-resolve
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//rollup.config.js
 plugins: [
       // …
    resolve({
       browser: true,
    }),
    // …
 ]

6. 加载 CommonJS 模块

再再次运行rollup -c。

WARN没了。但出现了一个Error。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[!] Error: 'default' is not exported by node_modules/mobile-select/mobile-select.js
https://rollupjs.org/guide/en/#error-name-is-not-exported-by-module

mobile-select模块是CommonJS模块,在Rollup中,加载CommonJS模块的能力放在可选插件中,我们需要安装rollup-plugin-commonjs。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
npm install -D rollup-plugin-commonjs
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//rollup.config.js
 plugins: [
       // …
    commonjs({
        include: ['node_modules/**']
    }),
    // …
 ]

7. PostCSS插件

再再再次运行rollup -c。

上一个Error解决了,我们来看下新的Error

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
!] Error: Unexpected token (Note that you need plugins to import files that are not JavaScript)
node_modules/mobile-select/mobile-select.css (1:0)

Rollup本身不支持加载css组件,我们需要安装一个Rollup的PostCSS插件。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
npm install -D rollup-plugin-postcss
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//rollup.config.js
 plugins: [
       // …
    postcss({
        extensions: ['.css'],
    }),
    // …
 ]

最后一次运行rollup -c,可以了。

8. 压缩代码

打包出来的js文件比较大,我们用rollup-plugin-terser压缩下代码。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
npm install -D rollup-plugin-terser

在rollup.config.js的 插件列表加上terser()。

9. Rollup输出配置

打包的工作到这里就结束了,我们想要测试打包成果。

可能你还记得,我们打包输出的是CommonJS模块,因为rollup.config.js里面的output.format选项选择的是cjs。

可选的输出模块类型有下面这些:

  • amd – 异步模块定义,用于像 RequireJS 这样的模块加载器。
  • cjs – CommonJS,适用于 Node 和 Browserify/Webpack。
  • es – 将软件包保存为 ES 模块文件。
  • iife – 一个自动执行的功能,适合作为<script>标签。(如果要为应用程序创建一个捆绑包,您可能想要使用它,因为它会使文件大小变小。)
  • umd – 通用模块定义,以 amd,cjs 和 iife 为一体。

为了放在<script>中使用,方便测试,我们将打包格式改为umd。

同时,对于life和umd格式,我们需要指定输出模块名称,在js脚本中可以直接使用模块。

最终,我们的Rollup打包配置是这样的。

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

export default {
    input: './src/main.js',
    output: {
        file: './dist/tip-city-selector.js',
        format: 'umd',
        name: 'CitySelector'
    },
    runtimeHelpers: false,
    plugins: [
        postcss({
            extensions: ['.css'],
        }),
        resolve({
            browser: true,
        }),
        commonjs({
            include: ['node_modules/**']
        }),
        babel({
            exclude: 'node_modules/**',
        }),
        terser(),
    ]
};

10. 发布npm

最后,如果对封装的组件有信心的话,我们可以把组件发布到npm

package.json的main属性指向包的出口,在我们的项目中,是"main": "dist/tip-city-selector.js"。

npmloginnpm publish发布。

0. 参考文章

Rollup官方文档

你真的会用 Babel 吗?

rollup-plugin-babel

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-04-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

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

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
RunLoop详解
线程刚创建的时候没有Ru nLoop对象,RunLoop会在第一次获取它的时候创建
老沙
2019/09/28
6410
深入浅出 RunLoop(二):数据结构
CFRunLoopObserverRef中的_activities用来保存RunLoop的活动状态。当RunLoop的状态发生改变时,通过回调_callout通知所有监听这个状态的Observer。
师大小海腾
2020/04/16
9490
RunLoop总结:RunLoop基础知识
没有实际应用场景,很难理解一些抽象空洞的东西,所以前面几篇文章先介绍了RunLoop的几个使用场景。 另外AsyncDisplayKit中也有大量使用RunLoop的示例。 关于实际的使用RunLoop 的案例和使用场景就不总结了,今天总结一点RunLoop的基础知识和概念。
Haley_Wong
2018/08/22
8370
RunLoop总结:RunLoop基础知识
Runloop的再理解(Runloop下)
我们知道,Runloop可以保证线程不退出,那么,为什么Runloop具有此功效呢?那就要从Runloop的定义说起。
拉维
2019/10/28
8620
Runloop的再理解(Runloop下)
Objective-C RunLoop 详解
本文转自ibireme的《深入理解RunLoop》 RunLoop 是 iOS 和 OSX 开发中非常基础的一个概念,这篇文章将从 CFRunLoop 的源码入手,介绍 RunLoop 的概念以及底层实现原理。之后会介绍一下在 iOS 中,苹果是如何利用 RunLoop 实现自动释放池、延迟回调、触摸事件、屏幕刷新等功能的。 目录 RunLoop 的概念 RunLoop 与线程的关系 RunLoop 对外的接口 RunLoop 的 Mode RunLoop 的内部逻辑 RunLoop 的底层实现 苹果用 R
BY
2018/05/11
1.6K0
iOS RunLoop的介绍
MelonTeam
2018/01/04
1.2K0
iOS RunLoop的介绍
iOS多线程——RunLoop与GCD、AutoreleasePool你要知道的iOS多线程NSThread、GCD、NSOperation、RunLoop都在这里
你要知道的iOS多线程NSThread、GCD、NSOperation、RunLoop都在这里 转载请注明出处 https://cloud.tencent.com/developer/user/1605429 本系列文章主要讲解iOS中多线程的使用,包括:NSThread、GCD、NSOperation以及RunLoop的使用方法详解,本系列文章不涉及基础的线程/进程、同步/异步、阻塞/非阻塞、串行/并行,这些基础概念,有不明白的读者还请自行查阅。本系列文章将分以下几篇文章进行讲解,读者可按需查阅。 iOS
WWWWDotPNG
2018/04/10
1.9K0
【IOS开发高级系列】Runloop专题
http://www.cocoachina.com/ios/20150601/11970.html
江中散人_Jun
2023/10/16
5410
【IOS开发高级系列】Runloop专题
RunLoop源码阅读RunLoop源码阅读
系统内核在收发事件、消息时使用的消息传递函数。可以理解为多进程之间的一种通讯调用机制。
用户8893176
2021/08/09
1.2K0
RunLoop源码阅读RunLoop源码阅读
iOS开发·RunLoop源码与用法完全解析(输入源,定时源,观察者,线程间通信,端口间通信,NSPort,NSMessagePort,NSMachPort,NSPortMessage)
OSX / iOS 系统中,提供了两个这样的对象:NSRunLoop 和 CFRunLoopRef。
陈满iOS
2018/09/10
2.6K0
iOS开发·RunLoop源码与用法完全解析(输入源,定时源,观察者,线程间通信,端口间通信,NSPort,NSMessagePort,NSMachPort,NSPortMessage)
一份走心的runloop源码分析
对iOS开发者而言,runloop是一个老生常谈的话题,但凡是iOS开发者,在工作中必然直接或间接的接触过runloop。而对于面试者而言,runloop又几乎是必考点。在几年前,笔者写过一篇文章NSRunLoop,对runloop原理以及应用场景做了基本介绍。但是当时也是道听途说,简单的翻看了源码的do...while循环,并没有深入源码。所以,本文将从源码的角度剖析runloop的组成,强化自己对runloop的认识,验证我们脑海中一直以来似懂非懂的原理,真心希望这篇文章能够帮助到大家。
VV木公子
2020/05/20
9.2K0
一份走心的runloop源码分析
iOS源码分析(1)——RunLoop
NSRunLoop 是基于 CFRunLoopRef 的OC封装,提供了面向对象的 API,但不是线程安全的,CFRunLoopRef 是在 CoreFoundation 框架内的,它提供了纯 C 函数的 API,是线程安全的,CoreFoundation是开源的(CoreFoundation 源码地址)
羊羽shine
2019/05/29
8290
老司机出品——源码解析之RunLoop详解
RunLoop详解 不得不说,人的惰性是真可怕啊。 从上周六就到写runLoop的建议开始,星期三告诉自己从星期四开始着手写这篇博客。然而现在戳个时间戳,现在是4.30星期日。写完发出去又不知道是什么时候啦,哈哈哈懒癌 这一期讲什么呢?这一期讲runLoop哟。一直以来,runLoop这个玄而又玄的东西似乎被当做了公司面试挑人的终极话题,原因不难想,日常开发用到runLoop的地方少之又少,没有时间的积累这方面的知识应该还是相对较于匮乏的,所以runLoop的了解侧面也能发应开发者的开发经验,当然就被当做
老司机Wicky
2018/08/22
1.2K0
老司机出品——源码解析之RunLoop详解
RunLoop
RunLoop 是 iOS 和 OSX 开发中非常基础的一个概念,这篇文章将从 CFRunLoop 的源码入手,介绍 RunLoop 的概念以及底层实现原理。之后会介绍一下在 iOS 中,苹果是如何利用 RunLoop 实现自动释放池、延迟回调、触摸事件、屏幕刷新等功能的。
用户2491699
2018/08/09
8640
RunLoop
再谈RunLoop
RunLoop 一 概述: 一句话解释RunLoop:运行任务的循环。 为什么要有RunLoop:解决交互式UI设计中的一个问题,如何快速响应用户输入,如何快速将程序运行结果输出到屏幕? 计
王大锤
2018/05/17
8290
iOS_RunLoop、Modes、Source、Timer、Observer、主要结构...
RunLoop为了实现程序不退出,在没有事件处理时休眠,在有事件到来时立刻被唤醒。
mikimo
2022/07/20
4740
iOS_RunLoop、Modes、Source、Timer、Observer、主要结构...
RunLoop
临近春节,回望2020十分感慨,今年年初换了工作一年来都比较忙,回看上次写的文章停留在了2020年1月,上次写iOS文章停留在2018年3月十分感慨,这里总结下近期研究的RunLoop
陈雨尘
2021/02/04
4090
iOS 之如何利用 RunLoop 原理去监控卡顿?
1. 前言 卡顿问题,就是在主线程上无法响应用户交互的问题。如果一个 App 时不时地就给你卡一下,有 时还长时间无响应,这时你还愿意继续用它吗?所以说,卡顿问题对 App 的伤害是巨大的,也是 我们
网罗开发
2021/05/14
2.9K0
iOS 之如何利用 RunLoop 原理去监控卡顿?
深入浅出 RunLoop(三):事件循环机制
首先我们来看一下主线程的RunLoop的启动过程。 前面我们说过,我们的 iOS 程序能保持持续运行的原因就是在main()函数中调用了UIApplicationMain函数,这个函数内部会启动主线程的RunLoop。 打断点,通过 LLDB 指令bt查看函数调用栈如下:
师大小海腾
2020/04/16
9380
iOS学习——浅谈RunLoop
  RunLoop的字面意思是运行循环、跑圈,一个App启动后能一直执行,就是因为启动后进入了一个循环,在这个循环中不断监听各种状态、手势动作,并做出相应的响应。这个循环就是我们今天要探究的RunLoop。
mukekeheart
2018/10/12
7470
iOS学习——浅谈RunLoop
相关推荐
RunLoop详解
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档