Lolipop's Studio.

Lolipop's Studio.

how about groping lights through young ages

loading
从同步 QQ 空间说说到前端呈现,我都做了些啥

最近在捣腾我的 Timeline 时间线项目,希望将我在不同平台上的发言和活跃记录同步过来,在独立的站点上按照创建时间倒序呈现。

过去,我尝试把这个想法放到 Telegram 上实现,把发言和记录同步到我的频道上。但是格式转换的繁杂以及自由度上的限制让我大费周章,加之增量开设的同步内容会以消息的方式一条一条添加到末尾,无法按时间排序,最终我放弃了这个方案。

言归正传,在项目开发的过程中,我遇到的一个相对复杂的场景即 QQ 空间说说的同步。本文事无巨细地记录下我在处理 QQ 空间说说同步的过程中,做了哪些工作,希望为有相应需求的厚米们带来一些灵感。

同步 QQ 空间说说

同步方案的探索与确定

非常自然而然的,笔者设想使用 Puppeteer 模拟用户操作,打开 QQ 空间网页端,输入账号和密码,进入到个人主页,根据 DOM 结构爬取得到说说的信息。同样非常自然而然的,在切换登录模式(从二维码登录到账号密码登录)步骤就卡着了,模拟点击切换登录模式按钮无效。笔者并非爬虫专家,没有此类问题的对抗经验,在搜索无果后无奈放弃。再想到后续可能还要处理登录安全验证,或处理别的防爬手段,判断 Puppeteer 的方案其实并不合适 QQ 空间说说的同步。

纯前端如何实现一个转盘抽奖组件

为什么

前阵子面试的时候被问到这个问题,觉得挺有意思,于是决定亲手实现一个转盘抽奖组件试试。

翻看别人的实现方案时,发现和自己面试时答得相差很大,悲 😢。但总之,是时候开始弥补自己的 CSS 和动画技能了。

是什么

一个转盘抽奖组件主要由三部分组成,写有中奖结果的圆形转盘、指向结果的指针和开始转动的按钮。

如果每个中奖结果的概率相近,我们可以按照真实概率来划分每个奖品所占圆形的扇形比例。但是通常转盘中会设置抽中概率极小的大奖,按照真实比例的话将无法充分展示奖品内容,而且降低用户对转盘抽奖本身的兴趣度。所以本文实现的转盘组件选择 均分的方式 来划分每个奖品所占的扇形比例,符合通用的原则,也从视觉上让用户觉得中奖概率相当。

Electron 执行后台程序并在渲染器实时打印运行日志

开发图像查重工具时遇到了这样一个问题:在查重之前,用户需要先对图像文件进行索引操作,后台将调用可执行文件并为每张图像生成特征值。索引操作所需的时间与图像的数量及大小呈正相关,笔者为大约 50000 张图片(约 170GB)生成特征值,需要花费将近 90 分钟的时间。在这种情况下,如果渲染器什么也不展示,卡在那里,用户难免会非常焦虑 —— 后台是否还在运行,我是不是卡死了?

那么需求也就明了了,正如本文的标题所述,我们需要将后台运行的日志实时推送到渲染器,这样用户便能看到索引操作的进度,安下心来。

技术背景

众所周知,一个 Electron 应用分为了 Renderer 渲染器和 Main 主进程两端。渲染器负责对客侧的展示,正如我们访问的所有网页一样,是 HTML、CSS、JavaScript 的集合,无法调用 Node 或是访问宿主机文件等。而主进程则具备有服务端应用的性质,能够调用 Node 或是与宿主机交互等。

综上所述,为了实现我们的目标,在背后依次要实现这些事情:

  1. 渲染器接收用户索引操作的请求,将请求发送至主进程。
  2. 主进程接收到请求,调用可执行文件开始生成图像特征值。
  3. 主进程将产生的日志信息实时推送给渲染器。
  4. 渲染器接收到日志信息,并向用户展示。
部署一个给朋友使用的 Minecraft 模组服务器

笔者在今年五月份部署了一个与朋友同玩共乐的 Minecraft 服务器,稳定运行至今。忽然想记录为一篇博客,分享分享折腾的经历。

笔者结合个人喜好(最新版本,模组优先)和大众推荐(Fabric 更适合新版本 Minecraft),决定基于 Fabric 搭建一个可以添加模组的 Minecraft 服务器。此类服务器简称为模组服务器,还有基于 Paper, Spigot 等搭建的插件服务器,可以综合自身需求,选择最合适的搭建方案。

部署 Minecraft 服务器

安装 Java 环境

Java 版的 Minecraft 服务器依赖于 Java 启动,因此在一切的最开始,需要在服务器上安装 Java 环境。

Java 版的 Minecraft 自 1.18 版本开始需要 Java >= 17。参考网上俯拾皆是的教程,通过包管理工具或前往 Oracle OpenJDK 页面下载并安装合适版本的 Java。

