Skip to content
/ leaa Public

Leaa is a monorepo restful CMS / Admin built with Nest.js (@nestjsx/crud, node.js) and Ant Design.

License

Notifications You must be signed in to change notification settings

SolidZORO/leaa

Repository files navigation

leaa-banner

Leaa (project 1d1h)

Build Status Codacy Badge

Leaa is a monorepo CMS (Content Management System) built with Nest.js, Next.js, and Ant Design.

Monorepo-Packages

  • leaa-api / backend (Nest.js + @nestjsx/crud + MySQL + Docker Compose)
  • leaa-dashboard (demo) / dashboard (React.js + Antd + MobX)
  • leaa-www / website (Next.js)
  • leaa-miniprogram (independence-repo) / wechat-miniprogram (Taro.js + Taro-ui + GraphQL)
  • leaa-app (independence-repo) / iOS and Android (expo + GraphQL)

Install

View the README.md of each sub-directory in packages. You may need to look at yarn workspaces first.

Dashboard (demo)

dashboard UI

dashboard-UI

Legacy

TODOS

TODOS

DEV SUMMARY

本来总结应该写在文末,但我感觉还是提上吧,起码不用看我唠唠叨叨一堆开发日志。

以前老想着自己写一个全栈项目试着打通 5 端,苦于没时间,一直拖着,写的时候还以为需要大半年,但没想到现在只花了一个半月就做好了,而且很多地方我还最求了最佳实践,总体而言还算比较满意。

项目初衷是想用 React 或者说主要是 JSX 的语法来做更多的事情,比如写小程序或者 App,而且现有的技术框架也支持我这种想法,拿着以前的已有经验配上一些较新的技术比如 GraphQL 就开始上路了。

apidashboardwww 这几个端上碰到问题不算多,但 miniprogram (小程序,下文简称 mp)app 上就没那么幸运了,因为他们都不是标准的 web 语言,类似 HTML 富文本 渲染这种在 web 上天然支持的功能,到了他们上面就变成 fuckingSelf 需要自己解析了,比如 a 链接,因为在 mpapp 中并没有 a 链接的说法,用户点击 a 后会发生什么完全由开发者自己决定,这和我以前开发的 「web 应用」完全是两种概念。倘若以前有过 App 开发经验,相信要躺的坑会变少许多。

说到坑,我觉得我这一手坑挖技能真是了得。RN 以坑多而红想必已人尽皆知,好,我选了。monorepo 的坑大家可能不了解,但的确也是能把人坑得死去活来的,好,我选了。用 TS 开发 RN 的坑不多,但也不少,好,我也选了。然后就变成了选择了这个 RN + monorepo + TS 超级大坑(哭),不过后面我还是一点点的躺了过来,实在佩服自己的耐心(摊手)。

为什么会选 monorepo 这种方式开发呢?我的初衷是 5 端共享 TS 的 interface 和一些可复用的配置,但是后来写 mpapp 的时候发现,由于他们的一些特殊机制,我没办法给他们共享。实际上 mpapp 算是和 monorepo 完全隔离的,如果后面我重构代码,我会把这些 「非标准 web 应用」单独放一个 repo,因为他们真的很难伺候,node_modules 也是自有一份无法共享,每份体积都很大。大到不是关键,关键是每次 yarn install 的时候非常非常满,CPU 狂飙感觉电脑都要起飞了。本来我是倾向于能用 yarn workspaces 解决的 mono 就不用 lerna,但因为这个问题我尝试着上了 lerna,可问题似乎没得到好转,只好作罢。这一次用 monorepo 真真切切的给到了经验,算得上是拳拳到肉的疼,也让我知道如何取舍 monomulti

好,如果现在让我写一个 5 端难度排行,我认为会是这样 mp > app > www > api > dashboard

为什么会把 mp 列为最难的部分?因为 mp 不单有很多私货,而且 devtools 也 bug 多得出奇,有时候我修一个 bug 修半天没好,结果重启一下 devtools 就好了,这个真的是要气吐血。而且因为我用了 Taro,很多新的功能比如 custom-tab-bar 没跟上,文档都没有,我自行摸索弄是弄出来了,但也花了不少时间。当然,如果你用 Taro 同时有 custom-tab-bar 这个需求,leaa 可能是目前全 Github 已有方案的最优解。

另外关于 www (Next.js v9) 我本来也有很多想说的,但随着时间流逝,这些想说的慢慢变消失了,而这种「不想说」并不是那种「难者不会会者不难」的不想说,而是因为 Next.js 坑太多,解决一个坑必定会引发另外几个坑,而且官方都没有什么最佳实践给你参考,都是一些简单的 example,一旦想要做一些复杂的功能,这种前后端都要处理的「SSR」的确让人有种「难言之隐」的感觉。随着每一次 Next.js 大版本的变动如 8to9,都会有很多断崖式的改动,没办法啦,zeit 的文化就是这样,只能用「一切的不如意都源自于自己不够强大」来安慰自己。

