Vite封装ts工具库并发布npm包

  最近公司的很多项目都用到相同功能的时间格式化函数,如果每次来一个项目都拷贝一份代码的话,就很麻烦,结合我们之前介绍的Verdaccio搭建npm私有服务器;本文我们通过Vite作为脚手架,封装一个时间函数的组件库。

  封装时间函数,就绕不开强大的Momentjs库,但是Momentjs库又比较大,我们打包的时候不想将其打包进我们的库中,打包时需要将依赖包进行排除;因此本文我们主要来看下如何通过Vite封装一个纯工具库,并且发布到内部的Verdaccio上使用。

框架搭建

  首先我们使用pnpm包管理器搭建一个Vite项目,选择库打包模式

1
pnpm create vite

  输入我们项目的名称,然后选择框架,选择其他Others:

谢小飞博客专用防爬虫链接,想要看最新的前端博客请点这里

选择框架

  这一步是选择项目的模板,我们在这里选择库模式:

模板

谢小飞博客专用防爬虫链接,想要看最新的前端博客请点这里

  最终我们生成项目模板的基本目录结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
|- lib
|- main.ts
|- public
|- vite.svg
|- src
|- main.ts
|- style.css
|- typescript.svg
|- vite-env.d.ts
|- index.d.ts
|- index.html
|- package.json
|- tsconfig.json
|- vite.config.ts

  这里我们对主要的文件和文件夹进行使用的说明;lib作为我们项目模块的主要存放目录,可以将我们不同的函数和模块等,放到它的下面,最后使用index.ts进行统一导出。

  src目录是调试目录,我们可以在main.ts中引入lib中的模块,进行调试,测试功能是否正常调用;因此这个文件夹下面的style.css和svg文件基本用不到。

想要在局域网中开启调试,在package.json中修改dev添加--host参数。

  此外,还有两个文件夹是打包后出现,一个是dist文件夹,生成打包后的文件;另一个是types文件夹,存放生成的类型声明文件;因此我们调整后的目录结构大致如下:

1
2
3
4
5
6
7
8
9
10
11
12
|- dist
|-(打包后的文件)
|- lib
|- index.ts
|- (其他模块)
|- src
|- main.ts
| types
|- index.d.ts
|- (其他类型声明文件)
|- package.json
|- vite.config.ts

使用块级注释

  我们项目的主要结构基本定义完后,先来写两个工具函数尝试一下,在lib目录下新建一个format.ts,导出两个函数,用来实现时间戳和时间字符串的相互转换:

谢小飞博客专用防爬虫链接,想要看最新的前端博客请点这里

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import moment, { MomentInput } from "moment";

// 将时间戳转换成时间字符串
export function formatTimestampToDate(
timestamp: MomentInput,
formatter = "YYYY-MM-DD HH:mm:ss"
) {
return moment(timestamp).format(formatter);
}

/**
* 将时间字符串转换成时间戳
* @param {String} date 时间格式,例如2023-06-01 02:00:00
* @returns {Number} 返回时间戳,例如1689264000000
*/
export function formatDateToTimestamp(date: MomentInput) {
return moment(date).valueOf();
}

  接着我们需要在lib/index.ts中进行统一导出:

1
export { formatTimestampToDate, formatDateToTimestamp } from "./format";

  上面的两个函数,我们发现使用了两种注释方式,一个是我们常见的行内注释,也就是两个斜杠的方式;另一个是比较详细的块级注释,将入参和出参都详细的标注说明;块级注释的好处,让我们在src/main.ts中引入两个函数看下实际的效果就知道了。

行内注释

块级注释

  很容易就发现,使用块级注释,在调用函数时具有很好的提示效果;这样别人在调用我们封装的函数时,就不用担心不知道函数的怎么调用,以及入参怎么传的问题了。

谢小飞博客专用防爬虫链接,想要看最新的前端博客请点这里

  那么如何来生成这样的注释呢?VSCode提供了一个插件jsdoc,我们可以在商店中很方便的搜索并安装:

