前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >使用 Rollup + TypeScript 编写库

使用 Rollup + TypeScript 编写库

作者头像
Innei
发布于 2021-12-28 02:38:06
发布于 2021-12-28 02:38:06
2.6K00
代码可运行
举报
文章被收录于专栏:静之森静之森
运行总次数:0
代码可运行

本文的主题是一步一步建立 Rollup + TypeScript 代码模板。

前言

首先看看,我们需要做什么。通常一个库,在发布前他的目录树是这样的。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1.
2├── dist
3├── esm
4├── lib
5├── node_modules
6├── package.json
7├── pnpm-lock.yaml
8├── rollup.config.js
9├── src
10├── tsconfig.json
11├── vite.config.js

COPY

其中,dist 目录一般是通过 Rollup 等打包器打包后的入口文件,一般具有多种格式,以不同后缀命令,如: index.cjs.js index.esm.js。lib 和 esm 目录可以是 TypeScript 编译后生成的文件,目录下的结构基本和原项目结构相同,只是后缀变为 js,lib 一般为 CommonJS 格式,esm 为 ESModule 格式。而这些是一个库最基本的需要发布的文件。

初始化项目

通过如下命令快速开始:

bash

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1npm init -y
2npm i -D typescript rollup @rollup/plugin-typescript @rollup/plugin-commonjs @rollup/plugin-node-resolve rollup-plugin-terse rollup-plugin-peer-deps-external
3npx run tsc --init
4mkdir src
5touch src/index.ts
6echo 'export {}' >> src/index.ts

COPY

注:基本配置不再过多赘述,@rollup/plugin-commonjs 为 ES6 转换插件,@rollup/plugin-node-resolve 为 Node 模块解析插件,rollup-plugin-terse 为代码压缩插件,rollup-plugin-peer-deps-external 为打包时使用外部库插件(就是说,打包的时候不把依赖库打包进去,node_modules 依赖链你也知道)。

建立 rollup.config.js,编写基本配置以支持 TypeScript。

js

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1//@ts-check
2import commonjs from '@rollup/plugin-commonjs'
3import { nodeResolve } from '@rollup/plugin-node-resolve'
4import typescript from '@rollup/plugin-typescript'
5import peerDepsExternal from 'rollup-plugin-peer-deps-external'
6import { terser } from 'rollup-plugin-terser'
7
8const packageJson = require('./package.json')
9
10const umdName = packageJson.name
11
12const globals = {
13  ...packageJson.devDependencies,
14}
15
16const dir = 'dist'
17
18/**
19 * @type {import('rollup').RollupOptions[]}
20 */
21const config = [
22  {
23    input: 'src/index.ts',
24    // ignore lib
25    external: ['lodash', 'lodash-es', ...Object.keys(globals)],
26
27    output: [
28      {
29        file: dir + '/index.umd.js',
30        format: 'umd',
31        sourcemap: true,
32        name: umdName,
33      },
34      {
35        file: dir + '/index.umd.min.js',
36        format: 'umd',
37        sourcemap: true,
38        name: umdName,
39        plugins: [terser()],
40      },
41      {
42        file: dir + '/index.cjs.js',
43        format: 'cjs',
44        sourcemap: true,
45      },
46      {
47        file: dir + '/index.cjs.min.js',
48        format: 'cjs',
49        sourcemap: true,
50        plugins: [terser()],
51      },
52      {
53        file: dir + '/index.esm.js',
54        format: 'es',
55        sourcemap: true,
56      },
57      {
58        file: dir + '/index.esm.min.js',
59        format: 'es',
60        sourcemap: true,
61        plugins: [terser()],
62      },
63    ],
64    plugins: [
65      nodeResolve(),
66      commonjs({ include: 'node_modules/**' }),
67      typescript({ tsconfig: './src/tsconfig.json', declaration: false }),
68
69      // @ts-ignore
70      peerDepsExternal(),
71    ],
72
73    treeshake: true,
74  },
75]
76
77export default config

COPY

配置之后,使用 rollup -c,就可以编译打包 ts 文件到 dist 目录了。

但是这才刚刚开始。

Path Alias

一般的也会用 Path Alias 方便方法的引入。

在 tsconfig.json 配置 paths,如

json

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1{
2  "compilerOptions": {
3    "baseUrl": "./src",
4    "paths": {
5      "~/*": [
6        "*"
7      ]
8    },
9  }
10}

COPY

就可以用 import foo from '~/' 的形式了。为什么要讲这个。因为这个是巨坑。请看下节。

TSC 编译与 Path Alias