出于 monorepo 的原因,有非常多「文件名相似」的文件在一个项目里,很多时候有种被文件淹没的感觉,在找文件的时候很容易被干扰,即便是我放弃了用 Components/Filter/index.tsx 改为用 Components/Filter/Filter.tsx 去给文件命名,以求 cmd +。p,能快速定位到文件本身而不是目录,但也难以摆脱这种「文件地狱」的感觉。

本来说好写总结就不要不抱怨了,但现在看来多多少少还是有一些吐槽,Anywhere,从 DockerApi 再到 UI/UX,写 leaa 过程的确让我学到很多,对软件架构、开闭原则有了更深的了解,以前写项目觉得「编码」与「建筑」其实是做着同一件事情, 这次算是更深刻的体会到了。

目前 leaa 还有很多很多很多 bug,但这似乎不妨碍有需要的人通过 Github 上检索到 leaa 中对他们有用的代码,这也是我写 leaa 的初衷,以上。 2019-09-17 17:01 @ Guangxi Hezhou

DEV LOG

2019-08-01 23:39

从 git commit 可以看出,这篇 DEV LOG(开发日志)是现在才开始写的,项目本来叫做 1d1h,也就是一天一小时的意思,想着业余时间把之前写前后端的经验汇集起来,做个 Blog -> CMS -> Sohp 的开源项目,包括 API / Dashboard / Website / Wechat Weapp / React Native (iOS / Android),因为是一套 monorepo,类似 interface / entry 这些都是共用的所以感觉做成全平台也是一件很顺手的事情。

其实本来想早点写这个开发日志,但早期一大堆需要解决的问题,时间都用在开发上了,实在抽不出时间写记录,现在想想还真不应该这样,毕竟之前的一大堆问题如果记录下来了,其实就是隐形财富,虽然再次遇到了自己肯定懂如何解决,但就没办法 share 给其他人了。不过接下来的日志我会慢慢回顾就对了。

这里说一下我对 Dashboard 的理解吧,我觉得一个最小可用的的 Dashboard 应该包括。

  • 用户(登录 / 注册)
  • 角色
  • 权限
  • 文件上传
  • 广告
  • 分类
  • 文章
  • 设置

这几个模块写完基本上就可以拿来当 Blog 用了,特别是角色权限这块,如果有业务需求,基于这样的最小化的 Dashboard 开发基本上可以说也很简单了。我在以往的项目里处理权限已经很多次了,不过这次因为是 graphql,和之前的 restful 稍有区别,还是花了一些时间折腾的。

用 Nest.js 写了那么多的代码,其实算不上舒服,选用的原因其实还是看中了他的一整套范式以及武装到牙齿的 Typescript 支持。作者 @kamilmysliwiec 还是非常厉害的,Nest.js 的一些封装实现非常精妙,最重要的还与各种技术相结合,落地了很多业务场景,这点真的非常赞的。

dashboard 上技术选型时常见的 React + Antd,不过这次因为全面上了 hooks,包括 Apollo 都是最新的 hooks beta 版本,整个项目几乎见不到 Class,但在大规模使用 hooks 后,感觉代码长得实在难看,如果以前 Class 代码清晰度打 10 分的话,hooks 只能打 5 分。当然,最明显的应该是赚了一个代码 Fn 共享,换做是 Class,想要 share Class 的 Fn,还是挺麻烦的。

www 部分没得选,只能是 Next.js 了,其实之前我有自研过一套较为完备的 React-SSR,但为了顺应浪潮,加上 @Guillermo 神在推上天天天吹,忍不住还是入手了 Next.js。我开始写 www 的时候刚好赶上 Next.js v9 发布,这是一个从 core 就开始用 TS 重写的船新版本。本以为用起来会很顺利,但没想到还是坑了……

毕竟需要集成 Antd,即意味着,Client 自己的 pages 代码需要对 less 用 cssModule,Antd 则不用,Server 那边则是看到 less 就扔。所以官方提供的 withLess 插件最多只能管 60%,剩下 40% 支持不到位。本来像 Next.js,CRA 这种就是把 webpack 包起来,前端毒瘤真不想你碰,配一下都是炒鸡麻烦。