jsdoc

  插件的使用也很简单,我们只要写前面/**,然后VSCode就会自动提示使用jsdoc的注释了。

使用jsdoc

生成类型声明文件

  我们在上面目录结构中说到,types文件夹用来存放生成的类型声明文件;这些类型声明文件包括上面编写的函数注释以及入参出参的类型;它的作用,主要就是在我们安装项目依赖后,VSCode就会从依赖中找到声明文件,进行提示操作,方便包的使用者来调用函数。

  因此类型声明文件就相当于是我们项目提供给外部的一份说明书,其重要性自然不必多说,但是如果让我们一个函数一个函数的编写说明书,大家肯定是不乐意的;那么回到我们的项目上来,看下如何根据我们导出的函数,自动的生成类型声明文件呢?

可以将项目根目录下初始化生成的index.d.ts文件删除。

  打开tsconfig.json文件,添加类型声明文件的配置,outDir属性设置输出的目录:

谢小飞博客专用防爬虫链接,想要看最新的前端博客请点这里

1
2
3
4
5
6
7
8
9
10
{
"compilerOptions": {
+ "declaration": true,
+ "outDir": "types",
+ "emitDeclarationOnly": true,
- "noEmit": true,
},
- "include": ["src"],
+ "include": ["lib"]
}

  这里include属性是设置生成类型声明文件需要包含的文件夹,我们上面定义了src作为调试目录,因此这里需要改为我们代码的主要目录lib;修改后我们进行打包,可以看到我们的类型声明文件已经生成在types目录下了:

类型声明文件

  此外,我们还需要将package.json中的types属性进行修改,告诉包的调用者,我们的类型声明文件放在哪:

1
2
3
4
{
- "types": "./index.d.ts",
+ "types": "./types/index.d.ts",
}

依赖管理

  在平时的开发中,相信大家对dependenciesdevDependencies比较了解了,我们知道dependencies是我们项目运行所必须的依赖,比如我们正常开发一个项目,用到vue、react、element-plus等依赖,都可以放到这里;而devDependencies则是在开发过程中用到的依赖,比如typescript、vite、webpack等涉及编译打包等一些依赖,都是放到devDependencies字段。

  那么如果别人在安装我们开发的包时,npm会如何处理devDependencies字段里面的包呢?很明显,npm不会去管这个字段,这个字段只是在我们包在开发中用到的依赖。

  而另外一个peerDependencies这个字段我们在平时项目开发中接触的比较少,它的翻译过来的意思就是对等依赖;就像我们在包里封装时间函数时,需要用到Momentjs库,但是如果打包的时候将其打包进去,会导致整个包非常臃肿,如果调用我们包的项目也安装了Momentjs库,就会造成资源重复打包。

  这时,我们就可以在package.json中,添加peerDependencies,告诉包的调用者,想要安装我,首先要安装这个字段下面所有的包;如果我们去看vuex和vue-router的包,我们会看到它们的package.json中都将vue设置为对等依赖:

1
2
3
4
5
{
"peerDependencies": {
"vue": "^3.2.0"
}
}

谢小飞博客专用防爬虫链接,想要看最新的前端博客请点这里

  那么回到我们的项目中来,我们在安装Momentjs时,可以添加--save-peer参数:

1
pnpm add moment --save-peer

  在vite打包时,还需要通过配置将其从打包中排除:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { defineConfig } from "vite";

export default defineConfig({
build: {
// 其他配置
rollupOptions: {
external: ["moment"],
output: {
globals: {
moment: "moment",
},
},
},
},
});

  这样,后续当我们在项目中安装我们开发的包时,我们会看到提示安装了两个依赖包,即包本身及其下面对等依赖的包;如果我们去查看node_modules,目录下中也有了moment。

1
2
npm install vite-library-demo
added 2 packages in 2s

谢小飞博客专用防爬虫链接,想要看最新的前端博客请点这里

发包

  写到这里,我们的包基本的功能已经都具备了,可以进行发包的操作了;这时我们又面临了一个问题,我们需要对哪些文件进行打包然后发布上去呢?

  根据上面的项目结构,我们主要需要发布的就是dist和types文件夹,而lib和src文件夹都是需要排除的。和.gitignore一样,.npmignore文件是用来指定在发包时需要排除的目录;此外,下面这些文件是默认发布的,加不加到ignore都没有影响:

当项目中没有指定.npmignore时,默认使用.gitignore文件

  因此,我们在项目根目录新建一个.npmignore文件,写入如下内容,将我们不需要的文件和文件夹进行发包时的排除:

1
2
3
4
5
6
node_modules
src
lib
vite.config.ts
tsconfig.json
index.html

  此外,如果我们项目下文件比较多,一个一个排除比较麻烦,我们可以参考vuex包的package.json,将我们需要发布的文件,直接放到files属性下即可:

1
2
3
4
5
6
7
{
"files": [
"dist",
"types"
],
// 其他属性
}

  因此,我们可以发现,包文件的优先级从高到低如下顺序:

1
files属性 > .npmignore > .gitignore

谢小飞博客专用防爬虫链接,想要看最新的前端博客请点这里

  另外这里有一个非常实用的小技巧,我们不需要每次publish后再查看包的内容,可以通过npm pack先生成一个包进行预览,再通过tar -tf XXX.tgz就可以预览包了。

发布预览

  最后,我们可以在这个包里添加一些发布信息,例如包作者和主页的信息:

1
2
3
4
5
{
"author": "",
"homepage": "",
// 其他属性
}

  当然别忘了,添加READMD.md说明,告诉大家你这个包是做什么用的;最后,在激动的输入npm pubsh命令后,我们的包就正式发布到Verdaccio上去了,快去告诉你的小伙伴来调用你的包把。

发布

本文所有源码敬请关注公众号【前端壹读】,后台回复关键词【Vite工具库】即可获取。

谢小飞博客专用防爬虫链接,想要看最新的前端博客请点这里


本网所有内容文字和图片,版权均属谢小飞所有,任何媒体、网站或个人未经本网协议授权不得转载、链接、转贴或以其他方式复制发布/发表。如需转载请关注公众号【前端壹读】后回复【转载】。