2023 Logs 下半年
07-25 环境变量
关于环境变量 .env
和 dotenv
的问题,纯浏览器客户端的 JavaScript 没有 Node.js 的 process
概念,因此无法使用 process.meta.env
等变量
Vite 提供了一个解决方案,它内置了 dotenv,可以将 .env
文件的内容以明文形式复制到引用中 (import.meta.env.VITE_xxx
),这样在 vite build
后生成的 JavaScript 代码中可以访问这些变量。然而,不推荐将敏感信息放在客户端代码中,因为在浏览器端无法保密。(Vue 本身还是运行在客户端的,所以打包后同理)
使用反代
如果非要使用这些变量,可以启动一个 Node 服务端,客户端通过 fetch('/api')
发送请求,服务端路由解析后携带密钥请求目标 API,并将结果返回给客户端。这就需要实现一个反向代理 (Reverse Proxy) 来转发请求。使用像 Nuxt、Next 等支持客户端/服务端代码共享的框架会更方便
以下是一个使用 Express 实现简单反向代理的示例代码:
在上面的示例中,当客户端访问 /api
时,Express 服务器会将请求转发到 https://api.example.com
,并将响应返回给客户端
07-30 Serverless function
今天弹了个通知说之前用的腾讯云代理居然是 3 个月免费,后续按天收费…这只好转战到 Vercel 了
原来的那个用的是 Express 的代理中间件来转发的,但 Vercel 运行 Express 的方式有些奇怪。因为通常来说是要有 pnpm build 这样的指令来来部署运行 HTTP 服务的,但对于启动一个服务来说,只需要 node express.js
就行了。所以对于 Vercel 来说,并不能直接启动 node 服务,这是由它来接管了。它规定在 /api
目录下的文件都属于 Serverless Function,它以下面的形式来对请求作处理:
这样就要把原先的 express 方法转换过来了,照着文档 using express with vercel 改了一下就成这样了 (详见 Chilfish/proxy-ai):
这里不能用 app.listen
,必须要有导出能处理 (req, res)
的函数/对象,也不能放在 /express.js
然后 "build": node express.js
,这样 vercel 就因为一直在 listen 而不能结束 build 而无法部署
08-23 Weibo-Archiver
刷到了个 vite-monkey 的 vite 插件,突然就给来灵感了,这就能用 vue/vite 的那一套去开发油猴插件。于是就干起来了,记录在了 dev/weibo
09-05 首个 Issues 😶🌫️
也是在改着 Uniapp 的启动模板 ↓ 的时候,遇到了个很难受的热加载的问题,即便它用的是 vite。于是花点时间控制变量法排查问题并解决后,尝试着去提了一个 issue,第二天就有回应了 🥳
这还是首次为其它仓库提个比较有用的 issue hhh
09-06 Uniapp is bad 😣
emmmm 还是不可避免的 Uniapp 了,虽然还是蛮不想深究的,毕竟是在是太麻烦了。使用的是 uni-vitesse 作为启动模板
更新:后续发现实际上这个 Static 目录是没有问题的,只是因为图片的文件名包含了非 UniCode 字符,导致了编译错误…… 只要改为英文就能解决了……🫥
还没写很多,有一个点是 Static 目录在不同平台的表现是不一样的,需要像下面这样来检测…
而组件库方面,由于小程序的很多特性,只能用一些定制的组件库,挑来挑去还是使用 uview-plus 好了。而图标还是使用 UnoCSS 的方案
也还是再写再看好了…重点还不在这,这就是纯恶心人的东西 🤐
09-12 Nitro yes 🥳, Express no 😫
想着还有一个没填的坑是数据库那边的,于是就为 todo 启动了 MySQL+Express+TS 后端了。而且毕竟这学期还有一个 Spring Boot 要写,就顺便了,加上之后再填的后台管理系统,基本就填完了之前的小坑
ts + Node 第一个遇到的重拳是,要怎么运行啊…然后是打包 (?) 被 ts-node 的配置搞砸的情景还历历在目,就因为它默认是 CJS 而不是 ESM 的,特别麻烦。而像是 nodemon 这类的开发启动又依赖于 ts-node,总不能 tsc -w 再 nodemon 它吧…好吧这个坑还是得淌,毕竟之前就跳过了 node ts 的这一部分了 hhh
但期间想着打包的事情的时候,emmm 因为前端带来的习惯了,总想着打包。前端打包是为了压缩传输的体积和混淆代码,但在服务端就完全没必要了吧?后来我想的是,索然不用压缩,但可以转译为 js,并去掉开发依赖。这样一来服务器就能直接 node 运行,和不用下一堆生产版用不上的依赖了
说回来就是,正好在看着 VueUse 的源码,就看了看它是怎么打包发库的。发现它是先运行一个 /scripts/build.ts
脚本作预处理,再在里面调用 pnpm build:rollup
最终打包的。而我注意到它是直接运行 ts 的,用的是 tsx 工具,它直接是支持 ESM 的 ts 和 node,实在是大神器 hhh
在框框直写路由的时候,注意到 npm:mysql 这个包全传统回调写法实在是太不舒服了 (而且也没什么更新了),于是找到了个现代一点的替代品 mysql2。更实用和 Promised🥳 数据库服务商选的是免费的 TiDB 了,勉强用用还是可以的。其他很多方案还是要境外信用卡才能办理…
期间抱着超可维护性地想法,这抽离那聚合地,大致地写好了第一版。并终于地加了 auth 的路由中间件 (之前写的路由完全没往这里想,想着到时候再写好了 hhh,导致一直对中间件有种神秘的感觉 (写 Plugin 也是一样的感觉)),用的是 jose 库来写 JWS,即带签名的 JWT,一定程度上防止 Token 被伪造 (被偷了那还是没办法的)
终于,总算是写好了初版,但最大的问题就是,要怎么部署啊… Vercel + Express 虽然可行,但由于很多 js 历史遗留的问题,很难配置好在 Serverless Function 中用 ts (可以用,但就是一堆麻烦问题)。自建服务器感觉太麻烦,于是就找啊找一堆 Express Hosted Provider,还是很难方便免费地部署 express 上去…
想了再想,还是决定重构到 Nitro 上好了,它也是一个后端框架,支持部署到十几个服务商。记录在了 todo-ender/#1
我还是因为知道他是 Nuxt Server 部分的底层实现之一才了解到的,而且 unjs 这个组织十分神奇,Nuxt 依赖了许多他们的工具库。而且他们还将很多功能都抽离成单独的库,例如 Nitro 的网络服务依赖于 h3,监听 server 是他们的 listhen,useFetch 是 ofetch 等等
所以 Nitro 就相当于是 Nuxt 的 /server 部分,所以改写起来十分地舒畅 hhh。且得益于 “框架” 的特性 (总所周知 Express 还不算是一个框架),有很多像是基于文件的约定、hooks 等等,都可以很方便地利用起来
其中之一就是使用了统一的错误处理,它允许统一处理应用中抛出的错误 Nitro#errorHandler。这样我就这么想了,主要是一次次地写调用数据库等时的 try-catch 实在是太重复工作了,到时改起来会很麻烦,于是我干脆就不写 catch 了,在 nitroErrorHandler 中来处理这些抛出的错误,来统一错误信息和处理
其中有一个要注意的点是,如果是浏览器 UA 访问错误页面,它是会返回一个 HTML 的,而 curl 则是 json。这是因为它默认情况是视 UA 来处理 new Error
的返回体的,所以就要手动地将它转为 json 格式
我的做法是判断它的错误代码来分类的,好在 mysql2 和 jose 抛出的错误都有 code 字段,于是就能写成下面这样,然后再 switch case 就好了。这样就要写一个 creatMyError 之类的函数来抛出我们自定义的错误了
总体的体验下来就感觉 Nitro 实在是太又好了,Nuxt 生态圈实在是太 🥰🥰 了。之后就是拿 SB 写一遍来应付作业,和期待许久的 admin dashboard 了,todo 的前端也整合了过去 (见 09-16)
09-14 Kotlin 是幸福的 😎
还得是要学 Spring Boot 啊…但好在使用 Kotlin 是幸福无比的 😭
因为 Nest.js 和它实在太像了,数据库层面又让人联想到 Jetpack Room 的那一套,配置又梦回 Android,路由、MVC 等等,都把之前实践过的又整合了起来,想法十分地贯通
在数据库的实体类定义和解析方面有点小扯了一下,原因之一还是要找 Kotlin 的文档教程什么的还是有些绕,但还是找到了个专为 Kotlin 编写的 ORM:ktorm。使用 Kotlin 函数式的写法来写 SQL 操作,实在是太符合想象了,合鲤
再之后的,先鸽着了。回想这几星期并行这几个不同的项目,实在是有些难处理 hhh,但 antfu 简直是 😱😱
09-16 Nuxt is awesome 😭
怎么说呢,起因之一还是想配置一下 Vue 的自动路由,实在是不想新增一个页面就要去路由那里改一大串了,尝试简单手写一下基于文件的解析。虽然可以用,但拓展性实在是不强,许多 vue-router 都没法自定义。最后还是老实换回了 vite-plugin-pages 的文件路由库
这时候,todo 的后端也写得差不多了 (就是上面的 nitro 后端),正想整合一下,于是就很快糊了一个登录界面,和 /todo 的 meta: auth: true
。并写了个前置守卫的中间件,也是能很成功地拦截
但这时遇到了个经典的大问题:跨域 hhh… 按下面 CORS 的方法成功地解决了一些问题,但是生产环境怎么办捏…虽然也能去后端配 cors 的列表,但想想还是太憋屈了,于是重构到了 Nuxt,真香 hhh。记录在了 learn-vue/#1
当然,有很多 ssr 的问题还是要单独解决,特判和 ClientOnly 一把嗦就好了 😊
09-16 CORS 跨域代理
解决跨域的方法之一就是搭建一个不在跨域范围内的反代服务器,要同协议、域名、端口,所以通常就会将它映射在子域名或是根域名 /proxy
下,来反向代理转发目标服务器。(见 #使用反代)
Vite 可以在配置文件中设置开发代理,详见 vite proxy。这样,fetch /api/hello
的时候就被代理到了 http://localhost:3003/hello
了
但这只适用于开发环境,部署后的 SPA 模式只是纯 HTML,并没有 node 环境,所以并不能转发请求。要么使用 Vite+SSR 来配置路由,或是在服务器中单独配置
基于此,我还是换到了 Nuxt),这样生产环境也能代理了
09-19 Pull Request Merged 初体验
虽然早已广泛使用 pr 来管理自己项目的 commits,但还是第一次为别人的项目提交 pr😣😣,地址:v3-admin-vite/#133
这会正学着怎么写一个经典的后台管理系统,于是就找到了个看着还行的项目。在看源码的时候,被这拉风的代码风格给无语到了,立刻给它装了 eslint 试图美观一下,但还是挺难看的
正研究着路由权限的时候,/src/router/permission.ts
五层嵌套……他是怎么能忍的啊,于是花点时间按尽早 return 结束的原则改了改。想着既然都花时间了,为什么不提个 pr 贡献一下?于是就这么干了,建个新的分支,然后提交 pr,第二天就 merge 了,还是挺开心的 🥳🥳
09-26 api 状态码统一 200
看了篇知乎讨论说,其实后端的 Api 返回的状态码都设为 200 会更好,详见我们应该将所有的 API 都返回 200 的状态码
09-28 Exposed: Kotlin SQL Framework
在写 Kotlin Spring Boot 的时候,厌倦了 JDBC 或是 MyBatis 的繁琐,于是就找了个 Kotlin 友好的 ORM 框架 [Exposed] 来用。它的特点是使用 Kotlin DSL 来写 SQL,这样就能在编译时检查 SQL 语句的正确性,而不是在运行时才发现错误
使用下来的感受还是,不用写 SQL,而是用 Kotlin 的语法来操作真的是舒服很多 🥳
10-10
试试推特卡片
TODO:试着能不能 SSG 出来,但又不大想在 Vuepress 上再折腾太多……
㊗️ぼざろアニメ1周年!
— はまじあき🎸ぼざろ最新6巻発売中📖 (@hamazi__) October 8, 2023
これからも応援よろしくお願いします🎸✨
#ぼっち・ざ・ろっく pic.twitter.com/x9vfLoWe1W
10 月……
翻了下,想不到10月都干嘛去了,似乎就只有 chilpost-sb 和机器学习这回事……
11-03 Win11😎😎
两年下来,自带的 512G 有些捉襟见肘了,于是下了个致态的 PC005 1T 的固态 (虽然贵上了几十块,但老哥们都说这个稳),感恩长江存储 🙏🙏 1T 只要三百多,真香
然后想着,既然都换硬盘了 (轻薄本就一个固态的接口),为什么不顺便体验下 win11😍 巧的是,在下 win11 镜像的时候,恰巧发了新版本
要把积累的经验都用起来,于是装的是全英文版的,地区、语言什么的都用英文地区,至少能避免很多非 UniCode 字符的问题
换新硬盘的最大感受就是什么都变快了,读写有 3|2.3 G/s,休眠和恢复、内存交换等等都特别快 🥳
再就是有很多 win11 特有的功能。WSL2 开启 networkingMode=mirrored
就能与本机公用网卡,它的 localhost 就是本机的,再也不用端口转发之类的了。当然 WSA 也能玩上了,不过官方版必须设地区为美国才能装
当然……新系统也有一大堆时不时出现的小问题
11-23 又一个油猴爬虫插件
辅导员突然找我接了个他朋友那边的外包 😹 要我写个脚本帮他按格式批量导出那后台管理系统的数据……因为这个系统也是外包买来的,所以就没定制这个功能。他说上头要让他导出几万份数据……
具体的工作就是,截图一个表单、下载表单的附件文件,然后分类整理,完全就是重复性动作 🫥
我一听,好啊又是爬虫导出是吧,vite-monkey 启动!
做起来用不了多久,但最大问题在于,给特定 DOM 元素截图保存。虽然有 html2canvas 再 toBlob(),因为它是 SPA + ElementUI,得等数据加载出来才能截图。一开始的想法是 fetch 这个 html 然后给 DOMparser 解析,但它的数据是异步加载的,所以就没办法了
然后想着插进一个不可见的 iframe,然后再等。这个做法是完美可行的,但最大的问题就是内存泄漏……即便 remove 了 iframe,但它的内容还是会留在内存里,导致一次次的截图就会越来越慢,最后直接卡死了。必须重启标签页才能释放内存……
虽然有第三方的 HTML 截图库,但这个要登陆才有结果,而且试着尝试破解鉴权,但还是无果
突然间地,想到了可以利用跨窗口通信,直接在新标签页打开,截图之后,通过 postMessage 传回来。因为直接关闭了这个标签页,这样就不用担心内存泄漏的问题了,而且也能很好地控制截图的时机
接下来要做地就只是优化下 UI 和交互。但还是没做到测试齐全,考虑周到,还是根据客户的使用提 issues 来改 bug😹😹 直接一个用户即测试 (Customer as a Tester,CaaT) 的模式 🤣
当然对面还是很友好很有梗的,也很满意,最后还跟着辅导员去面基吃饭了 🥳🥳
12-02 WSA with Magisk
想着都是 WSA 了,不 root 怎能忍。但看了眼,似乎挺麻烦的,还得重新编译打包
但好在强大的社区已经帮办做好了 WSABuilds,直接下载就能用了 🥳
虽然真机还没 root 过,但先试用一下吧