但,我想说一个框架在项目初期给你几倍便利,那么它便会在项目后期给你带来几倍麻烦。CRA 如此,expo 如此,Next.js 也不例外,都是黑盒。那么我必须在两个小时内写一个 100% 符合我预期的 withPlugin 来,不然项目就卡了。翻了翻 Github 想看看有没有解决方案,但很不幸, v9 刚出根本找不到相关代码,看起来,只能 fuckingself 了。我虽对 webpack 很熟,但这 Next.js 在 webpack 上加了薄薄一层黑盒,写 withPlugin 有种被淹没在未知的 context 海洋中,是种非常憋屈的赶脚,不过还好,最终半小时搞定。提了个自带 resolve 的 issue 趁没被人发现赶紧 close 掉。希望给碰到同样问题的伙计在搜 issue 的时候带点帮助,毕竟需要 Next.js + antd withLess 的人还是很多的,特别是国内。


2019-08-15 20:45

时间过得好快,转眼半个月,最近没给 leaa 写什么新东西。重点放在了阿里云 OSS 整合这块。想要实现这样一个功能:

  • Local 上传
  • OSS 上传
  • OSS 上传后备份到 Local
  • OSS 上传 @2x 图片后,生成 @1x 上传回 OSS
  • OSS 上传 @2x 图片后,生成 @1x 上传回 OSS 并备份到 Local
  • 删除 OSS 需要触发删除 @1x 和 @2x 文件,并删除 Local 中的 @1x 和 @2x
  • Local 和 OSS 是否开启均可配置
  • 如 OSS 开启,为保证用户上传速度,所有上传直接走 OSS

其中过程还蛮艰辛的,涉及到 Local 和 OSS 之间的一些交互,而且因为直接走 OSS,所有请求不经 API,变成了等待 OSS 的 Callback,必须保证任何一步没做完都不能动 DB,勉强达到了幂等。 其实如果上传都走 API,然后由 API 统一处理再 put 到 OSS 会简单非非非非非非非常多,我这么做主要是担心做某些活动的时候,如果涉及到上传文件,并发就会很大,服务器缓不过来。所以拿 OSS 先挡一下还是很有必要的。

基本上 www 和 api 以及 dashboard 就告一段落了。明天开始 miniprogram


2019-08-16 12:04

刚整理 package 的时候发现 React 升级到了 16.9.0,console 下一堆类似的 Warning: componentWillMount...,看了一下 React CHANGELOG 发现的确是大改,未来版本要废弃几个 lifecycle。由于 leaa-dashboard 依赖 antd,所以还是等 antd 发版消除了这些 warning,再升上去。目前 React 是锁在 "react": "16.8.6", "react-dom": "16.8.6"


2019-08-16 15:07

做了一个 Leaa Stack 的 Banner 放到 README 顶部,用图片描述使用的技术比文字好不少。另外提一下 Leaa 这个名字,这其实是我喜欢的一个法国女演员 Léa Seydoux 的名字,避免重名率过高,我在 Lea 后面多加了个 a。不过 LEAA 在 Google 最多的指向是 Law Enforcement Assistance Administration 美国一司法机构(笑)。


2019-08-17 11:21

刚在用 lint 在给项目做全面检测发现了几个 error,比较有趣的是 packages/leaa-dashboard/src/pages/Permission/PermissionList/PermissionList.tsx L159 这里,项目 .prettierrcprintWidth.eslintrc.jsmax-len 都设置成了 120,但这里 prettier 不报错,也不自动格式化,但是 eslint 和我说这里超 120 了。

我只好加了个 eslint-disable-next-line max-len,感觉很有可能他们其中一个是用了 > 一个是 >=,但是我去修改了两者的属性后发现不是这个问题,算了,先加个 max-len,目前只有一处是只有,标本不够就先不处理了。待日后这个问题多了再统一处理。


2019-08-17 14:16

虽然自己很注意 style code,也会用 IDE 配合 keymap 写 marco 套用 prettiereslint 规则做 format。但项目 public 之后可能会有 contributors 进来(不,不会的 hhh),觉得还是在 git commit 卡一下 code style 会比较好。

通常项目上一个 husky 就够了,但是 monorepo 文件那么多,每次 git commit 全 packages 所有文件都 eslint 必然会卡到爆,所以肯定是要配合 lint-staged 做最小化 eslint 处理的,只让此次 git stage 中文件去跑 eslint。

可是貌似官方没有给出太多针对 monorepo 的建议和范例。摸索了一番,发现其实也不麻烦,只是和 non-monorepo 不大一样而已。为了和 pacakge.json 解耦我还特意写成配置文件,大致长这样:

module.exports = {
  'packages/**/*.ts?(x)': ['prettier --write', 'eslint', 'git add'],
  'packages/**/*.(css|less)': ['prettier --write', 'stylelint', 'git add'],
};

试了一下,速度还是蛮快的。要有更好的最佳实践可能还得用一段时间才知道效果了。


2019-08-18 11:42

试了大概一个晚上的 Taro,感觉不是特别理想,为什么呢?首先我需要的是一个 React to 小程序 的框架,而且想要的是 ONLY 小程序,至于为什么是 ONLY,后面我会展开详细说明。

