以前一直没好好学过 Python logging,最近学了一下觉得设计得挺灵活的,完全够满足我的各种需求:
1. 日志可以不是字符串而是对象,自己序列化保存。
2. 可以用 JSON / YAML 在运行期间随时修改日志管线。
3. 默认会采集线程名、task 名等信息,想记录的话自定义 Formatter 就行。
4. 想附加其他上下文信息只需要自定义 Filter。
5. 自带 rotating file、syslog、SMTP、HTTP 等各种 Handler,还可以配置攒多条后按特定条件触发一起发送的逻辑。
6. 可以接管 Python warnings。
7. 日志级别选项可以自定义。
8. 开销较大的计算基本都会只在必要时才做,并有缓存。
1. 日志可以不是字符串而是对象,自己序列化保存。
2. 可以用 JSON / YAML 在运行期间随时修改日志管线。
3. 默认会采集线程名、task 名等信息,想记录的话自定义 Formatter 就行。
4. 想附加其他上下文信息只需要自定义 Filter。
5. 自带 rotating file、syslog、SMTP、HTTP 等各种 Handler,还可以配置攒多条后按特定条件触发一起发送的逻辑。
6. 可以接管 Python warnings。
7. 日志级别选项可以自定义。
8. 开销较大的计算基本都会只在必要时才做,并有缓存。
👍3
@zzh1996 问我为什么在不同云服务商的 Debian 11 的机器上安装 unattended-upgrades,有的会自动创建 /etc/apt/apt.conf.d/20auto-upgrades,有的却不会,导致并没有启用自动更新。
这个行为受 debconf 数据库中的一个选项控制,相关信息存储在 /var/cache/debconf/{config,templates}.dat,两个文件都是纯文本。
执行 apt source unattended-upgrades 会下载这个包的源代码:
- debian/templates 有一个选项 enable_auto_updates,默认值为 true。
- debian/config 会设置这个选项的值,但因为优先级是 low 所以默认不会询问用户。
- debian/postinst 会从数据库查询这个选项的值,决定是否创建配置文件。
在腾讯云和 Hetzner 提供的 Debian 11 系统中,虽然没有预装 unattended-upgrades 包,但 debconf 数据库中奇怪地有这个选项,其值为 false。这是通过 debconf-set-selections 工具做到的,它专门用来在安装包之前设置各种选项(称为 preseed)。按我的理解,在 config.dat 中搜索 seen 可以看到所有被 preseed 过的值,在 templates.dat 中搜索 fake 可以看到所有被 preseed 过但没被真的安装用到的值。
我猜或许曾经某个系统会自动安装 unattended-upgrades,但云厂商没想默认启用,所以 preseed 成了 false,后来这个包不会被自动安装了,忘了移除相应配置?
这个行为受 debconf 数据库中的一个选项控制,相关信息存储在 /var/cache/debconf/{config,templates}.dat,两个文件都是纯文本。
执行 apt source unattended-upgrades 会下载这个包的源代码:
- debian/templates 有一个选项 enable_auto_updates,默认值为 true。
- debian/config 会设置这个选项的值,但因为优先级是 low 所以默认不会询问用户。
- debian/postinst 会从数据库查询这个选项的值,决定是否创建配置文件。
在腾讯云和 Hetzner 提供的 Debian 11 系统中,虽然没有预装 unattended-upgrades 包,但 debconf 数据库中奇怪地有这个选项,其值为 false。这是通过 debconf-set-selections 工具做到的,它专门用来在安装包之前设置各种选项(称为 preseed)。按我的理解,在 config.dat 中搜索 seen 可以看到所有被 preseed 过的值,在 templates.dat 中搜索 fake 可以看到所有被 preseed 过但没被真的安装用到的值。
我猜或许曾经某个系统会自动安装 unattended-upgrades,但云厂商没想默认启用,所以 preseed 成了 false,后来这个包不会被自动安装了,忘了移除相应配置?
👍2
Python traceback 格式化一个异常的调用栈时,可以要求带上每一个栈帧的所有局部变量。这对于事后理解异常是怎么发生的很有帮助,许多软件(例如 Django 在 debug 模式中)也有类似的设计,会显示局部变量。
然而,Python 3.12 之前,这个功能不会处理 repr 局部变量时产生的异常。只要任何一个栈帧的任何一个局部变量无法 repr,就会失败并报错。在我看来这是不可理喻的,因为服务器软件有需求捕获所有异常,记录尽可能丰富的调试信息,然后恢复并继续运行,这要求捕获异常和记录逻辑必须保证不产生新的异常(除非是内存不足等本来也没法继续运行的严重错误)。
异常处理、日志记录等功能都应当尽可能防御所有异常,在异常时执行一些备用逻辑,例如格式化失败时可以记录“发生了无法格式化的异常”。如果这些功能本身能抛出异常,导致服务器程序停机,让用户怎么办呢?只好自己在外面再手写一套保证不抛出异常的备用逻辑。
2021 年 3 月有人提这个 issue[1],2022 年 7 月改了[2],2023 年 10 月终于在 3.12 发布了。issue 中开发者反对的理由主要是认为 repr 抛出异常是程序自己的问题,并且 Python 不应该静默忽略异常,怎么说呢……有一些道理,但站在服务器程序开发者的角度感觉挺坑的。
[1]: https://bugs.python.org/issue43656
[2]: https://github.com/python/cpython/pull/94691
然而,Python 3.12 之前,这个功能不会处理 repr 局部变量时产生的异常。只要任何一个栈帧的任何一个局部变量无法 repr,就会失败并报错。在我看来这是不可理喻的,因为服务器软件有需求捕获所有异常,记录尽可能丰富的调试信息,然后恢复并继续运行,这要求捕获异常和记录逻辑必须保证不产生新的异常(除非是内存不足等本来也没法继续运行的严重错误)。
异常处理、日志记录等功能都应当尽可能防御所有异常,在异常时执行一些备用逻辑,例如格式化失败时可以记录“发生了无法格式化的异常”。如果这些功能本身能抛出异常,导致服务器程序停机,让用户怎么办呢?只好自己在外面再手写一套保证不抛出异常的备用逻辑。
2021 年 3 月有人提这个 issue[1],2022 年 7 月改了[2],2023 年 10 月终于在 3.12 发布了。issue 中开发者反对的理由主要是认为 repr 抛出异常是程序自己的问题,并且 Python 不应该静默忽略异常,怎么说呢……有一些道理,但站在服务器程序开发者的角度感觉挺坑的。
[1]: https://bugs.python.org/issue43656
[2]: https://github.com/python/cpython/pull/94691
GitHub Actions 的日志的安全模型怎么好像很多人都觉得没问题?
- public repo 的日志都是公开的
- 在 secrets 中的字符串如果在日志中出现就会被隐去
- GitHub 认识的几种凭据格式在日志中出现就会被隐去
- 输出 ::add-mask::this-is-a-secret 可以告诉 GitHub 这也是一个需要隐去的字符串
- 更不放心的话可以重定向到 /dev/null,但坏处是也没法看到输出了
- 很多并不严格算秘密/凭据,但可能会想保密的信息,例如 AWS ID、region、存储桶名等,几乎不能指望可以保密
- public repo 的日志都是公开的
- 在 secrets 中的字符串如果在日志中出现就会被隐去
- GitHub 认识的几种凭据格式在日志中出现就会被隐去
- 输出 ::add-mask::this-is-a-secret 可以告诉 GitHub 这也是一个需要隐去的字符串
- 更不放心的话可以重定向到 /dev/null,但坏处是也没法看到输出了
- 很多并不严格算秘密/凭据,但可能会想保密的信息,例如 AWS ID、region、存储桶名等,几乎不能指望可以保密
1
Telegram 新推出了给 channel post 用 star 打赏的功能,和 reaction 很像,但是:
- reaction 对频道主或其他订阅者都是匿名的
- star 打赏对频道主不匿名
- star 打赏可以选择要不要对其他订阅者匿名
- star 打赏可以自定义数量,不像 reaction 每个 emoji 每人最多点一下
- reaction 对频道主或其他订阅者都是匿名的
- star 打赏对频道主不匿名
- star 打赏可以选择要不要对其他订阅者匿名
- star 打赏可以自定义数量,不像 reaction 每个 emoji 每人最多点一下
最近终于尝试了一下 Hetzner Cloud,我简直吹爆!
- 非常便宜,性价比远超竞争者,2 核 4 GB 每月不到 4 美元
- 只需要关机就能升降配,不像有的云只能销毁重买机器
- 有 rescue 功能,可以引导一个临时系统,方便对硬盘做操作
- 有挂载 ISO 和从 ISO 安装系统的功能(用 web console)
- 每台机器免费给 IPv6 /64,可以随便绑定地址使用,我从没在别的云上见过这样的,都是每台机器只能绑 1 个或很少几个 IPv6 地址。再也不需要 Nginx 做分流了,可以直接不同服务绑到不同地址,还可以每个 docker 直接拿到自己的地址而不用 NAT
- 没有严重的丢数据/downtime 之类的负面记录
坏处:
- 地域选择比较有限,欧洲连各种地方延迟都有点高
- 硬盘是本地 RAID10,和 DigitalOcean、Linode 等类似,没有异地冗余,机房起火之类的意外可以导致数据丢失
- 比较难注册到账号,很多人上传身份证明后立刻没有理由地被 ban(不开代理,用不同 IP 和邮箱重试,可能可以成功,仅供参考)
- 非常便宜,性价比远超竞争者,2 核 4 GB 每月不到 4 美元
- 只需要关机就能升降配,不像有的云只能销毁重买机器
- 有 rescue 功能,可以引导一个临时系统,方便对硬盘做操作
- 有挂载 ISO 和从 ISO 安装系统的功能(用 web console)
- 每台机器免费给 IPv6 /64,可以随便绑定地址使用,我从没在别的云上见过这样的,都是每台机器只能绑 1 个或很少几个 IPv6 地址。再也不需要 Nginx 做分流了,可以直接不同服务绑到不同地址,还可以每个 docker 直接拿到自己的地址而不用 NAT
- 没有严重的丢数据/downtime 之类的负面记录
坏处:
- 地域选择比较有限,欧洲连各种地方延迟都有点高
- 硬盘是本地 RAID10,和 DigitalOcean、Linode 等类似,没有异地冗余,机房起火之类的意外可以导致数据丢失
- 比较难注册到账号,很多人上传身份证明后立刻没有理由地被 ban(不开代理,用不同 IP 和邮箱重试,可能可以成功,仅供参考)
👍4
北京环球影城
门票:需要提前买票和选日期,有各种门票可选,最近周四到周一晚上有特别活动,这些日子可以选全天票或者仅晚上的票,周二周三可以选全天票或者半天票(14 点至 20 点),另外还有 1.5 天票之类的选择。我买的是半天票,每人 316。官方微信小程序做得不怎么样,买票流程都能遇到 bug,只好去美团买。
价格:门票含所有大型项目,只要愿意排队就随便玩。里面有一些小的游乐项目是收费的,30-50 元一次。一个人吃到中等饱的程度大概 100 元。纪念品大概参考:头饰 100 多,巫师袍 800 多,巫师棋 2000 多。
入园:环球影城外面有一个叫城市大道的免费区域,可以比买票的入园时间早半小时来逛外面,然后准时进环球影城。周二 14 点时入园很快,几乎不用排队。
时间和步行量:园区内部不算大,但从上下车的地方到园区还有点远。我 13:30 下车,中间在园区吃饭,19:30 左右开始感觉脚有点痛了,20:10 开始离开,20:50 上车,总共刚好两万步并且比较累了。
设施:感觉各种设施挺好的,很多细节也都很讲究,例如卫生间密度很高,都提供免费饮用水,游乐项目排队过程中也有饮用水,排队前能看到估计等待时间。无障碍做得很好,游乐项目上下客区域也够大够方便。
游乐项目:大型项目(十几个)都是免费的,但要排队,我玩的基本都是等待 5 或 10 分钟,最热门的会有 20 或 30 分钟,微信小程序上可以看到所有项目实时等待时间。排队过程中可以看到一些有趣的东西,如果不排队的话反而快速走过去来不及看。很多项目都是按照 4 人一组设计的,工作人员会尝试凑满,不太会有 2 人可以单独拿到一排/一个座舱的情况,但可以尝试去抢最外侧之类的座位。3 人找不到 1 人来凑倒是比较常见。
霸天虎过山车:我认为最猛的过山车,几乎所有人都会持续叫
鹰马飞行:我认为第二猛的过山车,几乎所有人都会持续叫
飞越侏罗纪:不太刺激的过山车,只有两下有点剧烈的加速,但很短,少数人会叫一下
哈利波特与禁忌之旅:类似那种座椅会旋转和小幅移动的电影,有非常短暂的失重或加速,但没有剧烈位移
侏罗纪世界大冒险:坐车沿轨道走
神龙大侠之旅:功夫熊猫主题,坐船沿轨道走,会从高处掉落一下,第一排会有一点水溅到
奥利凡德:选一个幸运观众互动,其他人观看
灯光,摄像,开拍:观看
灯影传奇:旋转小飞机,座舱内 2 人向前,2 人向后,互相面对面
炫转武侠:旋转木马
门票:需要提前买票和选日期,有各种门票可选,最近周四到周一晚上有特别活动,这些日子可以选全天票或者仅晚上的票,周二周三可以选全天票或者半天票(14 点至 20 点),另外还有 1.5 天票之类的选择。我买的是半天票,每人 316。官方微信小程序做得不怎么样,买票流程都能遇到 bug,只好去美团买。
价格:门票含所有大型项目,只要愿意排队就随便玩。里面有一些小的游乐项目是收费的,30-50 元一次。一个人吃到中等饱的程度大概 100 元。纪念品大概参考:头饰 100 多,巫师袍 800 多,巫师棋 2000 多。
入园:环球影城外面有一个叫城市大道的免费区域,可以比买票的入园时间早半小时来逛外面,然后准时进环球影城。周二 14 点时入园很快,几乎不用排队。
时间和步行量:园区内部不算大,但从上下车的地方到园区还有点远。我 13:30 下车,中间在园区吃饭,19:30 左右开始感觉脚有点痛了,20:10 开始离开,20:50 上车,总共刚好两万步并且比较累了。
设施:感觉各种设施挺好的,很多细节也都很讲究,例如卫生间密度很高,都提供免费饮用水,游乐项目排队过程中也有饮用水,排队前能看到估计等待时间。无障碍做得很好,游乐项目上下客区域也够大够方便。
游乐项目:大型项目(十几个)都是免费的,但要排队,我玩的基本都是等待 5 或 10 分钟,最热门的会有 20 或 30 分钟,微信小程序上可以看到所有项目实时等待时间。排队过程中可以看到一些有趣的东西,如果不排队的话反而快速走过去来不及看。很多项目都是按照 4 人一组设计的,工作人员会尝试凑满,不太会有 2 人可以单独拿到一排/一个座舱的情况,但可以尝试去抢最外侧之类的座位。3 人找不到 1 人来凑倒是比较常见。
霸天虎过山车:我认为最猛的过山车,几乎所有人都会持续叫
鹰马飞行:我认为第二猛的过山车,几乎所有人都会持续叫
飞越侏罗纪:不太刺激的过山车,只有两下有点剧烈的加速,但很短,少数人会叫一下
哈利波特与禁忌之旅:类似那种座椅会旋转和小幅移动的电影,有非常短暂的失重或加速,但没有剧烈位移
侏罗纪世界大冒险:坐车沿轨道走
神龙大侠之旅:功夫熊猫主题,坐船沿轨道走,会从高处掉落一下,第一排会有一点水溅到
奥利凡德:选一个幸运观众互动,其他人观看
灯光,摄像,开拍:观看
灯影传奇:旋转小飞机,座舱内 2 人向前,2 人向后,互相面对面
炫转武侠:旋转木马
👍7
我一直在 Linux 上安装 Noto 字体,主要是为了省心,这样一装就几乎所有 Unicode 都能看了,而且没感觉美观程度上有什么大问题,但我也知道很多教程会推荐装文泉驿的字体。今天 @zzh1996 提到为什么很多 Linux 截图里的中文很丑,研究了一下才发现文泉驿的字体好难看啊!截图是从官网下载的“文泉驿正黑最新正式版”(v0.8.38-1)。
思源黑体(基本也就是 Noto 中的中日韩部分)比这好无数倍,望周知。
思源黑体(基本也就是 Noto 中的中日韩部分)比这好无数倍,望周知。
https://github.com/adobe-fonts/source-han-sans/raw/release/SourceHanSansReadMe.pdf
思源黑体的 readme,我的评价是非常专业,一看就是很懂行的人搞的,读下来学到了很多东西。
思源黑体的 readme,我的评价是非常专业,一看就是很懂行的人搞的,读下来学到了很多东西。
我一直想多给 IPv6 一些机会,看看能不能尽早利用上它的一些特性,但每次尝试都感到非常失望。最近调研注意到的一些问题:
- GitHub 不支持 IPv6。
- Docker 容器默认没有 IPv6。
- 很多程序启动时默认监听 0.0.0.0 或 127.0.0.1,也就是只监听 IPv4。Linux 上监听 :: 默认效果就是同时监听 IPv4 和 IPv6,但很少有程序这样,Python asyncio 甚至禁用了这个功能。
- 我一直听说用 IPv6 会导致不时遇到在某个网站上高延迟或低带宽,甚至资源加载失败,但怎么没有方便的工具对比这类差异?要是浏览器能切换 IPv4 only / IPv6 only / dual stack 模式就好了,我很想认真对比一些网站的效果,而不是静默地被坑了。
- 很大的两个 ISP,Hurricane Electric 和 Cogent,IPv6 没有 peer,所以不互通,还有很多 ISP 也存在类似问题。
- 很少有 VPS 提供 /64 之类的 IPv6 地址,以便机器内部给不同容器随意分配。有的只提供一个 /128,有的提供非常少的几个。
- 很多人可能只知道用 iptables/nftables 配防火墙,但忘了 IPv6,导致走 IPv6 就可以绕过防火墙。我这里不是想说没有 NAT 导致的问题(NAT 不是好的防火墙!),而是想说更一般的,想要禁止两个网络接口之间转发的情况,怎么网上都查不到有人讨论这个?
偶然看到的两个老帖子,感觉挺可乐的:
2011 年有人说“It's not terribly useful to have IPv6 only websites at the moment. Check back in 5-10 years though ;)”
2014 年有人说“The Internet is growing really fast, in a few years, the IPv6 network will be bigger than IPv4, so, with IPv4, you'll be out of the real Internet. Go ahead man! Upgrade your IP!! Change is a good thing.”
- GitHub 不支持 IPv6。
- Docker 容器默认没有 IPv6。
- 很多程序启动时默认监听 0.0.0.0 或 127.0.0.1,也就是只监听 IPv4。Linux 上监听 :: 默认效果就是同时监听 IPv4 和 IPv6,但很少有程序这样,Python asyncio 甚至禁用了这个功能。
- 我一直听说用 IPv6 会导致不时遇到在某个网站上高延迟或低带宽,甚至资源加载失败,但怎么没有方便的工具对比这类差异?要是浏览器能切换 IPv4 only / IPv6 only / dual stack 模式就好了,我很想认真对比一些网站的效果,而不是静默地被坑了。
- 很大的两个 ISP,Hurricane Electric 和 Cogent,IPv6 没有 peer,所以不互通,还有很多 ISP 也存在类似问题。
- 很少有 VPS 提供 /64 之类的 IPv6 地址,以便机器内部给不同容器随意分配。有的只提供一个 /128,有的提供非常少的几个。
- 很多人可能只知道用 iptables/nftables 配防火墙,但忘了 IPv6,导致走 IPv6 就可以绕过防火墙。我这里不是想说没有 NAT 导致的问题(NAT 不是好的防火墙!),而是想说更一般的,想要禁止两个网络接口之间转发的情况,怎么网上都查不到有人讨论这个?
偶然看到的两个老帖子,感觉挺可乐的:
2011 年有人说“It's not terribly useful to have IPv6 only websites at the moment. Check back in 5-10 years though ;)”
2014 年有人说“The Internet is growing really fast, in a few years, the IPv6 network will be bigger than IPv4, so, with IPv4, you'll be out of the real Internet. Go ahead man! Upgrade your IP!! Change is a good thing.”
我常感觉如今越来越多人认为电子游戏只能从竞技性中获得乐趣,我对这种趋势很担忧。我个人喜欢的游戏乐趣是探索性的,例如小时候在同学家里玩侠盗猎车手:罪恶都市,我们连剧情和任务提示都看不懂,只会打警察和用作弊码刷坦克,但看到自己的行为在游戏世界中产生的一连串反应就觉得非常有趣。
本科时玩狂野飙车8:极速凌云,我突然发现某辆车配合某张地图,可以实现全程完全不操作,只靠自动加速通关(会撞毁几次,但每次重生后都能继续前进),感到太妙了,还做了个脚本不断自动重开这个任务。直到有一个很懂这个游戏的同学看到我喜欢玩,给我说这个游戏要买什么车、做什么改装、以什么方式做任务才最好,我顿时觉得这个游戏失去了乐趣,我没有什么好探索的了,别人已经把最优策略贴到了我脸上,我只能去执行。
我真心地认为一个游戏最好玩的时候,就是大家都还不会玩的时候。这时大家可以很欢乐地探索、实验,看各种操作会导致什么结果,并且不在意这样瞎玩会怎么影响分数。Teeworlds、PUBG、军团要塞 2 等游戏都以这种方式给我留下了很好的回忆,我和大家瞎玩时,总觉得“我又想到一个必胜的妙计!”然后尝试执行。但迟早别人也会有办法对抗,我又需要不断改变策略看看会如何发展。一旦大家都会玩了,所有人的策略都收敛到和最优策略非常相似,有趣程度就会大幅降低。
而有一些游戏,我刚接触就被明确告知了“正确”的玩法,知道了要看什么教程,学什么技巧。明知别人已经总结好了教程和技巧而不看、不学,会显得很奇怪,明明学了却表现不好,会显得很无能。在这种环境中,很多人会逐渐认为电子游戏就是要竞技的,玩得不好自然不配获得游戏乐趣。我非常怀念曾经大家都不看教程,不专门去学习,而一起瞎玩游戏的日子。
本科时玩狂野飙车8:极速凌云,我突然发现某辆车配合某张地图,可以实现全程完全不操作,只靠自动加速通关(会撞毁几次,但每次重生后都能继续前进),感到太妙了,还做了个脚本不断自动重开这个任务。直到有一个很懂这个游戏的同学看到我喜欢玩,给我说这个游戏要买什么车、做什么改装、以什么方式做任务才最好,我顿时觉得这个游戏失去了乐趣,我没有什么好探索的了,别人已经把最优策略贴到了我脸上,我只能去执行。
我真心地认为一个游戏最好玩的时候,就是大家都还不会玩的时候。这时大家可以很欢乐地探索、实验,看各种操作会导致什么结果,并且不在意这样瞎玩会怎么影响分数。Teeworlds、PUBG、军团要塞 2 等游戏都以这种方式给我留下了很好的回忆,我和大家瞎玩时,总觉得“我又想到一个必胜的妙计!”然后尝试执行。但迟早别人也会有办法对抗,我又需要不断改变策略看看会如何发展。一旦大家都会玩了,所有人的策略都收敛到和最优策略非常相似,有趣程度就会大幅降低。
而有一些游戏,我刚接触就被明确告知了“正确”的玩法,知道了要看什么教程,学什么技巧。明知别人已经总结好了教程和技巧而不看、不学,会显得很奇怪,明明学了却表现不好,会显得很无能。在这种环境中,很多人会逐渐认为电子游戏就是要竞技的,玩得不好自然不配获得游戏乐趣。我非常怀念曾经大家都不看教程,不专门去学习,而一起瞎玩游戏的日子。
👍17
我被 iOS 这个傻逼设计坑了好几次了:应用没弹窗索要过某种权限的话,系统设置中就不会出现这个应用这项权限的开关,而且很多应用必须触发特定的执行路径才会弹窗索要权限。
如果让 Siri“6点提醒我取快递”,它会在“提醒事项”app 中创建一项,但然后到时间什么也不会发生,打开 app 会看到里面有过期了的项目。在系统设置中,这个 app 没有“通知”权限的开关。解决方案: https://discussionschinese.apple.com/thread/253975593 。一旦这样操作过一次,就有通知权限开关了。
曾经还遇到过比如某个应用从来没点击图标打开过,就没索要过联网权限,导致从其他应用以调用的形式打开时完全无法工作,也不好看出原因是权限问题。
如果让 Siri“6点提醒我取快递”,它会在“提醒事项”app 中创建一项,但然后到时间什么也不会发生,打开 app 会看到里面有过期了的项目。在系统设置中,这个 app 没有“通知”权限的开关。解决方案: https://discussionschinese.apple.com/thread/253975593 。一旦这样操作过一次,就有通知权限开关了。
曾经还遇到过比如某个应用从来没点击图标打开过,就没索要过联网权限,导致从其他应用以调用的形式打开时完全无法工作,也不好看出原因是权限问题。
很多语言有自己的方案来管理和切换编译器/工具链版本,但具体设计和实现质量各不相同,我一直觉得很不好用。最近研究了一下通过 VS Code 的 Dev Container 功能来为每个项目建立完全隔离的环境,发现其实挺简单的:
在项目目录中创建 .devcontainer/devcontainer.json,内容是 {"image":"mcr.microsoft.com/devcontainers/base:debian-12"}。用 VS Code 打开目录,右下角会自动提示要不要用 Dev Container 打开。用 Dev Container 打开后,会在一个专门的容器里,项目目录会被 bind mount 进这个容器,终端是容器里的终端,可以随便安装工具链和依赖,不会影响宿主机,如果有进程开始监听端口,VS Code 还会自动提醒并转发到宿主机上。
这个 image 可以换成任何自己喜欢的 Docker image,但最好是非 root 用户的,不然容器里会是 root 用户,创建的文件宿主机上不方便操作。只要是非 root 用户,VS Code 会负责把 uid 改成和宿主机上相同。如果有更复杂的定制需求,还可以创建 .devcontainer/Dockerfile 文件并修改 devcontainer.json,详询 ChatGPT。
这个方案令我特别满意的点就是项目目录在宿主机上,所以仍然可以用宿主机上的软件工具查看和修改各种文件,不像 Remote-SSH 那样想做各种操作都不太方便。但是这个方案也只适用于“编译器放在隔离环境里就能运行,只需要把编译结果带出来”的情况,对于 Python 这样的语言,要在宿主机上运行最终程序,宿主机上就必须装了正确版本的 Python,这种隔离环境用处很有限。
在项目目录中创建 .devcontainer/devcontainer.json,内容是 {"image":"mcr.microsoft.com/devcontainers/base:debian-12"}。用 VS Code 打开目录,右下角会自动提示要不要用 Dev Container 打开。用 Dev Container 打开后,会在一个专门的容器里,项目目录会被 bind mount 进这个容器,终端是容器里的终端,可以随便安装工具链和依赖,不会影响宿主机,如果有进程开始监听端口,VS Code 还会自动提醒并转发到宿主机上。
这个 image 可以换成任何自己喜欢的 Docker image,但最好是非 root 用户的,不然容器里会是 root 用户,创建的文件宿主机上不方便操作。只要是非 root 用户,VS Code 会负责把 uid 改成和宿主机上相同。如果有更复杂的定制需求,还可以创建 .devcontainer/Dockerfile 文件并修改 devcontainer.json,详询 ChatGPT。
这个方案令我特别满意的点就是项目目录在宿主机上,所以仍然可以用宿主机上的软件工具查看和修改各种文件,不像 Remote-SSH 那样想做各种操作都不太方便。但是这个方案也只适用于“编译器放在隔离环境里就能运行,只需要把编译结果带出来”的情况,对于 Python 这样的语言,要在宿主机上运行最终程序,宿主机上就必须装了正确版本的 Python,这种隔离环境用处很有限。
👍1
最近在用 Vite + Vue + Tailwind 写前端,感觉很爽,推荐。
Vite 可以实现 VS Code 中改代码后,浏览器渲染实时更新,不需要页面刷新,也不影响页面状态。
Vue 和 React 相比我感觉 Vue 还是更适合简单的小项目,光是一个 v-if 就比三元运算符舒服多了。
Tailwind 结合 Vite 的实时更新功能,让我改样式的效率提高了非常多。
另外,这几个东西结合是完全开箱即用的,配置上没什么坑点。
Vite 可以实现 VS Code 中改代码后,浏览器渲染实时更新,不需要页面刷新,也不影响页面状态。
Vue 和 React 相比我感觉 Vue 还是更适合简单的小项目,光是一个 v-if 就比三元运算符舒服多了。
Tailwind 结合 Vite 的实时更新功能,让我改样式的效率提高了非常多。
另外,这几个东西结合是完全开箱即用的,配置上没什么坑点。
👍2
最近学到的一些 CSS 技巧,基本都是从 Tailwind 学到的,见笑了:
- 谁还没学过 flex 的话一定要看看[1],这个不是最近学到的,但太简单好用了,值得强调一下。
- text-wrap: pretty; 避免最后一行只有一个字。
- overflow-wrap: break-word; 在单词中间换行来避免溢出。
- hyphens: auto; 按照 lang 属性时自动插入连字符。
- text-overflow: ellipsis; 溢出时显示省略号。
- font-variant-numeric: tabular-nums; 等宽数字。
- scroll-behavior: smooth; 点击页内跳转链接或 element.scrollIntoView() 都用平滑滚动。
- scroll-margin-top: 10px; 滚动到这个元素时,在它上方留 10px。
- scroll-padding-top: 10px; 滚动到内部的元素时,上方要留 10px。
- CSS 现在可以帮我决定把一个悬浮元素放在另一个元素的上下左右哪一侧,避免伸到窗口外面去[2]!可以用来实现右键菜单或者鼠标悬浮时显示的说明。真可惜这个特性是今年刚刚实现的,太新了。
- 浏览器原生支持根据语言生成正确的引号,以及正确实现双引号单引号交替?!用 <q>,对引号和交替规则不满意的话可以用 CSS 改。
- inset 是 top left bottom right 的缩写。
[1]: https://css-tricks.com/snippets/css/a-guide-to-flexbox/
[2]: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_anchor_positioning/Try_options_hiding
- 谁还没学过 flex 的话一定要看看[1],这个不是最近学到的,但太简单好用了,值得强调一下。
- text-wrap: pretty; 避免最后一行只有一个字。
- overflow-wrap: break-word; 在单词中间换行来避免溢出。
- hyphens: auto; 按照 lang 属性时自动插入连字符。
- text-overflow: ellipsis; 溢出时显示省略号。
- font-variant-numeric: tabular-nums; 等宽数字。
- scroll-behavior: smooth; 点击页内跳转链接或 element.scrollIntoView() 都用平滑滚动。
- scroll-margin-top: 10px; 滚动到这个元素时,在它上方留 10px。
- scroll-padding-top: 10px; 滚动到内部的元素时,上方要留 10px。
- CSS 现在可以帮我决定把一个悬浮元素放在另一个元素的上下左右哪一侧,避免伸到窗口外面去[2]!可以用来实现右键菜单或者鼠标悬浮时显示的说明。真可惜这个特性是今年刚刚实现的,太新了。
- 浏览器原生支持根据语言生成正确的引号,以及正确实现双引号单引号交替?!用 <q>,对引号和交替规则不满意的话可以用 CSS 改。
- inset 是 top left bottom right 的缩写。
[1]: https://css-tricks.com/snippets/css/a-guide-to-flexbox/
[2]: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_anchor_positioning/Try_options_hiding
👍11
Chrome 的 user agent stylesheet 中有 button { align-items: flex-start; } 而不是默认值 stretch,妈耶,花了好几个小时 debug。
我错了,我之后只用 div.jpg
我错了,我之后只用 div.jpg
👍2
👍16