目的
开发基于 typescript ES6 语法, 使用jest eslint 为校验或测试的npm包。 因为需要使用到 ts, 模块化,所以就存在模块编译打包的问题, 现有的打包工具中,webpack , Parcel 更偏向多类型资源 的web应用打包, 对于纯粹的npm工具包来说 rollup 更简单实用, 这里记录rollup的基础使用流程。
概述
Rollup 是一个 JavaScript 模块打包器,可以将小块代码编译成大块复杂的代码,例如 library 或应用程序。Rollup 对代码模块使用新的标准化格式,这些标准都包含在 JavaScript 的 ES6 版本中,而不是以前的特殊解决方案,如 CommonJS 和 AMD。ES6 模块可以使你自由、无缝地使用你最喜爱的 library 中那些最有用独立函数,而你的项目不必携带其他未使用的代码。ES6 模块最终还是要由浏览器原生实现,但当前 Rollup 可以使你提前体验。
背景
当期rollup 版本为 2.52.1
安装
代码语言:javascript复制// 全局安装
npm i -g rollup
// 本地安装
npm i -D rollup
简单例子
目录结构
- root
- src
- main.js
- utils.js
// main.js
import { call } from './utils'
call('show me')
// utils.js
export function call(...args){
console.log(...args)
}
命令行打包构建
代码语言:javascript复制rollup -i src/main.js -o lib/main.js
// -i 入口文件地址
// -o 打包后出入目录
打包后的文件
代码语言:javascript复制function call(...args){
console.log(...args);
}
call('show me');
// 可以看到rollup 将两个包的内容都合并到了一个文件夹中
package 配置本地打包命令
如果我们不希望输入过长的命令行参数或者rollup 为本地安装时,我们可以通过设置package命令解决.
代码语言:javascript复制{
'script': {
'build': 'rollup -c rollup.config.js', // 使用配置文件构建
'dev': 'rollup -c rollup.config.js -w', // 开启实时监控
}
}
基础命令
- -c 指定配置文件
- -w 监听文件变化,实时构建
- -i 入口文件
- -o 输出路径
- -n 模块名称
- -m 开启sourcemap
使用配置文件 rollup.config.js
在根目录新建文件rollup.config.js , 使用 -c 命令设置rollup配置的文件路径。
代码语言:javascript复制// rollup.config.js
export default {
input: 'src/main.js',
output: {
name: 'rollup-pkg',
file: 'lib/main.js',
format: 'cjs'
}
}
基础配置入门
- input 打包入口
{
input: 'src/main.js'
}
- output 输出配置
{
output: {
// 包名称
name: 'rollup-pkg',
// 包类型
format:'umd',
// 输出路径
file: 'lib/main.js',
}
}
- plugins 插件,提供扩展功能, 例如: babel ,typescript 转换等
import pluginResolve from '@rollup/plugin-node-resolve'
import pluginCommonjs from '@rollup/plugin-commonjs'
{
plugins: [
// 外部依赖查询
pluginResolve(),
// commonjs 转换
pluginCommonjs()
]
}
- external 外链, 忽略部分依赖
{
external: ['vue']
}
- globals 全局模块, 为类似 jquery 挂载在全局对象上的模块指定挂载点
globals: {
jquery: '$'
}
配置进阶
多类型输出
output 可以接收配置数组, 打包输入多种形式的结果文件
代码语言:javascript复制{
output: [
{
// umd
name: 'pks',
file: 'lib/main.umd.js',
format: 'umd'
},
{
// esm
name: 'pks',
file: 'lib/main.esm.js',
format: 'esm'
}
]
}
// 输出后的文件目录
// lib
// - main.umd.js
// - main.esm.js
独立plugins 配置
代码语言:javascript复制{
plugins: [....],
output: [
{
...
// 为某一输入指定独立的plugins
plugings: [pluginStrip()]
}
]
}
sourcemap、sourcemapFile
代码语言:javascript复制{
output: {
...
sourcemap: true // 是否生成sourcemap
sourcemapFile: '' // sourcemap 输出地址
}
}
banner、 footer 文件首尾插入内容
代码语言:javascript复制{
output: {
// 插入版本号
banner: '/* my-library version: v4.1.1 */',
footer: '/* author copy-left */'
}
}
配置列表
导出配置可以为列表, 同时构建多个包
代码语言:javascript复制export default [
// 第一组配置, 输出到 lib/ 目录
{
input: 'src/main.ts',
plugins: [
pluginResolve({
extensions: ['.js', '.jsx', '.ts', '.tsx'],
}),
pluginCommonjs(),
pluginEslint({
throwOnError: true,
throwOnWarning: false,
include: ['src/**'],
exclude: ['node_modules/**']
}),
pluginTypescript2({
clean: true,
tsconfig: './tsconfig.json'
})
],
output: [
{
name: 'roll',
file: 'lib/main.umd.js',
format: 'umd'
},
],
},
// 第二组配置, 输出到 dist/ 目录
{
input: 'src/index.ts',
plugins: [
pluginResolve({
extensions: ['.js', '.jsx', '.ts', '.tsx'],
}),
pluginCommonjs(),
pluginEslint({
throwOnError: true,
throwOnWarning: false,
include: ['src/**'],
exclude: ['node_modules/**']
}),
pluginTypescript2({
clean: true,
tsconfig: './tsconfig.json'
})
],
output: [
{
name: 'roll',
file: 'dist/main.esm.js',
format: 'esm'
},
],
}
watch 配置项
代码语言:javascript复制{
// 包含目录
include: 'src/**',
// 忽略目录
exclude: 'node_modules'
}
常用插件 - Plugins
@rollup/plugin-node-resolve
模块查询,告诉rollup 如何查询node_modules内的依赖模块。
- 使用
import pluginResolve from '@rollupplugin-node-resolve'
{
plugins: [ pluginResolve({...options}) ]
}
- options
{
// 入口匹配
exportConditions: ['default', 'module', 'import'],
// 是否为浏览器环境, false 时将忽略所有浏览器属性
browser: false,
// 模块查询目录
moduleDirectories: ['./src'],
// 强制定位到根节点的 `node_modules` 包, 防止同类包的多次绑定
dedupe: [],
// 可操作的文件类型
extensions: ['.js', '.jsx', '.ts', '.tsx'],
// 限制包的查询路径范围
jail: ['/'],
// 用于扫描的属性?
mainFields: ['browser', 'jsnext:main', 'module', 'main'],
// 是否只处理断言为 ES2015 的模块
modulesOnly: false,
// 只查询匹配模式的路径, 未匹配的模块将作为外部模块
resolveOnly: ['batman', /^@batcave/.*$/],
// 模块根目录, 配合 dedupe 属性使用
rootDir: process.cwd(),
// 忽略package 中的 sideEffects 设置
ignoreSideEffectsForRoot: false,
}
- 实战使用比对
// main.js
import dayjs from 'dayjs'
import { call } from './utils'
call(dayjs().format('YYYY-MM-DD'))
// 未使用,ES模式打包结果
import dayjs from 'dayjs';
function call(...args){
console.log(...args);
}
call(dayjs().format('YYYY-MM-DD'));
// 使用后,ES模式打包结果
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
function createCommonjsModule(fn, module) {
return module = { exports: {} }, fn(module, module.exports), module.exports;
}
// 引入dayjs包
var dayjs_min = createCommonjsModule(.....);
function call(...args){
console.log(...args);
}
call(dayjs_min().format('YYYY-MM-DD'));
@rollup/plugin-commonjs
将commonjs模块转换为 ES6 模块, 当我们导入commonjs 包时, commonjs 模块无法直接被rollup解析,需要先转换为ES6 模块。该包配合 @rollup/plugin-node-reslove 来正确处理外部依赖的引入问题
- 使用
import pluginCommonjs from '@rollup/plugin-commonjs'
{
plugins: [pluginCommonjs()]
}
- options
{
// 动态引入处理,为需要动态引入的模块,创建模拟commojs环境
dynamicRequireTargets: [
// 需要处理的文件
'node_modules/logform/*.js',
// ! 标记不需要处理的文件
'!node_modules/logform/index.js',
],
// 忽略某些文件
exclude: [],
// 包含某些文件
include: [],
// 导入其他非js扩展文件
extensions: ['.js'],
// 忽略全局对象
ignoreGlobal: false,
// 是否生成 sourceMap
sourceMap: true,
// 对于同时使用 es6 和 commonjs require 的情况,是否使用混合模式
transformMixedEsModules: false,
// 需要忽略的 require
ignore: [(id) => id !== ''],
ignoreTryCatch: false,
ignoreDynamicRequires: false,
// 定义转换后的包引入写法, 例如: const foo = require('foo'); 转换为 import foo from 'foo';
esmExternals: false,
// default 默认导入的处理方式
defaultIsModuleExports: 'auto',
// 处理 require 引入返回值
requireReturnsDefault: false
}
@rollup/plugin-eslint
引入eslint 规则校验, 如果根目录包含.eslintrc.* 配置文件, 将被自动加载到配置中, 这里需要注意插件的引入位置, 应在其他编译,转换插件之前。 例如: pluginEslint(...) pluginTypescript2(...)。 保证eslint 处理的是源码,而非编译后的转换代码。
- 使用
import pluginEslint from '@rollup/plugin-eslint'
{
plugins: [
pluginEslint({
fix: true,
throwOnError: true,
throwOnWarning: true,
})
]
}
- options
{
// 是否自动格式化
fix: false,
// 显示错误提示
throwOnError: false,
// 显示警告提示
throwOnWarning: false,
// 包含文件
include: [],
// 忽略文件
exclued: [],
// 格式化处理函数
formatter: ''
}
rollup-plugin-typescript2
typescript 转换
- 使用
import pluginTypescript from 'rollup-plugin-typescript2'
{
plugins: [
pluginTypescript({
tsconfig: './src/tsconfig.json' // 引入本地tsconfig.json
})
]
}
- options
{
// 工作目录
cwd: process.cwd(),
// 默认tsconfig 配置
tsconfigDefaults: {...},
// tsconfig配置路径
tsconfig: './src/tsconfig.json',
// 覆盖 tsconfig, 优先级 tsconfigOverride > tsconfig > tsconfigDefaults
tsconfigOverride:{...},
// 是否做校验
check: true,
// 错误级别; 0: Error 1: Warning 2: Info 3: Debugs
verbosity: 1,
// 是否删除旧的构建文件
clean: false,
// 缓存地址
cacheRoot: '',
// 包含项规则
include: [ "*.ts (|x)", "**/*.ts (|x)" ],
// 排除项规则
exclude: [ "*.d.ts", "**/*.d.ts" ],
// 错误忽略
abortOnError: true,
rollupCommonJSResolveHack:false,
objectHashIgnoreUnknownHack: false,
// 是否使用tsconfig内的类型文件导出路径
useTsconfigDeclarationDir:false,
// 导入无法被映入的ts模块
typescript: '',
transformers: ''
}
@rollup/plugin-babel
插件将默认加载根目录下的 babel.config.js 配置文件
- 使用
import * as pluginBabel from '@rollup/plugin-babel'
{
plugins: [
pluginBabel.babel({
babelHelpers: 'bundled',
include: ['src/**'],
exclude: ['node_modules/**']
})
]
}
rollup-plugin-terser
代码压缩
代码语言:javascript复制import pluginTerser from 'rollup-plugin-terser'
{
...
plugins: [
pluginEslint({
throwOnError: true,
throwOnWarning: true,
include: ['./src/**'],
}),
pluginNodeResolve(),
pluginCommonjs(),
pluginTypescript2({
tsconfig: './tsconfig.es5.json'
}),
pluginTerser.terser() // 放在末尾,导出编译后的压缩文件
]
}
官方插件库
实例DEMO地址
rollup-learning-demo