基于 SteamCMD 部署一个给朋友使用的饥荒联机版服务器

本文重现了笔者在自己的 CentOS 7 (64-bit) 系统中部署饥荒联机版服务器的全过程,供君参考。

Steam 版的饥荒联机版与 Wegame 版数据不互通,也无法相互联机。

笔者主要参考了如下两个部署教程:

安装 steamcmd

安装的步骤可以直接参考 SteamCMD 的官方文档中文版)。

使用 Nginx 治理我的服务

这些天在阿里云的 ECS 服务器上捣鼓自己的东西,通过 Nginx 转发请求,允许以域名的方式访问到笔者开设的不同站点、服务。

笔者撰写本篇文章,晒晒在服务器上都做了哪些工作,也希望能为您提供一些启发。

安装最新版本的 Nginx

笔者使用的服务器为 CentOS 7 系统,默认的 yum 源中包含的 Nginx 版本为 1.20.1(2021-05-21)。

更新 yum 源,添加 Nginx 的官方源:

1
rpm -ivh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
基于原生 Node 备份软路由上的 Minecraft 服务器存档,并通过 Alist 上传到云端

笔者最近在 OpenWRT 软路由上部署了一个 Minecraft 服务器,出于对数据安全的焦虑,于是折腾了一下存档备份的相关事宜,记录为此文。

在 CurseForge 等模组站上已有方便好用的 Minecraft 服务器存档备份插件,除非您喜欢折腾或高自由度的定制,不用像笔者这样编写一整个脚本。

完整的脚本可见此

编写备份脚本

前置准备

为了脚本编写方便,约定应该在 Minecraft 服务器的根目录执行脚本。校验当前脚本的执行目录:

遇到 AntD 组件中文乱码问题,可以试试这么解决

项目中使用了 AntD 4.x 的 <DatePicker /> 组件,开发环境显示正常,生产环境显示乱码,如下图所示:

error

问题原因

<DatePicker /> 组件底层的国际化既由 AntD 提供的 <ConfigProvider /> 控制(如上图的“年”,显示正常),又由 Moment 控制(如上图的“月”,显示乱码)。

经查询,当我们以 ISO8859-1 方式读取 UTF-8 编码的中文时,会出现如“由月è¦�å¥½å¥½å­¦ä¹ å¤©å¤©å�‘上”这样的符号型乱码,正如上图所示。

因此产生问题的关键在于,为何浏览器没有正确地以 UTF-8 格式读取 Moment 提供的中文语言包文本。

为什么我使用 Umi 的 model 简易数据流管理插件

Umi 是一款企业级的 React 前端应用框架,云巧产业数字组件中心推荐使用基于 Umi 的 Koi 框架统一前端应用研发流程,支撑前端项目从研发、联调到上线、发布的全流程。

本文假设您正在或计划使用 Umi 或 Koi 作为底层框架支撑前端应用的开发,并且对 Umi 有一定的了解。

数据治理的原则

React 的核心特征是“数据驱动视图”,用公式表达即 UI = render(data),通过数据变化来驱动视图变化。React 将组件内部自有的数据称作 state(状态),通过管理 state 来实现对组件的管理。

通过 Props 传参,可以在 React 中实现简单的父子、子父和兄弟组件间数据传递。对于跨级组件间的数据传递,React 提供了基于生产者-消费者模式的 Context API 来实现全局通信。

随着应用的膨胀,组件内部的状态变得愈加复杂,数据流管理的成本也越来越高。如果说所有代码的末路都是成为一座难以维护的大山的话,在那之前,我们应当好好想想如何尽可能多地延长代码的寿命,去重新思考我们的 React 项目的代码组织逻辑。

定时器 SetTimeout 在后台失效?试试 Web Worker 吧

业务上有这样一个需求:「若用户不活跃超过 12 个小时,自动退出当前页面,并切换路由到首页」。

想都没想,直接在 useEffect() 里用 setTimeout() 定个时,12 个小时后触发相应跳转事件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import React, { useEffect } from "react";

const LEAVE_PAGE_COUNTDOWN = 12 * 60 * 60 * 1000; // 12h

/** 离开页面的方法 */
const leavePage = () => {
// ...离开当前页面的业务代码
};

export default () => {
useEffect(() => {
// 初始化时设置定时器
const timer = setTimeout(() => {
leavePage();
}, LEAVE_PAGE_COUNTDOWN);

return () => {
// 页面卸载时清除定时器
if (timer) clearTimeout(timer);
};
}, []);
};

没想到,今天上班来,切换到没有关闭的标签页,发现还在当前页面,掐指一算怎么也有 12 个小时了,这是怎么一回事儿……?

昨天晚上走的时候还在和前辈探讨页面卸载(unload)事件与浏览器后台优化的坑,于是首先就想到了可能是浏览器优化的缘故,导致定时器没有正常执行。以「setTimeout」和「后台失效」为搜索关键词,很快找到了原因和优化解决方案。

失效原因