实现 Rollup 插件alias 并使用单元测试提高开发效率

news2024/11/28 10:31:54

本篇文章是对 实现 Rollup 插件 alias | 使用 TypeScript 实现库的基本流程 | 使用单元测试提高开发效率 的总结。其中涉及到开发一个组件库的诸多知识点。

实现一个经常用的 rollup 插件 alias

首先执行npm init命令初始化一个package.json文件,因为插件使用了typescript作为类型校验,所以需要执行tsc --init命令去生成一个ts的配置文件tsconfig.json,执行完上述的命令之后安装项目依赖。

pnpm i rollup typescript @rollup/plugin-typescript tslib -D

先简单实现一下这个插件,插件要求导出一个方法并且返回一个对象

import { Plugin } from 'rollup'
export function alias(): Plugin {
  return {
    name: 'alias',
    resolveId(source: string, importer: string | undefined) {
      console.log('resolveId', source, importer)
      return source
    }
  }
}

接下来需要将index.ts编译成可执行的js文件,新增一个rollup配置文件rollup.config.js,指定输入以及输出

import { defineConfig } from 'rollup'
import typescript from "@rollup/plugin-typescript"

export default defineConfig({
  input: './src/index.ts',
  output: {
    file: './dist/index.js',
    format: 'es'
  },
  plugins: [
    typescript({
      module:'esnext'
    })
  ]
})

在package.json里面新增一条命令,并执行pnpm build

"scripts": {
    "build": "rollup -c rollup.config.js"
  },

一般执行到这里会有一个CommonJS和ES module的类型冲突,如图所示
在这里插入图片描述
我们只需要在package.json指定类型即可

"type": "module",

再次运行pnpm build可以发现在dist目录下会生成打包完成之后的index.js文件。

当别人去安装你的包的时候需要所指定执行的文件在哪,即修改package.json里面的main字段,由"main": "index.js"改为"main": "./dist/index.js"

使用开发的 alias 插件

新增一个example文件夹新增index.js、add.js写入相关的测试代码

import { add } from './utils/add.js'
console.log(add(1, 2))
export function add (a, b) {
  return a + b;
}

在example里面执行初始化并且新增rollup配置文件rollup.config.js,并且补充build命令,具体操作和上文类似

import { defineConfig } from 'rollup'
export default defineConfig({
  input: 'index.js',
  output: {
    file: './dist/index.js',
    format: 'es'
  }
})

通过在example目录下执行如下命令就可以使用我们开发的插件

// ../上层目录
pnpm i ../ -D

执行完之后会新增如下代码

"devDependencies": {
  "rollup": "^3.26.2",
  "rollup-alias": "link:.." //  新增的依赖
}

在这里插入图片描述
example/rollup.config.js里面引入我们编写的 alias 插件,完整的代码如下

import { defineConfig } from 'rollup'
import { alias} from 'rollup-alias'

export default defineConfig({
  input: 'index.js',
  output: {
    file: './dist/index.js',
    format: 'es'
  },
  plugins: [
    alias()
  ]
})

在此执行pnpm build可以发现已经成功的打印出了log
在这里插入图片描述

为插件添加TS类型提示

首先补充插件的参数类型提示并且完善一下插件逻辑

import { Plugin } from 'rollup'
interface AliasOptions {
  entries: { [key: string]: string }
}

export function alias(options: AliasOptions): Plugin {
  const { entries } = options
  return {
    name: 'alias',
    resolveId(source: string, importer: string | undefined) {
      console.log('resolveId', source, importer)

      const key = Object.keys(entries).find((e) => {
        return source.startsWith(e)
      })
      if (!key) return source
      return source.replace(key, entries[key]) + '.js'
    }
  }
}

执行build之后在我们会发给 alias 传参的时候并没有对应的参数类型提示
在这里插入图片描述
这里需要在tsconfig.json文件中开启 "declaration": true 功能,以及设置"outDir": "./dist"
package.json里面添加"types": "./dist/index.d.ts",执行完上述操作之后再次执行 pnpm build
在这里插入图片描述
在这里插入图片描述

补充单元测试

安装vitest,补充单元测试文件index.spec.ts,添加测试命令

pnpm i vitest -D
// index.spec.ts
import { describe, it, expect } from 'vitest'
import { alias } from '.'

