前言打造属于自己的npm库 - 走进编程世界的新奇冒险
编程世界是一个充满无限可能的地方,它让我们能够创造出令人惊叹的应用和工具,改变着我们的生活方式和社会。不论你是一个刚踏入这个神奇领域的新手,还是一个经验丰富的老手,你已经取得了很大的进步,学会了使用现有的npm库来加速你的开发过程。现在,是时候向前迈出更大的一步,创造属于自己的npm库,让你的想象力得到充分的发挥!
为什么要写npm库?
你可能会疑问,为什么要自己动手写一个npm库呢?因为编写自己的npm库不仅可以提高你的技术水平,还能让你的代码为他人所用,让更多人受益。你的库可能解决了某个特定问题,或者提供了一种新颖的方法来处理常见任务。这是你展示才华、学习和成长的机会。
本教程的目标
在这个教程中,我将带你逐步了解如何创建自己的npm库。无需担心,我们将从最基础的开始,确保即使是没有太多经验的新手也能跟上。随后,我们将深入探讨npm库的结构、创建和发布过程,以及如何使用Node.js技术来实现功能强大、高质量的npm库。
将学到的技能
通过本教程,你将学到以下关键技能:
- 使用npm初始化一个新的npm库项目
- 编写库的代码和文档
- 进行本地测试和调试
- 发布你的npm库到全球npm注册表
- 处理版本控制和库维护
走向新奇冒险
写npm库是一段充满新奇冒险的旅程。它不仅让你深入了解软件开发的方方面面,还为你提供了与其他开发者分享和学习的机会。最重要的是,它展示了你的独创性和创造力。
我相信你已经准备好踏上这个令人兴奋的旅程。让我们一起开始吧!探索编程的乐趣,创造属于自己的世界,让你的代码闪耀着光芒,影响着未来。
祝你编程之旅愉快!
1. 搭建一个简单的npm库项目
一个优秀的项目必须建立在稳固的基础架构之上,因此我们首先需要确立项目规范并搭建良好的基础架构
所以接下来就开始搭建起始项目啦!
由于本篇文章只讲述搭建项目的核心芝士,所以prettier、eslint、commitlint、husky等这些基础规范配置就跳过了
当然!有兴趣的话或者不想自己搭建可以跳过,直接使用我搭建的更全面的 起始框架 starter-ts (求个star~)
初始化项目文件
- 创建项目文件夹
mkdir start-npm
- 进入项目文件夹
cd start-npm
- 初始化package
pnpm init
- 我这边使用的是pnpm,要使用其他的都没问题
- 由于是ts开发,所以安装
pnpm i typescript@4.8.4 -D
- 使用vscode打开当前的目录
code .
- 如果是mac的话 需要
cmd + shift + p
开启code命令
- 如果是mac的话 需要
初始化vitepress
安装vitepress
zsh
pnpm add -D vitepress@latest
初始化vitepress
zsh
pnpm dlx vitepress init
我的选择是这些,建议与我的相同
然后需要在vitepress的config中加上base
因为后续的github pages的初始路径就是项目的名字,不设置的话部署完成之后是会路径错误的
此时执行 pnpm run docs:dev
就可以运行vitepress项目啦!
里面的各种可以在
config.ts
文件中配置 具体的可以查看官方文档,这里就不一一赘述了
安装vite打包工具
-
首先,项目中还需要安装vue与vue-tsc
- vue在vitepress中写组件会用到
- vue-tsc在打包的时候会用到
zshpnpm i vue vue-tsc -D
-
然后安装打包工具:
pnpm i vite vite-plugin-build rimraf -D
- vite-plugin-build 是一款vite社区的plugin
- 原生的vite库模式只能打包文件
- 而这款插件支持整个文件夹的转换和声明文件生成
- 详细的可以查看官方文档
- rimraf是一款删除文件的工具
- vite-plugin-build 是一款vite社区的plugin
-
接着需要在
package.json
中增加以下scriptjson{ "scripts": { "build": "npm run clean && vue-tsc --noEmit && vite build", "clean": "rimraf dist lib es types", } }
配置vite打包
- 创建
vite.config.ts
- 以下主要是通过vite-plugin-build打包的
- 详细的配置说明可以查看vite-plugin-build
- 其中也用到了rollup配置,详细的可以查看官方文档
ts
import path from 'path'
import { defineConfig } from 'vite'
import { buildPlugin } from 'vite-plugin-build'
export default defineConfig({
plugins: [
buildPlugin({
fileBuild: {
emitDeclaration: true, // 生成声明
inputFolder: 'packages', // 输入根目录
ignoreInputs: ['**/*.spec.*', '**/*.test.*', '**/*.d.ts', '**/*.vue', '**/*.md'] // 排除转换的文件
},
libBuild: {
buildOptions: [
{
rollupOptions: {
external: ['vue'], // 排除打包的依赖
output: { globals: { vue: 'vue' } } // 指定外部依赖
},
lib: {
formats: ['es', 'cjs'], // 打包转换的模式
entry: path.resolve(__dirname, 'packages/index.ts'), // 入口文件
name: 'starter-ts',
fileName: (format) => `index.${format}.js`
}
}
]
}
})
]
})
配置 tsconfig.json
ts
{
"compilerOptions": {
"target": "ESNext",
"removeComments": true, // 删除注释
"alwaysStrict": true, // 在代码中注入'use strict'
"noImplicitAny": true, // 不允许隐式的any类型
"noImplicitThis": true, // 不允许this有隐式的any类型
"sourceMap": false, // 生成目标文件的sourceMap文件
"noUnusedLocals": false, // 检查只声明、未使用的局部变量(只提示不报错)
"strictNullChecks": true, // 不允许把null、undefined赋值给其他类型的变量
"strictFunctionTypes": true, // 不允许函数参数双向协变
"module": "CommonJS",
"esModuleInterop": true, // 允许export=导出,由import from 导入
"moduleResolution": "node", // 模块解q析策略,ts默认用node的解析策略,即相对的方式导入
"lib": ["ESNext"],
"resolveJsonModule": true,
"strict": true,
"skipLibCheck": true,
"skipDefaultLibCheck": true,
"types": ["vitest/globals"]
},
"include": ["packages/**/*"],
"ts-node": {
"files": true
}
}
安装vitest单测工具
zsh
npm i vitest -D
接下来,为了执行测试,请将以下部分添加到你的 package.json
文件中:
json
{
"scripts": {
"test": "vitest"
}
}
另外建议安装vscode的vitest扩展,可以方便测试
vitest详细的配置可以查看 vitest官方文档
2. 编写库代码
创建一个hook - useSum
-
首先在
packages
下创建一个这样的文件结构jsuseSum ├─index.md // hook对应的文档 ├─index.test.ts // hook的测试程序 └index.ts // hook的入口文件
-
index.ts
useSum源码tsexport const useSum = (a: number, b: number) => a + b
-
index.test.ts
useSum测试tsimport { describe, expect, it } from 'vitest' import { useSum } from './index' describe('useSum', () => { it('should return the sum of two numbers', () => { const result = useSum(3, 5) expect(result).toBe(8) }) it('should handle negative numbers', () => { const result = useSum(-2, -4) expect(result).toBe(-6) }) it('should handle zero values', () => { const result = useSum(0, 0) expect(result).toBe(0) }) })
-
index.md
useSum文档md# useSum 计算两数之和 ## 示例 ```vue <template> <div> <input type="number" v-model="val1" /> <input type="number" v-model="val2" /> <br /><br /> result: {{ sum }} </div> </template> <script setup lang="ts"> import { useSum } from '.' import { ref, computed } from 'vue' const val1 = ref(1) const val2 = ref(1) const sum = computed(() => useSum(val1.value, val2.value)) </script> ```
-
然后在vitepress的sidebar中添加上useSum的文档连接
js{ sidebar: [ { text: 'hooks', items: [ { text: 'useSum', link: '/useSum/' }] }, { text: 'Examples', items: [ { text: 'Markdown Examples', link: '/markdown-examples' }, { text: 'Runtime API Examples', link: '/api-examples' } ] } ] }
-
最后一步:创建库入口文件
- 在packages下创建一个
index.ts
文件
tsexport * from './useSum'
- 在packages下创建一个
到现在就已经开发完一个hook了,然后可以执行test文件进行测试,通过之后就可以打包发包啦
3. 打包项目
以上流程都做好之后就可以打包项目了
zsh
pnpm run build
打包结果会创建以下3个文件夹
json
├─dist // 通过主入口文件打包出的文件夹
├─es // vite-plugin-build 打包出的es模式
├─lib // vite-plugin-build 打包出的commonJs模式
4. 发包前的准备
配置 package.json
json
{
"name": "start-npm",
"version": "1.0.0",
"description": "description", // 项目描述
"author": "coderhyh <coderhyh@gmail.com>", // 作者
"license": "MIT", // 开源许可证
"homepage": "https://coderhyh.github.io/start-npm",
"repository": { // 仓库来源
"type": "git",
"url": "git+https://github.com/coderhyh/start-npm"
},
"bugs": "https://github.com/coderhyh/start-npm/issues",
"main": "./lib/index.js", // commonJs模式入口文件
"types": "./es/index.d.ts", // ts类型入口文件
"module": "./es/index.js", // es模式入口文件
"files": [ // 发包包含的文件
"dist",
"lib",
"es"
],
"sideEffects": [ // tree shaking 优化
"dist/*"
],
"keywords": [ // 库的关键词 利于搜索
"start-npm"
],
"exports": { // 声明模块的导出方式 使你的库在不同的环境中能够被正确地引用和加载
".": {
"types": "./es/index.d.ts",
"import": "./es/index.js",
"require": "./lib/index.js"
},
"./es": {
"types": "./es/index.d.ts",
"import": "./es/index.js"
},
"./lib": {
"types": "./lib/index.d.ts",
"require": "./lib/index.js"
},
"./*": "./*"
},
"scripts": {
"build": "npm run clean && vue-tsc --noEmit && vite build",
"clean": "rimraf dist lib es types",
"test": "vitest",
"docs:dev": "vitepress dev packages",
"docs:build": "vitepress build packages",
"docs:preview": "vitepress preview packages"
},
"devDependencies": {
"rimraf": "^5.0.1",
"typescript": "^4.8.4",
"vite": "^4.4.9",
"vite-plugin-build": "^0.10.0",
"vitepress": "1.0.0-beta.7",
"vitest": "^0.34.1",
"vue": "^3.3.4",
"vue-tsc": "^1.8.8"
},
"dependencies": {}
}
这里重点解释一下 dependencies 字段:
dependencies中存放的是当前库的依赖, 比如我的库依赖
js-cookie
, 那么在我的库被下载时, npm便会读取package.json
文件,下载库所需的依赖到node_modules
中
package版本控制
安装bumpp
zsh
pnpm i bumpp -D
bumpp是一个版本控制工具,用于协助在更新 npm 包版本时生成更友好和可定制的版本变更提示信息。在开发和维护 npm 包时,更新版本是一个常见的操作,而 bumpp 可以帮助你生成有意义的版本变更说明,以便用户和开发者了解每个版本的改动。
并在package.json
的scripts中增加以下
json
{
"scripts": {
"release": "bumpp",
}
}
之后切换版本就会更加友好啦,并且还会自动commit、tag、push