上面说了 Rollup 的打包,再来说说 TSC,其实也比较简单。一般的,我会在根目录下新建一个 tsconfig.json 作为基本 tsconfig,然后在建立 build 用 tsconfig,开发用 tsconfig,都是从根目录的 extends 出来。这样做的好处就是不同环境用不同配置比较灵活。

大概这就像这样:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1.
2├── package.json
3├── pnpm-lock.yaml
4├── readme.md
5├── renovate.json
6├── rollup.config.js
7├── src
8│   ├── tsconfig.build.json # build
9│   ├── tsconfig.cjs.json # cjs build
10│   ├── tsconfig.json # dev
11├── tsconfig.json  # base
12├── vite.config.js
13└── yarn-error.log

COPY

前面说了 tsc 编译也要两种格式一个是 ESM,另一个是 CJS。就需要编写两个配置了,唯一的不同其实就是 outDirmodule。然后编译跑这行就行了。

json

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1{
2  "scripts": {
3    "build": "tsc --build src/tsconfig.build.json && tsc --build src/tsconfig.cjs.json"
4  }
5}

COPY

好像没有什么不对,但是仔细一看人傻了,tsc 编译之后的产物没有把 Path Alias 转换过来。但是这个库被调包侠调过来之后,它的环境咋知道 ~ alias 是个啥,况且 js 也不读 tsconfig 的配置。

这可咋整。

一查发现别的 CLI 都用了一个工具叫 tsconfigs-paths,但是这玩意好像只是个库,用起来比较麻烦。在这之后有大佬写一个 TypeScript 的插件叫 @zerollup/ts-transform-paths。用于解决这个问题。由于目前 TypeScript 还不支持自定义 transformer 所以得用 ttypescript 替换 TypeScript。

bash

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1npm i -g @zerollup/ts-transform-paths ttypescript

COPY

json

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1// tsconfig.json
2{
3  "compilerOptions": {
4    "outDir": "./dist",
5    "baseUrl": "./src",
6    "paths": {
7      "~/*": [
8        "*"
9      ]
10    },
11    "plugins": [
12      {
13        "transform": "@zerollup/ts-transform-paths",
14      }
15    ]
16  }
17}

COPY

tsc 全换成 ttsc,

bash

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1ttsc --build src/tsconfig.build.json && ttsc --build src/tsconfig.cjs.json"

COPY

之后。

打包 DTS

DTS 就是 tsc 生成 d.ts,我们要做的就是把 dts 也打包一份,全部扔到一个 index.d.ts。这样的话如果引用的是任何一个 dist 下的 index.js (比如dist/index.esm.js)都会识别到 type definition。

但是,@rollup/plugin-typescriptrollup-plugins-typescript2 都没有这一功能。

之后就发现了一个神器 dts-bundle-generator。可以做到这个需求,同时它也支持 Path Alias 的转换。

使用也非常的简单。

bash

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1dts-bundle-generator -o build/index.d.ts src/index.ts --project tsconfig.json  --no-check

COPY

一些不能工作的点

  1. ttsc 在 typescript 4.5.2 的环境可能会报错。TypeError: Cannot read properties of undefined (reading 'impliedNodeFormat')。 解决方式:降级到 4.4.4
  2. dts-bundle-generator 不能支持没有提前引入的泛型的值的解析(也可能是 目前 TS 的 bug)参考:https://github.com/timocov/dts-bundle-generator/issues/178

Package.json

注明需要发布的文件,以及入口文件、类型文件。

json

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1{
2  "main": "build/index.cjs.js",
3  "module": "build/index.esm.js",
4  "types": "build/index.d.ts",
5  "unpkg": "build/index.umd.min.js"
6}

COPY

完整模板:

