从零开始:构建并发布你的 npm 工具库及文档网站

在日常的前端开发中,经常会遇到文本处理,日期处理,文本转换等需求。通常是将它写到一个utils 文件中。问题来了,每个项目都要处理,那么文件就要重复的复制,我是个懒人。想着用rollup将它打包成一个 npm 插件,然后直接安装,之后局部引入来。这样就方便了,同时也只需要我需要的插件。这样一来随着工具函数的扩展,势必会带来一个问题,如何维护函数的使用呢?那么就需要一个文档了,文档的便于管理也是个问题,这里采用vitepess 来作为工具函数的文档官网。

npm 插件包构建

这里我根据个人需求采用的是rollup 作为插件的打包工具。

说一下我选择它的原因:

  1. 我的插件是纯工具函数,所以不需要 html 的渲染,那么vite就不在我的考虑,vite 主要还是应用在界面插件的开发上,会比较好一点,
  2. rollup 使用了 ES6 修订版 JavaScript 中包含的代码模块的新标准化格式,而不是以前的特定解决方案,如 CommonJSAMD。这意味着可以自由无缝地组合你最喜欢的库中最有用的单个函数。实现局部加载的功能。
  3. Tree-Shaking会静态分析您导入的代码,并排除任何未实际使用的内容**。**

步骤 1: 初始化项目

  1. 创建项目目录

    1
    2
    mkdir my-rollup-package
    cd my-rollup-package
  2. 初始化项目
    初始化一个新的 npm 项目,这将会生成一个 package.json 文件:

    1
    pnpm init -y
  3. 安装开发依赖
    安装 Rollup 和所需的插件:

    1
    pnpm install --save-dev rollup rollup-plugin-typescript2 @rollup/plugin-commonjs @rollup/plugin-babel @rollup/plugin-node-resolve rollup-plugin-node-globals rollup-plugin-node-builtins @rollup/plugin-terser @rollup/plugin-json rollup-plugin-dts rollup-plugin-import-export typescript @types/node
    • rollup​:核心打包工具。
    • rollup-plugin-typescript2​:处理 TypeScript 文件。
    • ​**@rollup/plugin-commonjs**​:将 CommonJS 转换为 ES6。
    • ​**@rollup/plugin-babel**​:使用 Babel 转译代码。
    • ​**@rollup/plugin-node-resolve**​:解析模块。
    • rollup-plugin-node-globals​:处理 Node.js 的全局变量。
    • rollup-plugin-node-builtins​:处理 Node.js 的内置模块。
    • ​**@rollup/plugin-terser**​:压缩代码。
    • ​**@rollup/plugin-json**​:导入 JSON 文件。
    • rollup-plugin-dts​:生成 TypeScript 声明文件。
    • typescript​:安装 TypeScript。
    • @types/node: types 声明文件
  4. 配置 TypeScript
    添加 tsconfig.json 来配置 TypeScript:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    {
    "compilerOptions": {
    "allowJs": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "node",
    "noEmit": true,
    "resolveJsonModule": true,
    "forceConsistentCasingInFileNames": true,
    "sourceMap": true,
    "strict": true,
    "target": "esnext",
    "isolatedModules": true,
    "useDefineForClassFields": true,
    "jsx": "preserve",
    "lib": ["esnext", "dom"],
    "baseUrl": ".",
    "paths": {
    "@/*": ["src/*"]
    }
    },
    "exclude": ["dist", "node_modules"]
    }

步骤 2: 项目结构

创建项目文件夹和文件结构:

1
2
3
4
5
6
7
8
9
10
my-rollup-package/
└── src/
│ └── modules/ (工具函数文件)
│ │ └── hello.ts
│ └── index.ts (入口文件改成全体导出)
│ └── iem.d.ts (这个文件是方便导入)
└── dist/ (将会生成)
└── package.json
└── rollup.config.js
└── tsconfig.json
  • src/index.ts 是你的主文件,它将包含你的主要代码。

步骤 3: 编写代码

src/modules/hello.ts 中添加一些简单的代码,例如一个简单的工具函数

1
2
3
export function greet(name: string): string {
return `Hello, ${name}!`;
}

src/iem.d.ts 中导人所有的函数

1
2
3
declare module "iem:./modules/*" {
export {};
}
  • 告诉 TypeScript,所有匹配 "iem:./modules/*" 模式的导入都是有效的模块。
  • 使用空的导出 (export {}) 来表示这些模块不导出任何内容。
  • 主要目的是让 TypeScript 理解那些通过自定义加载器或者特殊路径的模块,以确保项目正常编译,特别是在集成非标准模块加载或路径时。

src/index.ts 导出所有的工具函数

1
export * from "iem:./modules/**/*";

步骤 4: 配置 Rollup

