首先先来提一下我这两个开源项目,它们都是我们目前正在维护的开源项目:
如果你想参与进来开发或者想进群学习,可以添加我微信 yunmz777
,后面还会有很多需求,等这个项目完成之后还会有很多新的并且很有趣的开源项目等着你。
今年大部分时间都是在编码上和写文章上,但是也不知道自己都学到了啥,那就写篇文章来盘点一下目前的技术栈吧,也作为下一年的参考目标,方便知道每一年都学了些啥。
首先我先来对整体的技术做一个简单的介绍吧,然后后面再对当前的一些技术进行细分吧。
React 、Typescript 、React Native 、mysql 、prisma 、NestJs 、Redis 、前端工程化。
React 这个框架我花的时间应该是比较多的了,在校期间已经读了一遍源码了,对这些原理已经基本了解了。在随着技术的继续深入,今年毕业后又重新开始阅读了一遍源码,对之前的认知有了更深一步的了解。
也写了比较多跟 React 相关的文章,包括设计模式,原理,配套生态的使用等等都有一些涉及。
在状态管理方面,redux ,zustand 我都用过,尤其在 Zustand 的使用上,我特别喜欢 Zustand ,它使得我能够快速实现全局状态管理,同时避免了传统 Redux 中繁琐的样板代码,且性能更优。也对 Zustand 有比较深入的了解,也对其源码有过研究。
Next.js 是一个基于 React 的现代 Web 开发框架,它为开发者提供了一系列强大的功能和工具,旨在优化应用的性能、提高开发效率,并简化部署流程。Next.js 支持多种渲染模式,包括服务器端渲染( SSR )、静态生成( SSG )和增量静态生成( ISR ),使得开发者可以根据不同的需求选择合适的渲染方式,从而在提升页面加载速度的同时优化 SEO 。
在路由管理方面,Next.js 采用了基于文件系统的路由机制,这意味着开发者只需通过创建文件和文件夹来自动生成页面路由,无需手动配置。这种约定优于配置的方式让路由管理变得直观且高效。此外,Next.js 提供了动态路由支持,使得开发者可以轻松实现复杂的 URL 结构和参数化路径。
Next.js 还内置了 API 路由,允许开发者在同一个项目中编写后端 API ,而无需独立配置服务器。通过这种方式,前后端开发可以在同一个代码库中协作,大大简化了全栈开发流程。同时,Next.js 对 TypeScript 提供了原生支持,帮助开发者提高代码的可维护性和可靠性。
今年所有的项目都是在用 ts 写了,真的要频繁修改的项目就知道用 ts 好处了,有时候用 js 写的函数修改了都不知道怎么回事,而用了 ts 之后,哪里引用到的都报红了,修改真的非常方便。
今年花了一点时间深入学习了一下 Ts 类型,对一些高级类型以及其实现原理也基本知道了,明年还是多花点时间在类型体操上,除了算法之外,感觉类型体操也可以算得上是前端程序员的内功心法了。
不得不说,React Native 不愧是接活神器啊,刚学完之后就来了个安卓和 ios 的私活,虽然没有谈成。
React Native 和 Expo 是构建跨平台移动应用的两大热门工具,它们都基于 React ,但在功能、开发体验和配置方式上存在一些差异。React Native 是一个开放源代码的框架,允许开发者使用 JavaScript 和 React 来构建 iOS 和 Android 原生应用。Expo 则是一个构建在 React Native 之上的开发平台,它提供了一套工具和服务,旨在简化 React Native 开发过程。
React Native 的核心优势在于其高效的跨平台开发能力。通过使用 React 语法和组件,开发者能够一次编写应用的 UI 和逻辑,然后部署到 iOS 和 Android 平台。React Native 提供了对原生模块的访问,使开发者能够使用原生 API 来扩展应用的功能,确保性能和用户体验能够接近原生应用。
Expo 在此基础上进一步简化了开发流程。作为一个开发工具,Expo 提供了许多内置的 API 和组件,使得开发者无需在项目中进行繁琐的原生模块配置,就能够快速实现设备的硬件访问功能(如摄像头、位置、推送通知等)。Expo 还内置了一个开发客户端,使得开发者可以实时预览应用,无需每次都进行完整的构建和部署。
另外,Expo 提供了一个完全托管的构建服务,开发者只需将应用推送到 Expo 服务器,Expo 就会自动处理 iOS 和 Android 应用的构建和发布。这大大简化了应用的构建和发布流程,尤其适合不想处理复杂原生配置的开发者。
然而,React Native 和 Expo 也有各自的局限性。React Native 提供更大的灵活性和自由度,开发者可以更自由地集成原生代码或使用第三方原生库,但这也意味着需要更多的配置和维护。Expo 则封装了很多功能,简化了开发,但在需要使用某些特定原生功能时,开发者可能需要“弹出”Expo 的托管环境,进行额外的原生开发。
样式方案的话我使用的是 twrnc ,大部分组件都是手撸,因为有 cursor 和 chatgpt 的加持,开发效果还是杠杠的。
rn 原理也争取明年能多花点时间去研究研究,不然对着盲盒开发还是不好玩。
NestJs 的话没啥好说的,之前也都写过很多篇文章了,感兴趣的可以直接观看:
对 Nodejs 的底层也有了比较深的理解了:
Prisma 是一个现代化的 ORM (对象关系映射)工具,旨在简化数据库操作并提高开发效率。它支持 MySQL 等关系型数据库,并为 Node.js 提供了类型安全的数据库客户端。在 NestJS 中使用 Prisma ,可以让开发者轻松定义数据库模型,并通过自动生成的 Prisma Client 执行类型安全的查询操作。与 MySQL 配合时,Prisma 提供了一种简单、直观的方式来操作数据库,而无需手动编写复杂的 SQL 查询。
Prisma 的核心优势在于其强大的类型安全功能,所有的数据库操作都能通过 Prisma Client 提供的自动生成的类型来进行,这大大减少了代码中的错误,提升了开发的效率。它还包含数据库迁移工具 Prisma Migrate ,能够帮助开发者方便地管理数据库结构的变化。此外,Prisma Client 的查询 API 具有很好的性能,能够高效地执行复杂的数据库查询,支持包括关系查询、聚合查询等高级功能。
与传统的 ORM 相比,Prisma 使得数据库交互更加简洁且高效,减少了配置和手动操作的复杂性,特别适合在 NestJS 项目中使用,能够与 NestJS 提供的依赖注入和模块化架构很好地结合,提升整体开发体验。
Redis 和 mysql 都仅仅是会用的阶段,目前都是直接在 NestJs 项目中使用,都是已经封装好了的,直接传参调用就好了:
import { Injectable, Inject, OnModuleDestroy, Logger } from "@nestjs/common";
import Redis, { ClientContext, Result } from "ioredis";
import { ObjectType } from "../types";
import { isObject } from "@/utils";
@Injectable()
export class RedisService implements OnModuleDestroy {
private readonly logger = new Logger(RedisService.name);
constructor(@Inject("REDIS_CLIENT") private readonly redisClient: Redis) {}
onModuleDestroy(): void {
this.redisClient.disconnect();
}
/**
* @Description: 设置值到 redis 中
* @param {string} key
* @param {any} value
* @return {*}
*/
public async set(
key: string,
value: unknown,
second?: number
): Promise<Result<"OK", ClientContext> | null> {
try {
const formattedValue = isObject(value)
? JSON.stringify(value)
: String(value);
if (!second) {
return await this.redisClient.set(key, formattedValue);
} else {
return await this.redisClient.set(key, formattedValue, "EX", second);
}
} catch (error) {
this.logger.error(`Error setting key ${key} in Redis`, error);
return null;
}
}
/**
* @Description: 获取 redis 缓存中的值
* @param key {String}
*/
public async get(key: string): Promise<string | null> {
try {
const data = await this.redisClient.get(key);
return data ? data : null;
} catch (error) {
this.logger.error(`Error getting key ${key} from Redis`, error);
return null;
}
}
/**
* @Description: 设置自动 +1
* @param {string} key
* @return {*}
*/
public async incr(
key: string
): Promise<Result<number, ClientContext> | null> {
try {
return await this.redisClient.incr(key);
} catch (error) {
this.logger.error(`Error incrementing key ${key} in Redis`, error);
return null;
}
}
/**
* @Description: 删除 redis 缓存数据
* @param {string} key
* @return {*}
*/
public async del(key: string): Promise<Result<number, ClientContext> | null> {
try {
return await this.redisClient.del(key);
} catch (error) {
this.logger.error(`Error deleting key ${key} from Redis`, error);
return null;
}
}
/**
* @Description: 设置 hash 结构
* @param {string} key
* @param {ObjectType} field
* @return {*}
*/
public async hset(
key: string,
field: ObjectType
): Promise<Result<number, ClientContext> | null> {
try {
return await this.redisClient.hset(key, field);
} catch (error) {
this.logger.error(`Error setting hash for key ${key} in Redis`, error);
return null;
}
}
/**
* @Description: 获取单个 hash 值
* @param {string} key
* @param {string} field
* @return {*}
*/
public async hget(key: string, field: string): Promise<string | null> {
try {
return await this.redisClient.hget(key, field);
} catch (error) {
this.logger.error(
`Error getting hash field ${field} from key ${key} in Redis`,
error
);
return null;
}
}
/**
* @Description: 获取所有 hash 值
* @param {string} key
* @return {*}
*/
public async hgetall(key: string): Promise<Record<string, string> | null> {
try {
return await this.redisClient.hgetall(key);
} catch (error) {
this.logger.error(
`Error getting all hash fields from key ${key} in Redis`,
error
);
return null;
}
}
/**
* @Description: 清空 redis 缓存
* @return {*}
*/
public async flushall(): Promise<Result<"OK", ClientContext> | null> {
try {
return await this.redisClient.flushall();
} catch (error) {
this.logger.error("Error flushing all Redis data", error);
return null;
}
}
/**
* @Description: 保存离线通知
* @param {string} userId
* @param {any} notification
*/
public async saveOfflineNotification(
userId: string,
notification: any
): Promise<void> {
try {
await this.redisClient.lpush(
`offline_notifications:${userId}`,
JSON.stringify(notification)
);
} catch (error) {
this.logger.error(
`Error saving offline notification for user ${userId}`,
error
);
}
}
/**
* @Description: 获取离线通知
* @param {string} userId
* @return {*}
*/
public async getOfflineNotifications(userId: string): Promise<any[]> {
try {
const notifications = await this.redisClient.lrange(
`offline_notifications:${userId}`,
0,
-1
);
await this.redisClient.del(`offline_notifications:${userId}`);
return notifications.map((notification) => JSON.parse(notification));
} catch (error) {
this.logger.error(
`Error getting offline notifications for user ${userId}`,
error
);
return [];
}
}
/**
* 获取指定 key 的剩余生存时间
* @param key Redis key
* @returns 剩余生存时间(秒)
*/
public async getTTL(key: string): Promise<number> {
return await this.redisClient.ttl(key);
}
}
前端工程化这块花了很多信息在 eslint 、prettier 、husky 、commitlint 、github action 上,现在很多项目都是直接复制之前写好的过来就直接用。
后续应该是投入更多的时间在性能优化、埋点、自动化部署上了,如果有机会的也去研究一下 k8s 了。
最近刷到一个帖子,讲到了
我目前也算是一个小全栈了吧,我也来分享一下我的技术吧:
NextJs
React Native
prisma
NestJs
taro (目前还不会,如果有需求就会去学)
剩下的描述也是和他下面那句话一样了(毕业后对技术态度的转变就是什么能让我投入最小,让我最快赚到钱的就是好技术)
学无止境,任重道远。
1
changwei 1 天前
认同,目前这一套技术栈也是我正在使用的,感觉稳定性,开发便捷性,以及文档和社区的丰富程度和支持力度都还不错。
另外最近用到的 turbomono 也不错,nodejs 全栈很适合用这套方案(也可以用 nx ) 我之前在知乎也有回答类似的问题: https://www.zhihu.com/question/594662421/answer/3259377731 |
2
felbryiozzzz 1 天前
单机应用 我现在用 1panel + strapi
|
4
Yuesh1 1 天前
|
5
laobobo 1 天前
佩服啊,工作几年了,react 源码从来没读过,懈怠了,躺平了
|
6
CodeCodeStudy 1 天前
vue, element plus, uniapp, midwayjs, typeorm, mysql, nginx, redis
其中,mysql 要学会增删改查,关联查询,分组查询等,nginx 要学会反向代理,redis 只要写入和读取和设定过期时间即可。 这是最简单的。 |
8
lcbp 1 天前
前端技术栈:vite vue electron uniapp threejs adonisjs leafletjs blender konvajs tailwindcss……
性价比最高的技术得是 Laravel ,使用起来非常舒服,开发效率非常高。 |
9
loading 1 天前
搭车问:
typescript 有没必要花时间学?现在似乎风向是嫌弃 ts 太重了,转 jsdoc 了。 |
11
cominghome 1 天前
AI ,哈哈
(半开玩笑半认真脸) |
12
moment082 OP @cominghome 现在应该有一大部分工资都应该是发给 ai 的
|
14
cominghome 1 天前
@moment082 别的地方不知道,我司倒是没说用 ai 替代程序员写代码啥的,但是有 1/3 的前端在搞 ai 在公司的落地了,主要是做一些辅助工具,目前反响还不错
|
15
moment082 OP @cominghome 我的意思是我在公司里面的大部分代码都是 ai 写的,工资应该发给 ai
|
16
zdw189803631 1 天前
我现在的观念是用到在学,不然什么都摸一遍,屁用没有,有那闲工夫,不如背两个英语单词
|
17
tomorrow092 19 小时 1 分钟前
![]( https://imgur.com/WSDy8d8)
这个 React 的问题有没有兴趣回答一下? |
18
crocoBaby 18 小时 22 分钟前
尤雨溪:你什么意思?
|
21
lizy0329 16 小时 48 分钟前
@CodeCodeStudy 什么年代了还 midwayjs ?
|
22
CodeCodeStudy 14 小时 59 分钟前
@lizy0329 #21 midwayjs 现在还在更新啊!不然呢,用什么好?
|
24
txzh007 9 小时 24 分钟前
感觉如果全栈的话 还是两门或者以上语言比较好.
|