配置 .gitignore
lua
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
bin
es
lib
cli
dist-ssr
packages/.vitepress/cache
*.local
# Editor directories and files
# .vscode/*
# !.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
创建github actions
GitHub Actions 是 GitHub 提供的一项持续集成(CI)和持续部署(CD)服务。它允许开发者自动化构建、测试和部署他们的代码,以提高开发工作流程的效率和可靠性。GitHub Actions 可以与 GitHub 仓库紧密集成,使开发者能够通过配置文件定义自定义的工作流程。
也就是说可以使用github actions实现自动化部署文档、自动发包。现在就开始吧!
-
首先在根目录创建对应文件
js├─.github | ├─workflows | | ├─docs.yml // 自动部署文档 | | └publish.yml // 自动发包
-
docs.yml
- 这个配置文件定义了一个完整的工作流程,涵盖了从代码检出到文档构建和部署的各个步骤,以自动化地将文档更新发布到 GitHub Pages 上
ymlname: Deploy Docs # 工作流程的名称,显示在 GitHub Actions 页面上 on: # 定义触发事件 workflow_dispatch: # 运行手动执行 push: # 当push的是master的分支,且修改的文件是paths中的,就会执行这个action branches: - master paths: - 'packages/**/*.md' - 'packages/.vitepress/**' - 'packages/public/**' jobs: # 定义一个或多个作业(jobs) docs: runs-on: ubuntu-latest # 指定作业运行在 `ubuntu-latest` 操作系统上 steps: # 定义作业中的一系列步骤 # 使用 `actions/checkout` 动作来检出代码库的内容 - name: Checkout 🛎️ uses: actions/checkout@v3.5.3 # 安装指定版本的 pnpm 包管理器 - name: Install pnpm uses: pnpm/action-setup@v2 with: version: '8.x' # 设置 Node.js 环境,然后进行依赖安装和文档构建 - name: Install and Build 🔧 uses: actions/setup-node@v3.7.0 with: node-version: '16.x' cache: pnpm - run: pnpm i - run: pnpm run docs:build # 将构建好的文档部署到 GitHub Pages - name: Deploy to GitHub Pages 🚀 uses: JamesIves/github-pages-deploy-action@v4.4.3 with: branch: pages # 指定部署到的分支名称 folder: packages/.vitepress/dist # 指定需要部署的文件夹路径
-
publish.yml
- 通过这个配置文件,GitHub Actions 会在推送一个标签,并且标签名符合
v*
格式的时候,自动执行一系列步骤,包括安装依赖、构建项目以及将代码包发布到 NPM 包管理器。这使得发布新版本的 npm 包变得更加自动化和便捷
ymlname: Publish Package To Npmjs # 定义触发工作流程的事件。在这里,工作流程会在标签推送到代码库,并且标签名符合 `v*` 格式时触发 on: workflow_dispatch: # 运行手动执行 push: tags: - 'v*' jobs: build: runs-on: ubuntu-latest steps: - name: Checkout 🛎️ uses: actions/checkout@v3.5.3 # 设置 Git 配置,以便在发布时使用指定的用户名和邮箱 - name: Configure Git run: | git config user.email "772567615@qq.com" git config user.name "coderhyh" - name: Install pnpm uses: pnpm/action-setup@v2 with: version: '8.x' - uses: actions/setup-node@v3.7.0 with: node-version: '16.x' registry-url: 'https://registry.npmjs.org/' cache: pnpm - name: ⏳ Install dependencies run: pnpm i - name: 👷 Build lib run: pnpm run build # 使用 `npm` 命令来发布包到 NPM 注册表 - name: 📦 Publish run: npm publish env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} # 使用 GitHub Actions 的 secrets 存储的 NPM token NPM_TOKEN: ${{ secrets.NPM_TOKEN }} # 另一种存储 NPM token 的环境变量
- 通过这个配置文件,GitHub Actions 会在推送一个标签,并且标签名符合
配置github中的settings
1. 要设置一下仓库的actions权限,不然的话执行工作流一些操作是没有权限的

