zhao's Moments

让我们组建一支乐队,一起来超越我们的偶像吧!

Mar 26th
2023

最近帮助一图流升级网站。把技术应用在真实的网站上,真是种前所未有的体验。

我遇到的第一个问题,是打包相关的。一图流的网站用 CDN,按流量计费,非常烧钱。最初观察到后端接口返回的 json 的体积很大,于是启用了 gzip 压缩。然后是图片,从 png 改为 webp 有损压缩,手动调整参数,在看起来不糊的条件下尽量减小体积。

于是只剩下 js 了。最初没有将 js 分页面打包,还把 Element UI 放到了单独的文件里。尽管首页上只用了一小部分 Element UI 的组件,但在访问首页时,还是要把其它页面用到的 Element UI 的代码都下载下来。ECharts 没有使用 npm 安装,而是把它的 js 放在 static 目录下。网站的 js,一大半都是 Element UI 和 ECharts,就觉得“钱白花了”。

网站用的是 Nuxt 2 框架。我以前没有接触过这个框架,在网上搜索打包相关的内容,又看了文档,然而一无所获。以前 Vite 用惯了,看 Nuxt 2 启动开发服务器都要好久,非常不爽。索性新建项目,尝试把代码迁移到 Vite + Vue 3 + Element Plus。出乎意料的是,迁移过程非常顺利,代码几乎不用改就能跑起来。我用 vue-router 实现了分页打包的功能。装了两个插件,一个可视化地分析 js 产物,另一个能够将库从产物中排除。我把 Vue、Router、Element Plus、ECharts 等库都排除掉,在 html 里通过 CDN 引入,这样产物体积就小很多了。

下一步是 SSR。原先使用 Nuxt 2 时,并没有充分利用 SSR,页面上的数据,都是在 mounted() 中下载的,这也是需要改进的地方。我尝试安装了 vite-plugin-ssr,参照文档和示例代码,成功跑通了。对不同页面,分别采用不同的渲染策略:首页和礼包页面以数据展示为主,所以用服务端渲染;攒抽计算器和基建排班器以交互为主,加载又很慢,于是干脆用 SPA,这样页面出现时就立即能交互。然而,攒抽计算器加载很快,如果用 SSR,用户注意不到加载 js 的时间,用 SPA 反而会产生页面加载很慢的错觉。基建排班器加载却很慢,页面出现后要等很久才能交互,如果用 SSR,反而体验不好,有种网页坏了的感觉。所以攒抽页面用 SSR,基建页面用 SPA。最后是路由,出于简单起见,用 vite-plugin-ssr 的服务端路由,不再使用 vue-router。

加了 SSR 后,在打包时也要区分服务端和客户端。按照上面的做法,将一些库从客户端的打包产物中排除,在 html 里通过 CDN 引入;在服务端则不必这样做。好在 Vite 足够灵活,能够满足这样的需求。接着又重写了导航栏。原来的导航栏用的是 El-Menu,这个组件有几个缺点:不能右键,在新选项卡中打开、只能在客户端渲染,不能在服务端渲染、不够灵活,不能加按钮或开关等其它组件。以往首页切换亮色和暗色的按钮,做成菜单项,不是个好办法。再加上导航栏比较简单,样式也是现成的,于是自己写了一个。

将新网站上线后,本以为万事大吉,不料接连有用户反馈打不开。现象是 html、css 和图片完全正常,但 js 却被某种神秘力量阻碍,无法运行。同时在 QQ 内置的浏览器里,有些地方的样式也不对。本以为是网络问题,但又不像。经过排查后发现,QQ 和微信内置的浏览器不能识别 8 位 16 进制格式的颜色,只能用 rgba 格式,调整打包选项,就解决了这个问题。但是,js 依旧无法运行,毫无头绪。

某日,无意间看 nginx 的日志,发现一位有问题的用户,用的浏览器很老,User Agent 包含 Chrome/79 字样。再结合他的手机型号的发布时间,可以推断:他使用的小米浏览器虽然版本很新,但是它调用系统的 WebView。系统的 WebView 版本太老,不支持新的特性。我在手机上安装了 Chrome 79,果然有问题,不支持 ?? 运算符。于是改了打包设置,目标设为 es2015,顺利解决。顺便还学会了在电脑的 Chrome 上调试手机浏览器里的网页。

不料第二天,又有一名用户反馈网站打不开。这次不是手机了,而是在电脑上。一问,他用的是 2345 浏览器。2345 浏览器的内核是 Chromium 69,不支持 globalThis。搜索了一圈,通过 Polyfill.io 补上了这个功能。

然而第三天,又有一名用户反馈网站仍然打不开。他的系统 WebView 内核是 Chromium 61。本来以为会和上次一样顺利,不料 Chrome 61 不支持正则的 s 标志,Polyfill.io 也不包括这一功能。@vite/plugin-legacy 插件还和 vite-plugin-ssr 冲突。尝试在浏览器里直接引入 core-js 也没有成功。无奈只得放弃,劝他装个新版浏览器。

这样,一图流前端的迁移算是告一段落了。

09:46


Mar 7th
2023

为了这碟醋(100 首歌)包的饺子(B 站音频下载器)

Responsive image

11:44


Feb 18th
2023

最近想要自建语音聊天服务,以代替音质非常糟糕的 QQ 语音,于是发现了 Mumble(服务端叫 Murmur)。因为是在家中使用,所以没有把 Murmur 搭在 VPS 上,而是直接把它跑在笔记本上。Murmur 占用的内存很小,空闲时大概不到 30 MB。

Mumble 客户端上手很容易。首次启动软件时会运行向导,帮助调整声音相关的选项。Mumble 支持 PipeWire 后端,自带 Speex 和 RNNoise 两种降噪方式(可以关闭或选择一种,也可以同时开启),实际效果极佳。

安卓上有第三方客户端 Mumla

12:07


Jan 28th
2023

GNOME Terminal 不支持 OSC 52,于是我把终端换成了 Kitty。然而通过启动器或 Nemo 的菜单打开 NeoVim 或终端时,由于 GLib 的问题,Cinnamon 不会用 Kitty,还是会选择 GNOME Terminal。其实指定 Terminal=true 的程序都会受到影响。

按照 GLib Issue 338 的内容,GLib 2.76.0 会在最近几个月内新增 xdg-terminal-exec 的命令,以解决这个 12 年前提出的问题。不过在用上新版 GLib 前,还是得有临时解决方案:把 ~/.local/kitty.app/bin/kitty 软链接到 ~/bin/gnome-terminal,Cinnamon 就会调用 Kitty 了。

GNOME Terminal 运行程序,参数的格式为 gnome-terminal -- <command>。Kitty 可以接受相同格式的命令。但是比如 Alacritty,它接受的参数格式就与 GNOME Terminal 不一样。可以写一个脚本,转化一下参数:

 1#!/bin/bash
 2
 3while [[ $# -gt 0 ]]; do
 4  case $1 in
 5    --)
 6      shift
 7      break
 8      ;;
 9    *)
10      shift
11      ;;
12  esac
13done
14
15alacritty -e $@

赋予可执行权限,保存到 ~/bin/gnome-terminal,就可以了。

PS:用 Python 也挺短的:

 1#!/usr/bin/env python3
 2# -*- coding:utf-8 -*-
 3
 4import sys
 5import subprocess
 6
 7while len(sys.argv) > 0:
 8    if arg := sys.argv.pop(0) == "--":
 9        break
10
11subprocess.run(["alacritty", "-e"] + sys.argv)

17:42


Jan 22nd
2023

过年喽!

pictures
pictures

22:33