JSCommon:前端自己的 Commons

写在前面
如果你是一名前端开发者,你一定遇到过这样的场景:新建项目时,package.json
里的依赖列表越来越长,每次都要重复安装那些熟悉的工具库。如果你是一名后端开发者,刚接触前端时可能会困惑:为什么前端需要这么多依赖?为什么没有像 Java 的 Apache Commons 那样的统一工具库?为什么没有依赖收敛?
JSCommon 就是为了解决这些问题而生的。
前端开发的真实困境
每个项目都是"依赖收集器"
让我们看看一个典型的前端项目:

依赖地狱对比
这还只是冰山一角。随着项目复杂度增加,依赖列表会继续膨胀。每个库都有自己的版本更新节奏,有时候升级一个库会导致其他库不兼容,开发者需要花费大量时间处理这些版本冲突。
API 风格的"精神分裂"
更让人头疼的是,每个库都有自己的 API 设计风格:

API设计对比
作为开发者,你需要在不同的 API 风格之间切换:
- lodash 的
_.isEmpty()
- dayjs 的链式调用
dayjs().format()
- axios 的配置对象风格
- 各种库不同的参数顺序
这种不一致性不仅增加了记忆负担,也让代码审查变得困难。
学习成本的"复利效应"

学习曲线对比
对于新手前端开发者来说,这个学习曲线尤其陡峭。你不仅要学会 JavaScript 语言本身,还要掌握十几个不同工具库的 API。对于从后端转前端的开发者来说,这种碎片化的生态更是让人困惑。
JSCommon:一个依赖解决所有问题
设计哲学:简单就是美
JSCommon 的核心思想很简单:为什么不能像 Apache Commons 那样,提供一个统一的工具库?
bash
# 传统方式
npm install lodash dayjs axios big.js classnames js-cookie localforage qs validator vconsole animate.css
# JSCommon 方式
npm install @wolforest/jscommon
就这么简单。一个命令,解决所有常用工具函数的需求。
真实的项目结构
JSCommon 不是纸上谈兵,而是基于真实项目需求设计的:
scss
// 实际的模块组织
packages/core/src/
├── lang/ // 语言处理工具
│ ├── ArrayUtil.ts // 70+ 数组方法
│ ├── StringUtil.ts // 30+ 字符串方法
│ ├── DateUtil.ts // 25+ 日期方法
│ ├── ObjectUtil.ts // 40+ 对象方法
│ ├── NumberUtil.ts // 数字处理
│ ├── DecimalUtil.ts // 精确计算
│ └── ... // 其他 8 个工具类
├── net/URLUtil.ts // URL 和查询参数处理
├── storage/ // 存储方案
│ ├── StorageUtil.ts // localStorage/sessionStorage
│ ├── CookieUtil.ts // Cookie 操作
│ └── IDBUtil.ts // IndexedDB 封装
├── style/ // 样式工具
│ ├── ClassNamesUtil.ts // CSS 类名处理
│ └── AnimateUtil.ts // 动画效果
└── debug/VConsoleUtil.ts // 移动端调试
这不是随意拼凑的,而是基于 JavaScript
数据类型、特性及实际项目中最常用的功能模块精心设计的。当然也离不开 Apache Commons 的思想。
统一而强大的 API
JSCommon 最大的特点是 API 的一致性。所有工具类都遵循相同的命名规范:
csharp
// 统一的命名模式:模块名 + Util.方法名
ArrayUtil.isEmpty([]) // 检查数组是否为空
ArrayUtil.chunk([1,2,3,4], 2) // 数组分块
StringUtil.camelCase('hello-world') // 转驼峰
StringUtil.capitalize('hello') // 首字母大写
DateUtil.format(new Date(), 'YYYY-MM-DD') // 格式化日期
DateUtil.add(date, 1, 'day') // 日期加减
这种设计有几个明显的好处:
- IDE 友好 :输入
ArrayUtil.
后,IDE 会自动提示所有可用的数组方法 - 易于记忆:不需要记住不同库的不同 API 风格
- 代码可读性:看到方法名就知道它属于哪个功能模块
真实的使用体验
在 React 项目中
javascript
import { ArrayUtil, StringUtil, DateUtil } from '@wolforest/jscommon';
const UserList = ({ users }) => {
// 数据处理管道
const processedUsers = ArrayUtil.chunk(
ArrayUtil.compact(
ArrayUtil.map(users, user => ({
...user,
displayName: StringUtil.capitalize(user.name),
joinDate: DateUtil.format(user.createdAt, 'YYYY年MM月DD日')
}))
),
10 // 每页10个用户
);
return (
<div>
{processedUsers.map((userGroup, index) => (
<UserGroup key={index} users={userGroup} />
))}
</div>
);
};
在 Vue 项目中
javascript
import { StringUtil, NumberUtil, StorageUtil } from '@wolforest/jscommon';
export default {
data() {
return {
userPreferences: StorageUtil.getItem('preferences') || {}
};
},
computed: {
formattedPrice() {
return StringUtil.capitalize(
`${NumberUtil.toFixed(this.price, 2)} 元`
);
}
},
methods: {
savePreferences() {
StorageUtil.setItem('preferences', this.userPreferences);
}
}
};
对于后端开发者
如果你习惯了 Java 的开发方式,JSCommon 会让你感到熟悉:
scss
// 类似于 Java 的 StringUtils
StringUtil.isEmpty(str) // 类似 StringUtils.isEmpty()
StringUtil.isBlank(str) // 类似 StringUtils.isBlank()
// 类似于 Java 的 CollectionUtils
ArrayUtil.isEmpty(list) // 类似 CollectionUtils.isEmpty()
ArrayUtil.isNotEmpty(list) // 类似 CollectionUtils.isNotEmpty()
// 类似于 Apache Commons Lang
ObjectUtil.equals(obj1, obj2) // 类似 Objects.equals()
工程化的最佳实践
零性能损失的设计
JSCommon 不是重新造轮子,而是智能整合现有的优秀库:
ini
// ArrayUtil.ts 的实际实现
import { chunk, isEmpty, head, last } from 'lodash-es';
export class ArrayUtil {
// 直接导出 lodash-es 的函数,零性能损失
static chunk = chunk;
static isEmpty = isEmpty;
static head = head;
static last = last;
// ...
}
这种设计确保了:
- 性能:直接使用底层库的实现,没有额外的性能开销
- 稳定性:基于经过大量项目验证的成熟库
- 文档:每个方法都有完整的 JSDoc 注释和使用示例
真正的按需加载
javascript
// 方式一:完整导入(适合快速开发)
import { ArrayUtil, StringUtil } from '@wolforest/jscommon';
// 方式二:模块导入(推荐方式)
import { ArrayUtil } from '@wolforest/jscommon/lang';
import { StorageUtil } from '@wolforest/jscommon/storage';
// 方式三:最小化导入
import { ArrayUtil } from '@wolforest/jscommon/lang';
const { isEmpty, chunk } = ArrayUtil;
通过 Webpack 或 Vite 的 Tree-shaking,只有实际使用的代码会被打包到最终的应用中。
完整的 TypeScript 支持
ini
// 完整的类型推导
const numbers = [1, 2, 3, 4, 5];
const chunks = ArrayUtil.chunk(numbers, 2); // 类型:number[][]
const first = ArrayUtil.head(numbers); // 类型:number | undefined
// 泛型支持
interface User { id: number; name: string; }
const users: User[] = [...];
const userNames = ArrayUtil.map(users, u => u.name); // 类型:string[]
实际的数据表现
基于我们的 React 示例项目的真实数据:
打包体积对比
导入方式 | 压缩前 | Gzip 后 | 说明 |
---|---|---|---|
完整导入 | 484KB | 136KB | 包含所有 21 个模块 |
单模块导入 | 50-120KB | 15-35KB | 如只导入 lang 模块 |
具体工具类 | 5-25KB | 2-8KB | 如只使用 ArrayUtil |
功能覆盖
- 21 个工具模块:覆盖前端开发的各个方面
- 409 个常用方法:基于真实项目统计的高频使用函数
- 10 个核心依赖库:精选的业界最佳实践
适用场景
快速原型开发
less
// 一个完整的数据处理流程
import { ArrayUtil, StringUtil, DateUtil, URLUtil } from '@wolforest/jscommon';
const processApiData = (rawData) => {
// 数据清洗和转换
const cleanData = ArrayUtil.compact(
ArrayUtil.map(rawData, item => ({
id: item.id,
title: StringUtil.capitalize(StringUtil.trim(item.title)),
date: DateUtil.format(item.timestamp, 'YYYY-MM-DD'),
url: URLUtil.addQuery(item.link, { utm_source: 'app' })
}))
);
// 分页处理
return ArrayUtil.chunk(cleanData, 20);
};
生产环境应用
typescript
// 只导入需要的模块,最小化打包体积
import { ArrayUtil, StringUtil } from '@wolforest/jscommon/lang';
import { StorageUtil } from '@wolforest/jscommon/storage';
// 用于大型应用的数据处理
class DataProcessor {
static process(data: any[]) {
return ArrayUtil.map(data, item => ({
...item,
slug: StringUtil.kebabCase(item.title)
}));
}
}
期望的社区反馈
以下社区反馈纯属想象,如有雷同,纯属巧合!
基于实际使用反馈,JSCommon 解决了开发者的核心痛点:
"终于不用每个项目都重复安装那一堆依赖了" ------ 某前端团队负责人
"作为后端转前端,JSCommon 的 API 设计让我很快就上手了" ------ 某全栈开发者
"统一的 API 让我们的代码审查效率提升了很多" ------ 某技术主管
未来规划
JSCommon 不是一个静态的项目,我们会持续:
- 跟进生态发展:及时集成新的优秀工具库
- 优化 API 设计:基于社区反馈持续改进
- 扩展功能模块:根据实际需求添加新的工具类
- 性能优化:持续优化打包体积和运行性能
结语
前端开发不应该是依赖管理的游戏,而应该专注于创造用户价值。JSCommon 的目标很简单:让前端开发回归本质,让开发者把时间花在真正重要的事情上。
无论你是经验丰富的前端开发者,还是刚入门的新手,或者是从后端转前端的开发者,JSCommon 都能为你提供一致、可靠、高效的工具支持。
一个依赖,全部功能。这就是 JSCommon 的承诺。
开始使用:
bash
npm install @wolforest/jscommon
项目地址: github.com/wolforest/j...
NPM 包: @wolforest/jscommon
感谢阅读到最后,期待你的 github 🌟 鼓励!