Zeka 的记事本

2020 年 12 月
记 React Context 造成的死循环
20201229 日说: 前端 React

使用 React context 可以方便的跨组件传值但很容易滥用

参照 gatsby-plugin-layout 的方式。但是出现了死循环。报错说明是重复 setState 所致。

原因是 Provider 与 Comsumer 恰好是父子组件关系,子组件通过 Context 调用了父组件的 setState 方法。调用后触发了父组件的更新,然后再次触发了子组件的 setState,最终导致了无限循环。

解决方法为使用 if 判断,如果不同,则触发 setState,这样就只会调用一次。

如果是挂载在组件上的回调则不会触发此循环。

由于 setState 是异步,所以在 context 多个子组件多次使用 setState(常见于 context)可能会导致数值不正确。这是因为两个回调拿到的可能是同一个原始值,从而导致更新出现问题。

一个不保险(但是 work)的方法是在你期望延后执行的 setState 上包裹一层 setTimeout。

使用 Cloudflare Worker 制作 Steam 展示页面
20201228 日说: 网络

参考 这篇

为了强行使用 Serverless,我使用 cf 的 worker 反代了 steam 的 api。

原理为在 worker 上写 fetch,然后直接将 worker url 作为 api。

这么做的原因在于 Steam API 的调用需要 apikey 与 userid,这两个按道理来说似乎不是应该随意公开的信息(其实能获得的东西有限,而且没有修改权限)。

结果发布在:https://flag.zeka.cloud/steam

由于 PWA 的缓存问题,你可能需要多刷新几次才能看到内容。

/static/cfd6c67a74848d7f10efe4bd003a909e/82adf/photo_2020-12-28_02-01-07.jpg
my pic test
20201223 日说:

please view it both on pc and pe

/static/1b69d538069873a3066d1a632a967ab1/fbe8b/c0a26ead3432d3fe481206e006430505.jpg
/static/17a662f5ca9d58b53ab30ff8abc48b2f/54411/img_20200612_221921.jpg
/static/84c3f4ea2a2b0c35b1be3097f42661c6/40740/602734b4c02af78b2a2280d7df960e7a.jpg
记一次 Windows 上 eGPU 的 24 错误恢复
20201218 日说: Windows

外接显卡扩展坞一时爽,断开火葬场。网上似乎也没有提到如何才算正确断开 eGPU。

使用英伟达的 RTX2060S,扩展坞用的是 Akitio Node (非 Pro)。

于是保险起见,我首先选择 “断开 GPU”,然后再弹出 USB,确认断开后,关闭电脑,再关闭扩展坞电源。虽然目前外设基本支持热拔插,但是这样显然更保险。

这样会导致 Windows 认为你手动禁用了外设。下次再插入时,必须进入设备管理器,找到你的显卡(一般在“显示适配器”里面),手动打开。

但是有时还是会出问题,我最常遇到的问题是:

该设备不存在、运行不正确、或者没有安装所有的驱动程序。 (代码 24)

这可能是由于断开显卡不正确导致的,Windows 识别了错误的外设,从而导致雷电口出现问题。这种情况下不论是禁用再启用设备,还是更新驱动,重启都是没用的。

正确的做法是选择卸载该设备,并跑一次 Windows 更新(必须)。卸载设备使得这个雷电口暂时不可用。不过 Windows 的自动更新能检测到接口,从而恢复错误。

更新完成后,应该可以愉快的使用了。

/static/3602665874675b481495d7b91b771144/dd13c/photo_2020-12-16_18-00-07.jpg
年轻人的第一个 Github Actions
20201216 日说: 网络

写了一个简单的 Githb Actions,每次 pull 都自动将 Next.js 部署到服务器并运行。稍微记录下使用到的 actions:

记一次 swarp 安装的错误
20201215 日说: Linux

安装的是 astromatic 的图片处理软件 swarp,不是 X server 的 swarp,与之类似的还有 docker。安装环境为 Ubuntu20。

官方 显然是标准的科研大佬,对其他 trival 的东东看不上眼。响应式没有不说,证书直接拿的 DNS 服务商提供的,关键是图片也没有加 TLS。这明显的体现在官方为 Ubuntu 配置的 source 使用的是过时的 TLS1.0/TLS1.1 协议,直接导致 apt source 不能使用。

没办法,只能从源码安装了。直接从首页下载的 source 版本过低能用才不正常。查了许久,终于发现官方在极为隐蔽的角落放置了一个 Github 仓库。

按照说明安装即可:

# 先无脑来一下
sudo apt update
sudo apt install build-essential git 
git clone https://github.com/astromatic/swarp.git && cd swarp
./autogen.sh
# configure 很可能挂,缺啥补啥即可。
./configure
make
# 测试
./src/swarp
# swarp [image 1] ... 好了
sudo make install
记一次 netcat 不同来源导致的错误
20201214 日说: Linux