然后往下滑 选择这个选项保存

2. 配置github pages
这里选择的分支是pages是因为上面的action工作流把打包的文档放在了pages分支下
如此就可以通过github站点访问部署的文档了

3. 配置npm发包的token
这个是需要创建npm账号的,可以自行创建
创建npm token

然后拿到token放在仓库即可

5. 发布仓库
如此一来,所有操作都已完成,现在就可以初始化仓库并发布到仓库
记住!包名不要重复!!不然发布npm不可以的!!!
如果首次发布没有给tag, 是不会执行publish的action, 所以可以去仓库actions中手动执行一下
仓库的action执行都可以在这里看到了,并且可以点击进入查看更详细的信息

手动发布npm包
这里说一下本地手动发布npm包的流程
- 创建一个npm账号
- npm的镜像源一定要设置会npm的
- 因为要发布到npm官网, 所以这个是不能错的
- 然后cd到项目中
npm login
登录账号npm publish
发布
6. 大功告成
现在,就可以在npm查看自己发布的包了
以下是我发布的一个库,有兴趣的童鞋可以拿去参考一下 hyh-toolkit 求个star~

结语
在这个教程中,我们一起探索了创建自己的npm库的精彩世界。从最初的规划到最后的实现,你已经迈出了许多令人激动的步伐,成为了自己的npm库创造者。
通过编写npm库,我们不仅提高了技术水平,还为开发社区贡献了独特的知识和创意。自己的库可能会成为其他开发者的强大工具,解决问题,推动项目向前发展。
感谢你我一起完成这个npm库的创造之旅。我相信,你将继续在编程的世界里谱写属于自己的精彩篇章。愿你的代码充满创造力,影响着更多的人,并为这个美妙的技术世界添彩。
祝你编程之路越走越远,不断迸发新的创意和成就!