初步使用下来,感觉 Taro 感觉是一个集大成者,他身上的责任还蛮重的,需要兼容太多的 类小程序 环境,比如 支付宝小程序今日头条小程序 等…… 而且还要考虑兼容 RN 那不友好的 yoga CSS 引擎,团队还是非常不容易的,能做到这这个程度,我还是非常佩服的,这里必须先给个赞。接下来我讲一下我几小时下来大概的感触。

H5 端

完美!正常 Web 开发一样,没什么好说的。支持 HRM,支持 css module。不用关心 webpack,上来就能 run。不过有一点值得注意,就是如果想要兼容 RN,那就不能用 taro-ui 或是别的什么第三方 UI lib,只能使用内置的 @tarojs/component,这个限制感觉卡得比较厉害,期待 taro-ui 早日支持 RN

小程序端

也非常完美,说不上没什么不好的地方,run 起来后,打开官方微信 debug tools 顺利走起。唯一坑点是对 monorepo 支持不友好,当然这点也无可厚非,国内本来用 monorepo 的就少,用了肯定要自定义为「自己有能力解决 monorepo 上的任问题」的态度。我在 monorepo 下 run,遇到的是这个问题:

can't find module : ../../../node_modules/@tarojs/taro-weapp/

社区上也有一些人在提 issues 比如 需要 monorepo 支持,我的做法和他差不多,都是用 yarn wokespaces 的 nohoist 去做处理,只不过我的方案是只让 Taro 相关的模块保留在 sub-package 下,别的该提升还是提升,最大化 share 了 modules:

{
  "nohoist": ["**/@tarojs/**"]
}
React Native 端

package.json 里的 有 dev:rn,我就 run 了,结果是好的,看到提示编译成功,但就没有下文了…… 然后去官方 docs 看了下,感觉略复杂,那这和单独折腾一套原生 RN 开发有什么区别?而且依赖 Taro 的话,RN 版本锁在 0.55.4,天啊!这和官方目前 0.60.x 的版本号相距甚远,要知道 RN 每一个版本迭代都是质的飞跃,如果用上 0.60.x 还能在 Android 上赚一个 Hermes,效率也是大幅提升。另外还有一个让我顾虑的是,用上RN@Taro,意味着只能使用 @tarojs/component 这个 UI lib,也就是意味着要放弃掉 NativeBaseShoutem 这两个在 RN 上相对优质的 UI lib。

嗯…… 综上考虑,如不是一心想为了节约成本和时间,想着 一套代码多处运行 ,目前还是建议放弃 RN@Taro ,如果要说一个最佳的切入时机,我认为是至少 taro-ui 支持了 RN ,当然,这个代价实在太高,官方永远不去做支持也是非常有可能的。

好啦回到正题,我使用 Taro 的初衷一开始就是用来 ONLY for 小程序的,所以对于目前的情形我觉得「一切 OK」。leaa-app 那边还是 RN 或者 expo 处理就好,毕竟坑基本上在以往项目踩完了(笑)。


2019-08-18 22:18

记录一下今天白天用 Taro 的心得,真是满满的心酸啊……

  • 首先,比较痛苦的是不支持 @apollo/react-hooksreact-apollo!也就是说,任何 Apollo 官方的包都不可以用了!不能 useQuery<Query> 都不让,用就给你报 hooks 那经典的错误 Invariant Violation: Invalid hook call. 结果是直接用写好 export apolloClientapolloClient.query(),这真是一夜回到解放前啊!

  • 本来想着方便,在 H5模式下 debug,apolloClient 这种方式能跑起来已经很开心了,没想到…… 小程序 模式弹 error 了,说 fetch is not found globally and no fetcher passed, to fix pass.... 查了下资料说是 「微信小程序在某一次升级中, 移除了全局的 fetch」这……,还好,马上找到了前辈写的 lib wx-apollo-fetcher。整个库就几行:

    return new Promise(resolve =>
    wx.request({
        ...
        complete: ({ data, statusCode, errMsg }) => resolve({...})
    }))
    

    然后在 HttpLink 那边替换一下变成 fetch: wxApolloFetcher 就好了。万万没想到微信还会做这种断崖式更新,真是骚操作。

  • 再就是路径 alias 的问题,官方 issues 这贴讨论得最激烈,我看完后试了,依然无解。这里的无解是 小程序 端无解,H5 端是好的。这…… 我这好歹是 monorepo,要是不能 share @leaa/common 包里的代码,那会变得很尴尬。行吧,我先不复用,忍忍。

本以为经历过 RN 的开发已是煎熬,但这次…… 哎,不说了,怪自己用的技术太新(啪)。


🔰 READING MORE...