describe('alias', () => {
  it('should replace when match successful', () => {
    const aliasObj:any = alias({
      entries: {
        '@': './utils'
      }
    })
    expect(aliasObj.resolveId('@/add')).toBe('./utils/add.js')
  })

  it('should not replace when match fail', () => {
    const aliasObj: any = alias({
      entries: {
        '@': './utils'
      }
    })
    expect(aliasObj.resolveId('!/add')).toBe('!/add')
  })
})
"scripts": {
    "test": "vitest"
  },

我们需要在 build 的时候排除掉我们的测试文件可以在 tsconfig.json 补充如下代码 "exclude": ["./src/*.spec.ts"]
然后执行pnpm test 可以看到这里的测试用例是通过的也可以证明我们写的代码是没问题的。
在这里插入图片描述

entries 支持数组格式

这里直接贴完成之后的代码

import { Plugin } from 'rollup'

interface AliasOptions {
  entries: { [key: string]: string } | { find: string, replacement: string }[]
}

export function alias(options: AliasOptions): Plugin {
  const entries = normalizeEntries(options.entries)
  return {
    name: 'alias',
    resolveId(source: string, importer: string | undefined) {
     
      console.log('resolveId', source, importer)
      const entry = entries.find((e) => e.match(source))

      if (!entry) return source

      return entry.replace(source)
    }
  }
}

function normalizeEntries(entries: AliasOptions["entries"]) {
  if (Array.isArray(entries)) {
    return entries.map(({ find, replacement }) => {
      return new Entry(find, replacement)
    })
  } else {
    return Object.keys(entries).map((key) => {
      return new Entry(key, entries[key])
    })
  }
}

class Entry {
  constructor(private find: string, private replacement: string) { }
  match(filePath: string) {
    return filePath.startsWith(this.find)
  }
  replace(filePath: string) {
    return filePath.replace(this.find, this.replacement)
  }
}

以上就简单的实现了一个rollup插件开发的大致流程

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

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

相关文章

DevOps系列文章之Argo CD 使用

一、什么是 argo cd Argo CD 是用于 Kubernetes 的声明性 GitOps 连续交付工具。 二、为什么使用 argo cd Argo CD 可在指定的目标环境中自动部署所需的应用程序状态,应用程序部署可以在 Git 提交时跟踪对分支,标签的更新,或固定到清单的特…

测试开发之路 ---- 可读性,可维护性,可扩展性