创建一个名为 rollup.config.js 的文件,并粘贴给出的配置代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import { defineConfig } from "rollup"; // 从 rollup 导入 defineConfig 函数,用于定义配置
import ts from "rollup-plugin-typescript2"; // 导入 TypeScript 插件,用于编译 TypeScript 文件
import commonjs from "@rollup/plugin-commonjs"; // 导入 CommonJS 插件,将 CommonJS 模块转换为 ES6
import babelPlugin from "@rollup/plugin-babel"; // 导入 Babel 插件,用于转译代码
import resolve from "@rollup/plugin-node-resolve"; // 导入 Node.js 解析插件,用于解析模块
import globals from "rollup-plugin-node-globals"; // 导入插件以处理 Node.js 全局变量
import builtins from "rollup-plugin-node-builtins"; // 导入插件以处理 Node.js 内置模块
import terser from "@rollup/plugin-terser"; // 导入 Terser 插件,用于压缩 JavaScript 代码
import json from "@rollup/plugin-json"; // 导入 JSON 插件,用于导入 JSON 文件
import dts from "rollup-plugin-dts"; // 导入 DTS 插件,用于生成 TypeScript 声明文件
import { importExportPlugin } from "rollup-plugin-import-export"; // 导入自定义插件,用于处理导入和导出

// 定义 Rollup 配置
const config = defineConfig([
{
input: ["src/index.ts"], // 输入文件为 src/index.ts
output: [
{
dir: "dist/esm", // 输出目录为 dist/esm
format: "esm", // 输出格式为 ES Module
preserveModules: true, // 保持模块结构
},
{
dir: "dist/cjs", // 输出目录为 dist/cjs
format: "cjs", // 输出格式为 CommonJS
preserveModules: true, // 保持模块结构
},
],
plugins: [
importExportPlugin(), // 使用自定义导入导出插件
ts(), // 添加 TypeScript 插件
babelPlugin({ exclude: "**/node_modules/**" }), // 添加 Babel 插件,排除 node_modules
json(), // 添加 JSON 插件
commonjs(), // 添加 CommonJS 插件
],
},
{
input: "src/index.ts", // 再次使用 src/index.ts 作为输入
output: [
{
file: "dist/umd/index.js", // 输出文件为 dist/umd/index.js
format: "umd", // 输出格式为 UMD
name: "utils", // UMD 格式时的全局变量名
},
],
plugins: [
importExportPlugin(), // 使用自定义导入导出插件
ts(), // 添加 TypeScript 插件
babelPlugin({ exclude: "**/node_modules/**" }), // 添加 Babel 插件,排除 node_modules
json(), // 添加 JSON 插件
commonjs(), // 添加 CommonJS 插件
resolve({ preferBuiltins: true, mainFields: ["browser"] }), // 添加解析插件,优先使用内置模块
globals(), // 添加全局变量插件
builtins(), // 添加内置模块插件
terser(), // 添加压缩插件
],
},
{
input: "src/index.ts", // 输入文件为 src/index.ts
output: {
dir: "dist/types", // 输出目录为 dist/types
format: "esm", // 输出格式为 ES Module
preserveModules: true, // 保持模块结构
},
plugins: [importExportPlugin(), dts()], // 使用自定义插件和 DTS 插件生成声明文件
},
]);

export default config; // 导出配置

步骤 5: 添加打包脚本

打开 package.json,并添加 scripts 部分来配置打包命令:

1
2
3
4
5
6
json
复制代码
"scripts": {
"build": "rollup -c",
"build:watch": "rollup -c -w"
}
  • build​:执行打包。
  • build:watch​:监视文件变化并实时打包。

步骤 6: 打包项目

运行以下命令以打包你的项目:

1
pnpm run build

这将会生成以下文件和目录:

  • dist/esm​:包含 ES Module 格式的代码。
  • dist/cjs​:包含 CommonJS 格式的代码。
  • dist/umd/index.js​:包含 UMD 格式的代码,可以用于浏览器和 Node.js。
  • dist/types​:包含 TypeScript 的声明文件(.d.ts 文件)。

步骤 7: 测试生成的 npm 包

你可以创建一个 test 目录来测试生成的包:

  1. 创建测试目录
    1
    2
    mkdir test
    cd test
  2. 编写测试代码
    test 目录中创建一个 JavaScript 或 TypeScript 文件来测试该包,例如 hello.test.ts
    1
    2
    3
    4
    5
    6
    7
    import { describe, it, expect } from "vitest";
    import { greet } from "../src/modules/hello";
    describe("hello", () => {
    it("greet", () => {
    expect(greet("david")).toMatchInlineSnapshot(`"Hello, david!"`);
    });
    });
  3. 添加测试脚本
    在 package.json 文件中添加如下内容
    1
    2
    3
    4
    5
    ......
    "scripts": {
    "test": "vitest",
    },
    ......
  4. 运行测试
    1
    pnpm run test

添加 Vitepess 文档插件

使用官网的单独安装指令

1
pnpm add -D vitepress

由于vitepessrollup其实是分开的,无所谓先后安装的顺序,你也可以使用vitepess官网的向导安装指令

  1. 在文件中建立如下目录

    1
    2
    3
    4
    5
    6
    7
    8
    my-rollup-package/
    ├─ docs
    │ ├─ .vitepress
    │ │ └─ config.js (配置文件主题之类的设置)
    │ ├─ api-examples.md
    │ ├─ markdown-examples.md
    │ └─ index.md
    └─ package.json
  2. 启动并运行
    将以下 npm 脚本注入到 package.json 中:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    {
    ...
    "scripts": {
    "docs:dev": "vitepress dev docs",
    "docs:build": "vitepress build docs",
    "docs:preview": "vitepress preview docs"
    },
    ...
    }

    docs:dev 脚本将启动具有即时热更新的本地开发服务器。使用以下命令运行它:

    1
    pnpm run docs:dev

基本配置到这里就结束了,更多关于 vitepress 的用法关注官网