rollup-typescript-lib

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

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

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

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
.Net Remoting(分离服务程序实现) - Part.3
在上面Remoting基本操作的范例中,我们发现了这样一个情况:即是 客户应用程序 仍然需要引用 服务程序集(ServerAssembly),因为它需要DemoClass的元信息来创建代理。使用这种共享服务程序集的方式构建Remoting程序,其运行时的示意图如下所示:
张子阳
2018/09/30
5120
.Net Remoting(分离服务程序实现) - Part.3
.Net Remoting(远程方法回调) - Part.4
根据这三点的变化,我们可以看出:客户端含有客户端对象,但它还需要远程服务对象的元数据来构建代理;服务端含有服务对象,但它还需要客户端对象的元数据来构建代理。因此,客户端服务端均需要服务对象、客户对象的类型元数据,简单起见,我们将它们写在同一个程序集中,命名为ShareAssembly,供客户端、服务端引用。此时,运行时的状态图如下所示:
张子阳
2018/09/30
8500
.Net Remoting(远程方法回调) - Part.4
.NET Remoting 体系结构 之 信道的功能和配置 (二)
●  System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
DougWang
2020/02/18
7660
.Net Remoting(应用程序域) - Part.1
在互联网日渐普及,网络传输速度不断提高的情况下,分布式的应用程序是软件开发的一个重要方向。在.Net中,我们可以通过Web Service 或者Remoting 技术构建分布式应用程序(除此还有新一代的WCF,Windows Communication Foundation)。本文将简单介绍Remoting的一些基本概念,包括 应用程序域、Remoting构架、传值封送(Marshal by value)、传引用封送(Marshal by reference)、远程方法回调(Callback)、分别在Windows Service和IIS中寄宿宿主程序,最后我们介绍一下远程对象的生存期管理。
张子阳
2018/09/29
7510
.Net Remoting(应用程序域) - Part.1
原 WCF学习之旅----基础篇之NET
公用类 using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ServerObject {     public interface SayServer     {         string SayToServer(string word);     }     public class ServerObject:MarshalByRefObject,SaySe
魂祭心
2018/05/17
6300
.NET Remoting 体系结构 之 对象的激活
客户端可以使用和创建远程 Activator 类。使用 GetObject()方法,可以得到服务器激活的远程对象或知名的远程对象的代理。CreateInstance()方法返回客户端激活的远程对象的代理。 new 运算符可以代替 Activator 类激活远程对象。为此,还必须使用 RemotingConfiguration 类在客户端中配置远程对象。
DougWang
2020/02/17
7540
.NET简谈组件程序设计之(初识NetRemoting)
在本人的“.NET简谈组件程序设计之(初识远程调用) ”一文中,我们了解到什么是远程调用或者说在.NET平台上远程调用是什么样子的,可能和偏低层(Socket\Rpc)的远程调用有点距离。这只是系统为我们封装了假象而已,看不见不代表没有这逻辑,是为我们减轻了劳动负担。[王清培版权所有,转载请给出署名]
王清培
2022/03/14
3410
.NET简谈组件程序设计之(初识NetRemoting)
c# Romting简单示例
MaybeHC
2024/04/23
1810
c# Romting简单示例
WPF 使用RPC调用其他进程
如果在 WPF 需要用多进程通信,一个推荐的方法是 WCF ,因为 WCF 是 RPC 计算。先来讲下 RPC (Remote Procedure Call) 远程过程调用,他是通过特定协议,包括 tcp 、http 等对其他进程进行调用的技术。详细请看百度
林德熙
2018/09/18
1K0
我所理解的Remoting(1):Marshaling & Activation[下篇]
在上面一片文章,我花了大量的文字来来描述了Remote Object如何通过Marshaling的过程从Server端所在的Application Domain经过相关的转换(Transformation)传递到Client所在的Application Domain供Client调用; 以及Client的调用请求如何在Activate处于Server端Application Domain的Remote Object。大体的要点如下: Host在Server端注册Client可能会用到的一到多个Channel
蒋金楠
2018/01/16
5810
我所理解的Remoting(1):Marshaling & Activation[下篇]
解析.NET对象的跨应用程序域访问(下篇)
彭泽0902
2018/01/04
1.5K0
解析.NET对象的跨应用程序域访问(下篇)
.NET Remoting 体系结构 之 生命周期管理
对于客户端,答案比较简单。只要客户端调用远程对象上的方法,就会产生一个 System.Runtime.Remoting.RemotingException 类型的异常。此时,只需处理这个异常,完成一些必要 的工作,如重试、写日志以及通知用户等。 对于服务器,服务器应何时检测客户端是否还在?即服务器何时可以清理为该客户端保存的资 源?可以一直等待来自客户端的下一个方法调用,但该客户端可能再没有方法调用了。在 COM 领 域中,DCOM 协议使用 ping 机制解决这个问题。客户端把 ping 和引用对象的信息发送给服务器。 因为客户端在服务器上可能有几百个引用的对象,所以 ping 中的信息非常多。为了使这个机制更加 有效,DCOM 不发送所有对象的所有信息,而只发送与上一个 ping 不同的信息。 虽然这个 ping 机制在 LAN 上非常有效,但它并不适用于可伸缩的解决方案。考虑到有成千上 万的客户端向服务器发送 ping 信息,.NET Remoting 为生命周期管理提供了一个伸缩性更强的解决 方案:即租约分布式垃圾收集器(Leasing Distributed Garbage Collector,LDGC)。 这个生命周期管理只对客户端激活的对象和知名的单一对象有效。因为单一对象不保存状态, 所以在每个方法调用之后就可以销毁它们。客户端激活的对象保存状态,我们应该知道它们使用的 资源。如果在应用程序域外部引用客户端激活的对象,就需要创建租约。租约有一个租约时间。当 租约时间为 0时,租约就已经到期,此时远程对象就会断开连接,后由垃圾收集器回收。
DougWang
2020/02/17
6730
.NET Remoting 体系结构 之 信道的功能和配置 (一)
  信道用于.NET 客户端和服务器之间的通信。.NET Framework 4 发布的信道类使用 TCP 、HTTP 或IPC 进行通信。我们可以为其他的协议创建自定义信道。 HTTP 信道使用 HTTP 协议进行通信。因为防火墙通常让端口 80 处于打开的状态,所以客户端能 够访问 Web 服务器,因为.NET Remoting Web 服务可以侦听端口 80,所以客户端更容易使用它们。 虽然在 Internet 上也可以使用 TCP 信道,但是必须配置防火墙,这样客户端能够访问 TCP 信道 所使用的指定端口。与 HTTP 信道相比,在内部网环境中使用 TCP 信道能够进行更加高效的通信。 IPC 信道适合于在单个系统上进行跨进程的通信。因为它使用 Windows 进程间通信机制,所 以它比其他信道快。当执行远程对象上的方法调用时,导致客户信道对象就把消息发送到远程信道对象中。 服务器应用程序和客户端应用程序都必须创建信道。 下面的代码说明了如何在服务器端创建 TcpServerChannel:
DougWang
2020/02/17
1K0
如何通过Remoting实现双向通信
Remoting是NET平台下比较成熟高效的分布式技术,我们习惯采用传统的远程调用的方式使用Remoting。在客户端所在的Application Domain,我们通过Proxy(Transparent Proxy)远程地跨Application Domain调用一个方法。当来自Client端的调用请求通过Proxy到达Server端所在的Application Domain后,Remoting Infrastructure在Server 端激活(Activate)相应的远程对象(一个继承子System.
蒋金楠
2018/01/18
1K0
如何通过Remoting实现双向通信
我所理解的Remoting (2) :远程对象的生命周期管理[下篇]
在上一篇文章中([原创]我所理解的Remoting(2):远程对象生命周期的管理—Part I ),我简要的讲述了CLR的垃圾回收机制和Remoting 基于Lease的对象生命周期的管理。在这篇文章中,我们将以此为基础,继续我们的话题。在文章的开始,我将以我的理解详细地讲述Remoting中两个重要的概念——Lease和Sponsorship。然后我通过一个Sample,为大家演示如何以不同的方法延长远程对象的生命周期。 我们先不谈远程对象、本地对象。 不管是远程的对象,还是本地对象,都对于程序Appli
蒋金楠
2018/01/18
8460
我所理解的Remoting (2) :远程对象的生命周期管理[下篇]
我所理解的Remoting(1):Marshaling & Activation[上篇]
什么是Marshaling &Activation 对任何一项分布式技术(Distributed Technology),比如Remoting,XML Web Service,Enterprise Service,Marshaling和Activation(对于Marshaling,我实在是找不到一个比较贴切的中文短语来翻译,很多书把它翻译成封送,我总觉得很别扭,所以在这里我就直接用英文Marshaling,如果读者有较好的翻译,麻烦通知我一下)都是必须要解决的问题。本Blog主要讲述的是在Remoting
蒋金楠
2018/01/16
6890
我所理解的Remoting(1):Marshaling & Activation[上篇]
.NET Remoting 之了解
  在企业级应用开发中,分布式开发占据了越来越重要的位置。.NET Remoting 是一种可扩展性很强的开发技术。
DougWang
2020/02/18
8800
Castle 整合.NET Remoting
  今天研究了一下Castle的Remoting Facility.记录如下: 微软以前使用COM/DCOM的技术来处理分布式系统架构,通过Client端的Proxy代理程序来呼叫远程Server机器上的对象。.NET Framework则使用.NET Remoting或Web Services技术来实作分布式处理的工作概念;在这里针对.NET Remoting的设计架构做一个初步的简介和Castle整合示例。 .NET Framework提供了多种的机制来支持Remoting,如: .利用Channe
张善友
2018/01/19
5470
Castle 整合.NET Remoting
.net remoting 使用事件
在RPC如果需要使用事件,相对是比较难的。本文告诉大家如何在 .net remoting 使用事件。
林德熙
2018/09/19
7550
.net remoting 使用事件
Remoting配置文件的用法
本文转载:http://www.cnblogs.com/rickie/archive/2004/10/10/50392.html
跟着阿笨一起玩NET
2018/09/18
6950
推荐阅读
相关推荐
.Net Remoting(分离服务程序实现) - Part.3
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验