开源库
开源库
在给开源库取名字时,需要去npm官网查询名字是否已将存在,如果和npm上已经发布的包重名,那么是不允许发布的。
比如命名为jstoolmax
初始化项目
创建目录并生成package.json文件:
mkdir jstoolmax
cd jstoolmax
npm init --y
安装依赖
项目采用TypeScript开发,并使用Jest进行测试:
npm install typescript jest ts-jest jest-environment-jsdom ts-node @types/jest -D
在项目根目录下创建src目录及tests目录。
项目开发与测试
基于DTT模式进行开发与单元测试。
示例如下:
- src/function.ts
- tests/function.test.ts
type FuncType = (...args: any[]) => any
export function debounce<T extends FuncType>(
func: T,
delay: number
): (...args: Parameters<T>) => void {
let timerId: ReturnType<typeof setTimeout> | null = null
return function (...args: Parameters<T>): void {
if (timerId) {
clearTimeout(timerId)
}
timerId = setTimeout(() => {
func(...args)
}, delay)
}
}
import { debounce } from '../src/function'
beforeEach(() => {
jest.useFakeTimers()
})
afterEach(() => {
jest.clearAllTimers()
jest.useRealTimers()
})
test('应该在等待时间之后调用函数', () => {
const func = jest.fn()
const debouncedFunc = debounce(func, 1000)
debouncedFunc()
jest.advanceTimersByTime(500)
expect(func).toHaveBeenCalledTimes(0)
jest.advanceTimersByTime(500)
expect(func).toHaveBeenCalledTimes(1)
})
test('当防抖函数执行的时候,始终只执行最后一次的调用', () => {
const func = jest.fn()
const debouncedFunc = debounce(func, 1000)
debouncedFunc('a')
debouncedFunc('b')
debouncedFunc('c')
jest.advanceTimersByTime(1000)
expect(func).toHaveBeenCalledWith('c')
})
test('在等待时间内又调用了函数,重置计时器', () => {
const func = jest.fn()
const debouncedFunc = debounce(func, 1000)
debouncedFunc()
jest.advanceTimersByTime(500)
debouncedFunc()
jest.advanceTimersByTime(500)
expect(func).toHaveBeenCalledTimes(0)
jest.advanceTimersByTime(1000)
expect(func).toHaveBeenCalledTimes(1)
})
开源协议
选择一个合适的开源协议,目的是为了明确的声明自己的权利。
如果没有开源协议,那么可能面临如下两种情况:
- 可能是会被认为放弃所有权利,此时可能就会被别有用心的人钻空子,如恶意剽窃、抄袭等,这会损坏库开发者的利益。
- 可能是会被认为是协议不明,一般商业项目都会很小心地选择使用的库,如果缺少协议,则一般不会使用,这会让我们的库损失一部分使用者。
开源协议有很多,常用的有GPL、LGPL、MIT、BSD、Apache,前端项目常用的开源协议是后面三个。可在Choose a license,选择合适的协议。
| 开源协议 | 商业用途 | 可以更改 | 可以分发 | 私人使用 | 商标使用 | 授予专利许可 | 承担责任 |
|---|---|---|---|---|---|---|---|
| MIT | ✅ | ✅ | ✅ | ✅ | ❌ | ||
| BSD | ✅ | ✅ | ✅ | ✅ | ❌ | ||
| Apache | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
有一个更简便的方法,那就是看一些知名项目(Vue、React、Angular)它们所选择的协议是什么:
| 开源协议 | 项目 |
|---|---|
| MIT | jQuery、React、Lodash、Vue、Angular、ESLint |
| BSD | Yeoman、node-inspector |
| Apache | Echarts、Less.js、math.js、TypeScript |
目前前端领域,MIT和Apache协议的居多。
文档
一般来讲,一个合格的库,应该包含如下的文档:
- README文档。
- 待办清单。
- 变更日志。
- API文档。
README
README是库的使用者最先看到的内容,其好坏直接影响了库使用者的选择,因此在书写README文档的时候原则上需要主题清晰,内容简洁。一个合格的README 文档一般会包含如下的内容:
- 库的介绍:需要概括你这个库解决了什么样的问题。
- 使用者指南:帮助使用者快速了解如何使用你这个库。
- 贡献者指南:会罗列出这个库所有的贡献者。
待办清单
待办清单主要使用用来记录即将发布的内容或者未来的计划。待办清单主要有两个目的:
- 告诉库的使用者当前这个库在未来会发布什么样的新功能。
- 作为库的开发者的一个备忘,提醒自己将来还需要交付的功能。
待办清单也是md文件,一般命名为TODO.md。在 Markdown 语法中,支持通过[ ] 和[ x ]来表示未勾选状态和勾选状态。
变更日志
变更日志用于记录每一个版本更新的时候变更了哪些内容,变更日志的主要目的有两个:
- 一个是方便库的使用者在升级版本时了解不同版本之间的区别,从而避免升级带来的风险。
- 方便库的开发者做一个版本变更的备忘录。
变更日志一般会记录版本号、变更时间以及具体变更内容,变更内容尽量做到简洁明了。如何书写变更日志可参考Keep a Changelog。
一般变更日志叫做 CHANGELOG.md,在进行变更日记的记录时,越新的版本放在越上面。
API文档
API文档理论上来讲越详细越好,因为之后库的使用者通常都是和你的API文档打交道,API文档的好坏会直接影响库使用者的使用体验。
目前来讲,API 文档可以选择如下3种方案:
- 功能较少:可以直接写在
README.md文件里面。 - 内容较多:可以单独写一个文件。
- API数量众多(类似于Vue、React这种体量的),一个文件也不能满足需求了,可考虑单独做一个网站来提供详细的文档。
开源代码
目前Github是全球最大的开源协作平台,大部分的代码都通过Github来托管代码,因此可将代码托管到Github上面。
创建仓库
在Github中注册一个账号,并创建一个仓库「自行完成」。
.git
初始化本地git仓库:
git init
初始化完成后,会在项目根目录下面有一个.git目录,说明当前的项目已经成功的被初始化为了一个代码仓库。
.gitignore
在进行推送之前,还需创建一个名为.gitignore的文件来明确哪些目录和文件不需要提交:
node_modules
coverage
dist
push
// 关联远程仓库
git remote add origin git@github.com:[username]/[repo].git
// 切换到主分支
git branch -M main
// 推送
git push -u origin main
在进行远端仓库推送之前,要保证本地的代码仓库的工作区是干净的,否则可能推送失败。
发布代码
在开源代码后,如果有其他开发者想要使用我们的库,还需要去Github上手动下载下来,添加到他们的项目里面,这样是非常低效的一种方式。
npm的出现解决了这个问题,npm是前端领域非常出名的一个包的托管平台,提供了代码的托管和检索以及下载安装功能。
github vs npm
- Github通常托管的是项目、库的源码,供其他开发者可以查阅源代码。
npm通常托管的是项目或者库打包之后的代码,向npm上传代码的时候,我们上传了什么文件,开发者通过npm安装的时候就会得到对应的文件,npm在进行代码托管的时候,一般不会上传源码,而是上传打包后的代码。
打包代码
可选择适合的打包工具对源代码进行打包,常见的打包工具有Rollup、Webpack、Vite等。
如果是工具库,通常提供三种输出方式:
commonjs格式,主要在Node端使用。esm格式,ECMAScript模块化标准。umd格式,浏览器端使用。
黑名单与白名单
往npm发布代码的时候,并不是说所有的代码都需要发布,而只应该发布打包后的代码。
有两种方式可对发布的内容进行过滤:
- 黑名单
黑名单方式类似于.gitignore的方式,创建一个.npmignore,在这个文件里面的目录或者文件就不会被发布到npm上:
node_modules
src
tests
使用黑名单的方式有一个问题是: 在项目中新增了一些文件或者目录的时候,.npmignore也需要做出相应的修改。但有些时候会忘记修改.npmignore文件,导致一些不必要的文件或者目录被发布到npm上去。
- 白名单
在package.json文件中添加files字段,只有files字段里面的文件或者目录才会被发布到npm上去:
"files": [
"/dist",
"LICENSE"
]
包信息
在发布之前,还需完善一些必要的包信息:
- 包的说明信息:包的名字、包的版本、包的描述、包的作者。
- 包的入口文件。
- 其它信息。
{
"name": "xxx",
"version": "1.0.0",
"description": "xxx is a JavaScript utility library ...",
"type": "module",
"main": "dist/index.common.js",
"module": "dist/index.esm.js",
"browser": "dist/index.js",
"scripts": {
"test": "jest",
"build": "rollup -c ./rollup.config.ts"
},
"keywords": ["xxx"],
"author": "Jason Wang",
"license": "MIT",
"files": [
"./dist",
"LICENSE"
],
}
npm镜像
在发布之前,要确保镜像是指向npm官方镜像的:
// 确保为 https://registry.npmjs.org/
npm config get registry
// 设置镜像
npm config set registry=xxx
登录npm
在npm注册账号后,使用如下命令进行登录:
npm login
发布
使用如下命令进行最终的发布:
npm publish
文档站点
搭建的网站实际上就是一个文档网站,此时可以选择静态站点生成器。这些生成器一般都是支持以Markdown文件为主来编写和组织文档, 主打的就是一个快。
静态站点生成器
目前常见的静态站点生成器,有vuepress、vitepress、docusaurus:
- Docusaurus:Facebook 维护的文档生成工具,基于 React,对于了解 React 的开发者,可以很方便的进行二次开发
- Vuepress:由 Vue 作者尤雨溪所开发的,使用 Vue 来驱动的静态网站生成器。
- Vitepress:在 Vuepress 基础上的一次升级,利用 Vite 的能力,为开发者提供了出色的开发体验。
vitepress
VitePress 是一个基于 Vite 的静态站点生成器,主要用于构建和开发文档型网站。VitePress 提供了一个轻量级、高性能的开发环境,可以让你快速地构建和发布静态站点。
- 基于 Vite: Vite 是一个新一代的前端构建工具,提供了快速的开发服务器和优化的构建。VitePress 利用 Vite 的能力,为开发者提供了出色的开发体验。
- Markdown 支持: VitePress 使用 Markdown 作为内容格式,可以非常方便地编写和组织文档。它还支持 Vue.js 组件,这意味着你可以在 Markdown 文件中直接使用 Vue 组件,从而轻松地创建交互式文档。
- 主题系统: VitePress 支持自定义主题,你可以轻松地创建一个独特的、符合你需求的网站。VitePress 还内置了一个默认主题,提供了基本的导航和搜索功能,使你可以快速地开始搭建网站。
- 扩展性: VitePress 支持插件系统,可以通过插件扩展其功能。开发者可以编写自己的插件,或使用现有的插件来增强 VitePress 的功能。
- SEO 友好: VitePress 生成的静态站点具有良好的搜索引擎优化( SEO )特性,有利于提高网站的搜索排名。
安装
// 搭建基本架子
npx vitepress init
// 安装 vitepress
npm install vitepress -D
// 启动项目
npm run docs:dev
网站首页
网站首页的布局,是由docs下面的index.md来决定,具体可参考。
配置文件
Vitepress是基于文档来自动生成网站的,也就是说路由的生成都是自动的,我们需要做的仅仅是把文档放到正确的位置即可。
更多配置可参考。
Frontmatter
整个网站是基于Markdown 文档的,但是和普通的Markdown 文档相比,需要有一个Frontmatter,Frontmatter采用的是yaml的格式,主要是针对这个Markdown做一些元数据信息补充。
更多可参考。
---
title: xxx
description: xxx
---
部署文档
部署网站,理论上来讲,只要你有一个服务器,你要采用什么样的方式来部署都是可以的。但是前提是你需要有一个服务器(物理机、云服务器)。
除此之外还可以使用免费的三方服务来部署,比如通过Github来创建免费网站。
GitHub Pages
GitHub Pages是Github提供的一个免费的静态网站托管服务,它允许将代码托管到Github仓库里面,之后会将这个仓库作为一个网站提供给访问者。
GitHub Pages托管服务一个账号只能对应一个网站,特别适合拿来做个人博客、项目文档、简历等静态网站。
- 免费。对于公开仓库,GitHub Pages提供免费的静态网站托管服务。
- 支持自定义域名。可以将自己的域名与GitHub Pages网站关联。
- HTTPS支持。GitHub Pages支持 HTTPS,确保网站内容在传输过程中受到保护。
- 简单的部署。只需将静态文件推送到GitHub仓库,GitHub Pages就会自动部署并更新您的网站。
Github Actions
Github Actions是一个自动化工具,允许在Github仓库里面定义工作流并且执行。有了这个工具之后,可以让代码在推送、拉取请求、issue创建等工作全部实现自动化,自动执行构建、测试、部署等任务。
- 集成在GitHub中。无需使用第三方CI/CD工具,直接在GitHub仓库中管理和执行自动化任务。
- 可定制。可以创建自己的工作流,定义一系列的步骤和任务,根据项目需求进行调整。
- 支持多种语言和平台。GitHub Actions支持各种编程语言和操作系统,包括Windows、macOS和Linux。
- 可扩展性。可以使用GitHub社区提供的大量预构建Actions,也可以创建自己的Actions。
部署流程
- 将文档项目变为一个代码仓库
git init
- 在项目根目录下面创建一个名为
.gitignore的文件,记录忽略进行版本控制的文件。
node_modules
dist
- 自定义工作流,在项目根目录下面创建一个
.github/workflows目录,并在该目录中创建一个名为deploy.yml部署文件记录工作流,Github Actions将按照此步骤自动执行。以下为一个示例,根据需求自行修改。
deploy.yml
- 在Github创建一个名为
[username].github.io的仓库,username为个人的Github用户名。 - 本地仓库(文档项目)与远程仓库管理并推送。
// 关联仓库
git remote add origin git@github.com:[username]/[username].github.io.git
git branch -M main
// 推送
git push -u origin main
- 代码推送后,将自动触发Github Actions,待部署成功后,即可通过
https://[username].github.io访问。