环境为 Arch Linux,使用 pacman 安装。

为了让 SSH 走 SOCKS5 代理,需要使用 nc(netcat) 指令。画风大概这样:

Host name
  Hostname your.name
  User yourUser
  ProxyCommand nc -X 5 -x 127.0.0.1:port %h %p

netcat 是很强大的武器,可惜由于太菜只能用到最简单的功能。

自然要用无敌的 pacman 安装啦,快乐的输入 sudo pacman -S netcat。但是安装的时候出现了选择来源的提示,让你选择 bsd 版本或者 gnu 版本(默认是 gnu 版本的)。

结果坏事了,这个 nc 指令既不能识别 -X 指令,对 -x 的解析也是错误的(出现 Error: Couldn't resolve host "127.0.0.1:<port> 报错)。

印象中还有这个问题的是 unzip。由于恶臭 Windows 国内使用恶臭的国标编码,所以任何创建的压缩包默认是非 Unicode 编码的。而 .zip 文件本身没有任何用来标识编码的符号位。这直接导致了 Windows 压缩包在 Linux 乱码 虽然 unzip 官方知道这个问题,但是为了惩治不遵守规范的 Win,故意不为 zip 添加指定编码选项。在国内遇到中文编码,还得安装其他版本的 unzip。更好的方法是一起 boycott Windows

输入 -h 指令,发现根本没有 -X 选项。

思考了一下,决定安装 bsd 版本的 netcat。

sudo pacman -Qs netcat  # 查看包名
# local/gnu-netcat 0.7.1-8
sudo pacman -R gnu-netcat  # 移除
sudo pacman -S netcat
# 选择 bsd 版本即可
# 或者直接 -S openbsd-netcat
sudo pacman -Qs netcat
# local/openbsd-netcat 1.217_2-1

然后问题解决了。这不是第一次遇到这个问题,之前使用 rename 的时候遇到不同版本导致指令不同的问题。

查了一下资料,发现 nc 有很多变种,也就是我们安装的 nc 很少是原版的,常用的变种除了 OpenBSD 之外,各大社区也大多有自己变种。

记配置 uwsgi 的坑
20201214 日说: 网络

如果用 python 部署服务器,网上绝大多数教程都是告诉你使用 uwsgi。uwsgi 允许你启用多个线程来调用你的 Django 或者 Flask 应用,性能可以得到很大提升。

问题在于,这玩意配置不是那么容易的。下面的部署环境为 Debian 或者 Ubuntu。

apt 可以直接装上 uwsgi,但是 uwsgi 不是专门为 python 准备的,要让 uwsgi 能正确运行我的 python 服务,我们还得安装 python 插件:

# 如果你使用的是 python2,那么应该安装 uwsgi-plugin-python
sudo apt install uwsgi uwsgi-plugin-python3

之后就是书写 uwsgi file,坑点已经标记出来了:

[uwsgi]
socket = 127.0.0.1:8000
chdir = /your/workplace
wsgi-file = /your/flask/entry/server.py
# flask 中 app = Flask() 对象
callable = app
processes = 1
master = true
# 插件,告诉 uwsgi 需要使用 python,需要指定 python 版本,下面指定为 3.7.*
plugin = python37
threads = 2
daemonize = uwsgi.log
pidfile = uwsgi.pid
buffer-size=32768

插件装好就可以了。

谈一谈 node-sass 的坑
2020128 日说: 前端

这是在 Linux 开发的经验,可能不太适用其他环境。

使用框架开发,就离不开 node 环境,就离不开 npm 包管理器。 由于众所周知的原因,使用 npm 非常容易卡死,如果你在网上搜索,大家给你的解释是:换源。

npm config set registry https://registry.npm.taobao.org

在大部分情况下,这足以解决问题。但是任何使用过的人都知道,问题往往没有这么简单。网上描述的换源即起飞的情况似乎并没有出现。npm 依旧卡死,完全不想理你。

对此的解决办法很简单:使用 yarn。yarn 最大的特点是允许多线程下载包,所以你安装包的速度是 npm 的几倍。而且 yarn 的安装界面比 npm 更清晰,指令语义化更好,更符合逻辑(yarn 默认安装到 dependency,符合直觉)。关键是,yarn 多线程下载还附带很强的超时重试功能,这极大的方便了弱网(确信)环境的安装。

但是,这还只是痛苦的开始。对我来说,主要是和 node-sass battle。没错,node-sass 日常翻车,而且最近的 5.0.0 更新更是出现了大量问题。

node-sass 底层的 SASS 编译器是 C 写的,也就是说需要如 python2 之类的编译环境。对于正常 Linux 环境,往往自带,但是在 Docker,其他平台来说,就不是那么容易满足了。而且,源码编译用户体验也不好

好在 node-sass 只需要适配 node 环境,为此官方提供了编译好的二进制。这也带来了问题:二进制是依赖 node 编译的。如果 node 版本改变,就需要重新编译。

官方 给出了适配的环境列表。

举个例子,如果你的 node 版本为 15,node-sass 版本为 5.0+,那么官方提供好了编译好的文件,安装 node-sass 的时候就会直接拉取文件,跳过编译过程。反之,如果你的 node 版本为 15,而 node-sass 版本为 4.14,那么就不符合官方要求(只有 node-sass5 支持 node15),这种情况,如果你要安装,就会拉取源码在本地编译,这就需要大量依赖。

现在问题是,Arch linux 会默认更新到最新版本,所以我现在的 node 版本是 15.3,需要 node-sass5 以上才能支持。而对于大部分项目来说,node-sass 是不可能升级到 5 的,因为升级到 5 意味着不支持 node14 及以下,而他们有着大量用户。

所以,全局 node 版本为 15,项目版本 node-sass 保留在 4。所以每次都需要重新编译(当然,缓存可以帮大忙),这也极大的拖慢了安装速度。

但是对 docker,强求安装环境完备几乎不可能,为此需要根据 node-sass 版本选择 node 版本的 docker。这样就能直接利用官方编译好的镜像。

你以为这就完了么? Too Simply!

编译好的二进制文件不小,要命的是他不是 npm 的包,所以前面设置的淘宝镜像不起作用。你将直接从国外拉取,于是,,,

但是淘宝也料到了这一点,于是贴心的提供了 node-sass 源,简单来说,你只需要这样:

yarn config set sass_binary_site http://cdn.npm.taobao.org/dist/node-sass -g
# or
export sass_binary_site=http://cdn.npm.taobao.org/dist/node-sass

这一点 官方也贴心的给出了

简单来说,选好 node 版本与 node-sass 版本,不要随意升级(不升级,就永远不会出问题.webp)。

规范并不总是实用
2020123 日说:

之前写了一个简单的作业,通过 worker 跑计算物理的作业。原理很简单,但是由于我希望使用我比较熟悉的东西(比如 ts, sass),所以用到了我自己写的 webpack 框架

但是我错误的加上了 airbnb 的 ts 规范。规范本身没有问题,但是在使用上遇到了大问题。

airbnb 规范太严格了,几乎写不了程序,或者说回到了写 C 的时候,甚至更过分。

在我磕磕绊绊写完之后,我就更新了我的 repo,删除了 tslint。对于大型团队来说,好处是显而易见的,但是对希望快速开发的个人开发者来说并不适合。或者说,这是一种“过早优化”。

当然通过遵守 airbnb 规范也学到了很多,比如使用单引号或模板字符串表示字符串,以免与 JSX 中的 HTML 标签双引号冲突;比如不改变函数中引用类型参数(总是使用 Object.assign 方法或者解构创建新对象,不直接操作参数),从而避免副作用。当然,还有从 C 遗传下来的 legacy:最后一行留空(Python 也有类似规范)。

我没有看 airbnb 文档,但是显然它的一系列操作是和 fp(Functional Programming) 相关的。只能说 js 意外的是一个实践 fp 的好地方(不谈论语言特性,只谈论社区)。这反倒是与它的起源(Java)相反,也算挺有意思了。

记一次 feedparser 更新导致的错误
2020121 日说: Python

一直将 RSSHub 作为爬虫源。为了解析,使用了 Python 的 feedparser库。

写好后就挂在服务器上,也没出啥错误。后来打算换一台服务器,于是将爬虫挂到了另一台服务器上。没想到居然出现了问题。排查后发现,居然是因为 feedparser 更新了!更新后会自动对敏感字符串进行转意,于是出现了这样的问题:

# original
https://pbs.twimg.com/media/EoEtzXoUcAAkm3c?format=jpg&name=large
# processed by feedparser
https://pbs.twimg.com/media/EoEtzXoUcAAkm3c?format=jpg&amp;name=large

多了一个 &amp;。要修复直接添加一个 .replace("&amp;", "&") 就好了。

事后查看了一下 feedparser 仓库,发现从 16 年基本停止更新的库居然恢复更新了。原来版本为 5.2.1,更新后到了 6.0.2

只能反思自己以前依赖管理没做好,要是当时用了 pip freeze,也不会出现这种问题。

看来还是得养成使用 virtualenvpip freeze 的习惯。只能说相比 NPM 的包管理,我过于信任 pip 了。