目录 前言 测试框架与测试脚本的目标(部分) 分层 使用类似 xml 这种可扩展性强的语义存储数据 代码复用:抽象一切可抽象的,减少一切可能的代码相似与重复 活用 java 注解和反射(python 中应该也有相关的机制&…

如何从视频中提取音频?分享三个免费的方法给大家!

在数字时代,视频和音频的使用越来越广泛。有时,您可能希望从视频中提取音频,以便单独使用或与他人分享。无需购买昂贵的软件或具备专业技能,下面将介绍三种免费的方法,帮助您从视频中提取音频。这些方法简单易行&#…

Unity学习笔记--siki学院保卫萝卜

生命周期: 在同一个脚本中的执行先后顺序:先左后右 Inspector 赋值 > 外部调用 > Awake > OnEnable > Start 脚本对象的失活与激活不作用于Awake方法,当方法中只有Awake方法时,控制脚本激活失活的对勾会消失掉 当…

vue3 中ref的函数用法

简介 这里说的ref不是响应式ref,是用在组件身上的ref标识&#xff0c;一般都是ref“某一个字符串”&#xff0c;本文介绍第二种用法&#xff0c;ref“()>{}”,对没错&#xff0c;ref可以等于一个回调函数 ref可以是一个回调 <el-input:ref"(vc: any) > (inputAr…

lwip-2.1.3自带的httpd网页服务器使用教程(三)使用CGI获取URL参数(GET类型表单)

上一篇&#xff1a;lwip-2.1.3自带的httpd网页服务器使用教程&#xff08;二&#xff09;使用SSI动态生成网页部分内容 认识URL参数 在上网的时候&#xff0c;我们经常会见到在网址后面带有?AB&CD这样的语法格式。例如&#xff1a;https://blog.csdn.net/ZLK1214/articl…

OpenCV的HSV颜色空间在无人车中颜色识别的应用

RGB属于三基色空间&#xff0c;是大家最为熟悉的&#xff0c;看到的任何一种颜色都可以由三基色进行混合而成。然而一般对颜色空间的图像进行有效处理都是在HSV空间进行的&#xff0c;HSV(色调Hue,饱和度Saturation,亮度Value)是根据颜色的直观特性创建的一种颜色空间, 也称六角…

如何撤销git上一次的commit(或已push)

如何撤销git上一次的commit&#xff08;或已push&#xff09; 当多人开发时&#xff0c;我们本地commit后&#xff0c;刚要push&#xff0c;发现忘记pull最新代码&#xff0c;此时会有冲突push失败&#xff0c; 我们想要撤销最近的一次commit 我们先简单介绍一下git git有三大…

GreenPlum数据库日常维护

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&#x1f61…

使用 YOLOv8 和 Streamlit 构建实时对象检测和跟踪应用程序:第3部分:添加跟踪算法

介绍 对象跟踪是随着时间的推移识别一系列帧中的特定对象或多个对象的过程。它涉及定位对象在每个帧中的位置并跟踪其跨帧的移动。对象跟踪在各个领域都有广泛的应用,包括监控、机器人、自动驾驶、运动分析等。 跟踪算法使用各种技术(例如颜色直方图、运动分析、深度学习等)…

【多线程】(二)线程安全问题与线程同步

文章目录 一、多线程带来的风险1.1 观察线程不安全1.2 线程安全概念1.3 线程不安全的原因1.4 线程安全的解决方法 二、synchronized关键字2.1 synchronized 的特性2.2 synchronized 使用示例2.3 Java 标准库中的线程安全类 三、volatile关键字3.1 保证内存可见性3.2 禁止指令重…

Java反射的应用:动态代理

代理设计模式的原理 使用一个代理将对象包装起来, 然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。 对于静态代理&#xff0c;特征是代理类和目标对象的类都是在编译期间确定下来&#xff0c;不利于程…

基于FPGA的按键消抖

文章目录 基于FPGA的按键消抖一、按键消抖原理二、按键消抖代码三、仿真代码编写四&#xff1a;总结 基于FPGA的按键消抖 一、按键消抖原理 按键抖动&#xff1a;按键抖动通常的按键所用开关为机械弹性开关&#xff0c;当机械触点断开、闭合时&#xff0c;由于机械触点的弹性…

怎么使用Netty解码自定义通信协议

网络协议的基本要素 一个完备的网络协议需要具备哪些基本要素 魔数&#xff1a;魔数是通信双方协商的一个暗号&#xff0c;通常采用固定的几个字节表示。魔数的作用是防止任何人随便向服务器的端口上发送数据。协议版本号&#xff1a;随着业务需求的变化&#xff0c;协议可能…

SAP顾问生涯闲记:在SAP工作是什么体验

又有一段时间没更新自己的公众号了&#xff0c;为什么突然决定新开一篇SAP顾问生涯闲记系列的文章呢&#xff0c;是因为最近很荣幸地当选了SAP雇主品牌推广大使&#xff0c;作为SAP官方的推广大使在收获这份荣誉的同时&#xff0c;也承担了一些工作以及责任。 集结完毕︱SAP雇…

Flask_实现token鉴权

目录 1、安装依赖 2、实现代码 3、测试 源码等资料获取方法 1、安装依赖 pip install flask pip install pycryptodome 2、实现代码 import random import string import time import base64from functools import wrapsfrom flask import Flask, jsonify, session, req…

苍穹外卖day02——员工管理功能代码开发+分类管理代码导入

目录 新增员工——需求分析与设计 产品原型 接口设计: 数据库设计: 新增员工——代码开发 在Controller层中 在Service层中 在Mapper层中 功能测试 接口文档测试: 前后端联调测试: 新增员工——代码完善 ​编辑 第一个问题 第二个问题 员工分页查询 需求分析与设计 …

PostgreSQL考试难不难 ?

当涉及到PostgreSQL考试的详细难度&#xff0c;以下是一些可能涉及的主题和考点&#xff0c;这些主题在不同的考试中可能有所不同&#xff1a; 1.数据库基础知识&#xff1a;数据库的基本概念、关系型数据库模型、表、字段、主键、外键等。 2.SQL语言&#xff1a;对SQL语言的掌…

数据集——个人收集标注与使用过的数据集

前言 这是一个我个人在工作和学习中使用过以数据集的一部分&#xff0c;有语义分割&#xff0c;目标识别&#xff0c;人像抠图等几个大类&#xff0c;这只是我用过数据集中的一部分&#xff0c;这些数据集有小一部分是来源自网络&#xff0c;很大一部分都是我自己收集。 一、…