普通视图

发现新文章,点击刷新页面。
昨天以前折影轻梦

如何在 VSCode Remote 里监控远程资源

作者 折影轻梦
2024年7月14日 08:00

快速开始

在使用 VSCode 的过程中,你可以通过使用 Remote-SSH 插件来连接到远程服务器,然后使用 Monitor Pro 插件对远程服务器的资源进行监控。

  1. 安装和配置 Remote-SSH 插件

    • 打开 VSCode,点击左侧栏的扩展按钮。
    • 在扩展商店搜索并安装“Remote-SSH”插件。
  2. 连接到远程服务器

    • 安装完成后,在 VSCode 的终端中输入相关命令来连接到远程服务器。例如,可以使用ssh 用户名@远程服务器地址命令进行连接。
  3. 使用 Monitor Pro 插件进行资源监控

    • 安装 Monitor Pro 插件。这个插件可以帮助你实时跟踪重要的系统指标,并提供直观的展现方式。
    • 安装后,该插件会自动启用,并且你可以通过 VSCode 的状态栏查看当前的资源使用情况,如 CPU、内存、磁盘等。
  4. 刷新设置

    • Monitor Pro 插件允许你设置更新资源指标的刷新间隔,确保能够及时获取最新的资源使用数据。

如何安装和配置 Monitor Pro 插件?

安装 Monitor Pro 插件

在 VSCode 界面的左上角,点击“扩展”(或按 Ctrl + Shift + X),然后在搜索框中输入“Monitor Pro”。

找到“Monitor Pro”插件后,点击“安装”按钮即可完成安装。

配置 Monitor Pro 插件

安装完成后,会在 VSCode 的活动栏中看到一个新图标,点击它以启动 Monitor Pro 插件。

根据具体需求,可以在 Monitor Pro 的设置页面中进行相应的配置,比如调整监控项等。

部分支持的远程资源监控指标

  1. CPU 使用率:监控 CPU 的利用百分比。
  2. 内存使用率:监测系统的内存使用情况。
  3. 网络使用率:跟踪网络的使用情况。
  4. 文件系统使用率:监控文件系统的使用情况。
  5. 电池百分比和充电状态:监测设备的电池百分比和充电状态。

最佳实践

  1. 实时跟踪关键指标:Monitor Pro 是一个全面的资源监控工具,可以帮助你实时跟踪重要的系统指标。因此,建议定期检查这些指标以确保系统的稳定性和性能。

  2. 直观展现方式:Monitor Pro 提供直观的展现方式,这有助于快速识别问题所在。利用这一点,可以及时发现并解决潜在的性能瓶颈。

  3. 内存优化:虽然 Monitor Pro 主要关注的是资源监控,但结合其他工具如 Memory Monitor 和 Allocation Tracker,可以进一步优化内存使用。例如,通过 Memory Monitor 查看整个应用所占用的内存,并注意 GC(垃圾回收)操作的频率和时机,以避免内存抖动等危险信号。

  4. 定制化配置:根据你的具体需求,对 Monitor Pro 进行定制化配置。例如,可以选择监控特定的资源,从而更有效地管理和优化资源使用。

This message is used to verify that this feed (feedId:42331815237783574) belongs to me (userId:55156152962822144). Join me in enjoying the next generation information browser https://follow.is.

10 分钟 ZeroTier 私有 Plant 部署指南,提高游戏联机体验

作者 折影轻梦
2024年4月22日 08:00

在多人局域网游戏如星露谷物语、饥荒、我的世界等日益流行的今天,拥有一个稳定且低延迟的游戏联机环境对于提升玩家体验至关重要。本文将介绍如何使用 Docker 快速部署一个私有的 ZeroTier Planet 服务器,实现联机游戏低延迟,高稳定性。通过虚拟局域网技术,让不同地点的玩家能够如同在同一个局域网中一样进行游戏。

ZeroTier 简介

ZeroTier 是一种 P2P VPN 解决方案,它允许用户在互联网上创建一个虚拟的局域网,使得不同地理位置的设备能够像在同一个局域网内一样直接通信。也就是说,通过 ZeroTier,你可以和你的朋友在各自的家里,组成同一个局域网。然后你们就可以一起玩各种局域网联机游戏,如星露谷物语、饥荒、我的世界等。

ZeroTier 的核心组件包括 PLANET、MOON 和 LEAF,分别代表根服务器、卫星服务器和网络客户端。PLANET 是 ZeroTier 的根服务器,负责维护网络的全局状态和路由信息。

官方的 ZeroTier 服务器位于海外,对于国内用户来说,连接可能会不稳定。自建 PLANET 服务器可以有效解决这一问题,提升网络连接的稳定性和速度。

开始安装

准备条件

  • 一台具有公网 IP 的服务器,需要开放 3443/tcp、9994/tcp 和 9994/udp 端口。
  • 安装 Docker
  • Debian10+,Ubuntu20+ 等内核大于 5.0 的系统

使用 Docker 安装

新建 docker-compose.yml 文件,插入下面内容,
记得修改下面中的 IPV4IP ADDRESS 为你的公网 IP 地址。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
version: '3'services:  myztplanet:    image: xubiaolin/zerotier-planet:latest    container_name: ztplanet    ports:      - 9994:9994      - 9994:9994/udp      - 3443:3443      - 3000:3000    environment:      - IP_ADDR4=[IPV4IP ADDRESS]      - ZT_PORT=9994      - API_PORT=3443      - FILE_SERVER_PORT=3000    volumes:      - ./data/zerotier/dist:/app/dist      - ./data/zerotier/ztncui:/app/ztncui      - ./data/zerotier/one:/var/lib/zerotier-one      - ./data/zerotier/config:/app/config    restart: unless-stopped

在 docker-compose.yml 文件中目录下,使用如下命令启动

1
docker-compose up -d

后台配置

  1. 访问 http://ip:3443 进入 controller 页面,使用默认账号为:admin,默认密码为:password

  2. 进入后创建一个网络 (Add network),可以得到一个网络 ID

  3. 最后需要分配网络 IP: 选中 Easy setup->Generate network address

1d6b3d12c3a688385c45f6b940f42fae.png

b19f85de2600c57daefe7b9b344b27dc.png

Windows 客户端配置

下载

首先去 ZeroTier 官网下载一个 ZeroTier 客户端

覆盖 planet 文件

将服务器中 ./data/zerotier/dist 目录下 planet 文件覆盖粘贴到自己电脑的 C:\ProgramData\ZeroTier\One

覆盖 planet 文件.png

重启服务

Win+S 搜索 “服务”,打开 “服务”,找到 ZeroTier One,并且重启服务

重启服务

加入网络

在后台找到 ID,和平常使用 ZeroTier 加入网络的操作一样。

授权访问

在 ZeroTier 控制器的管理后台,找到新加的客户端并授权其访问。

授权访问.png

连通验证

马赛克处为你的公网 IP

连通验证.png

其他客户端

对于安卓客户端,目前只有非官方的客户端可用
https://github.com/kaaass/ZerotierFix

而 MacOS 用户需要替换 /Library/Application Support/ZeroTier/One/ 目录下的 planet 文件,并重启 ZeroTier-One:cat /Library/Application\ Support/ZeroTier/One/zerotier-one.pid | sudo xargs kill,后续则与 Windows 配置相似。

游戏联机

你的朋友也需要完成客户端配置,才能与你组成局域网。你可以手把手的教他如何操作,也可以让他参考下面的文章进行操作。

3 分钟加入朋友的私有 ZeroTier Plant 网络中

当网络组成后,你可以在后台找到朋友在局域网中的 IP,

然后使用 ping <IP> 命令测试网络延迟。

猜你也想读

3 分钟加入朋友的私有 ZeroTier Plant 网络中

作者 折影轻梦
2024年4月22日 08:00

为了帮助你和朋友们轻松流畅地通过局域网一起玩像《星露谷物语》、《饥荒》或《我的世界》这样的游戏,以下是在 Windows 系统上利用 ZeroTier 软件加入朋友搭建虚拟局域网的详细步骤

下载 ZeroTier

首先,请访问 ZeroTier 官方网站下载适用于 Windows 系统的 ZeroTier 客户端程序。也可直接从朋友处获取并安装。

配置 ZeroTier 服务

找你的朋友要 planet 文件覆盖粘贴到自己电脑的 C:\ProgramData\ZeroTier\One

16b4f746c777faf281bfa6bf04d60365.png

为了使新的配置生效,接下来请按下键盘上的 Win+S 组合键打开搜索框,输入“服务”,打开 “服务”,找到 ZeroTier One,并且重启服务

14bf0b688b1cbb9fb1525b66d68de414.png

加入网络

完成配置后,你可以按照常规的 ZeroTier 使用方法加入朋友的网络:

向朋友索取他们所创建的网络 ID。在 ZeroTier 客户端界面上,输入朋友提供的网络 ID 来申请加入网络。

b2004d8e10d483995644f272ae490476.png

加入网络后,需要等待你的朋友在 ZeroTier 控制面板(即管理后台)中对你新加入的客户端设备进行授权确认,你的朋友知道怎么操作。

开始联机游戏

当你的朋友确认你已成功加入并授权后。然后你可以让你的朋友看看你连接上没,连接上了就可以开始联机了

一旦双方都确认网络连接无误,你就可以开始愉快地联机游戏了。只需启动游戏,设置游戏内的局域网联机模式,与朋友们在同一个虚拟局域网环境下共同体验游戏的乐趣。

新标签页助你重新掌控你的收藏夹

作者 折影轻梦
2024年3月5日 08:00

在数字时代,我们的浏览器收藏夹,就如同一个宝库,里面藏着我们曾经因兴趣、工作或学习而保留的无数网站链接。小舒同学,一个浏览器新标签页扩展,帮助您高效地管理这些珍贵的在线资源。通过整洁、直观的界面和强大的功能,通过小舒同学这款强大的浏览器扩展,让您的收藏夹焕发新生。

一键展示管理收藏夹

不需要反复整理和搜索您的主页,小舒同学提供了一种轻松的方法来展示和管理您的收藏夹。通过在新标签页中,将书签以清晰的图形方式呈现,帮助您聚焦真正重要的事情。无论是微软的 Edge、Google 的 Chrome,还是 Mozilla 的 Firefox,都可以实现一步直观整洁地展示管理您的网络财富。

一键展示管理收藏夹

随时随地的同步空间

小舒同学的同步空间可以让您轻松同步收藏夹,通过同步空间功能,不管您是在工作场合的电脑还是在家里的设备,都可以轻松连接,访问您全部的收藏内容。您的内容将被安全地存储与同步,确保您可以在任何时间访问。网络世界的一切都将由您连接统一,不仅能启动哔哩哔哩,更能直接访问您关注的具体内容。

同步空间

网页端

直观且舒适的重组织

小舒同学以流畅和直观的用户体验,帮您重新组织您的在线生活。我们专注于舒适的交互设计,将您的收藏夹以一种对您有意义的方式进行组织。

小舒同学提供各式各样的卡片形式和布局,让您可以完全按照自己的喜好进行自定义。您可以创建个性化的卡片组合,以满足您的独特需求。

重组织

严格隐私保护

小舒同学重视用户的隐私保护,拒绝记录和上传用户数据。在不使用同步空间的情况下,您的收藏夹数据也只在浏览器本地数据中,确保隐私数据的私密性。依托于 Manifest V3,小舒同学严格控制所需权限,保证只加载本地代码,保护用户的安全与私密。

定制个性化新标签页

小舒同学的自由度极高,可以按照用户的喜好进行多种个性化设置。您可以更换壁纸、主题、主题色,甚至可以用自定义 CSS 美化您的标签页。拥有如此高度自定义的新标签页,您的浏览器将成为真正属于您的个性空间。

主题 Fluid

主题 Meteor

主题 Hyper

小舒同学不仅仅是一个简单的收藏夹工具,它改变了我们与网络信息的互动方式,提供了一个更高效、更有组织性的网络生活体验。减少了无谓的折腾,让每一次收藏都变得值得,让每一次浏览都充满发现的喜悦。现在,尝试小舒同学,让您的收藏夹变成您的独特网络资产,发挥它们真正的潜力吧。

使用 Docker 和 pnpm 优化打包 Nuxt

作者 折影轻梦
2024年2月25日 08:00

本文将指导你如何为一个结合了 Prisma 和 Nuxt.js 的全栈项目创建优化后的 Docker 镜像,并使用 pnpm 作为包管理器。

我的项目最终镜像大小从 1.12GB 缩减到了 160.21MB。

我的项目构成

Nuxt.js 是一个基于 Vue.js 的服务器端渲染应用框架,非常适合于构建现代化的 Web 应用。

我的项目直接采用 Nuxt 构建全栈项目。

  • Nuxt3
  • Prisma
  • PNPM

开始构建

首先,我们将使用 node:20-alpine 这个更轻量级的基础镜像来减小最终镜像的大小。Alpine Linux 因其安全、简单且体积小而广受欢迎。

多阶段构建是减少 Docker 镜像大小的有效策略之一。我们将使用三个阶段来构建我们的镜像。

第一阶段:构建依赖项

1
2
3
4
5
6
7
8
9
10
11
ARG NODE_VERSION=node:20-alpineFROM $NODE_VERSION AS dependency-baseWORKDIR /appRUN npm install -g pnpmCOPY package.json pnpm-lock.yaml ./RUN pnpm install --frozen-lockfile`

这一阶段负责安装我们项目的依赖项。我们使用了 pnpm 来代替 npm,pnpm 在缓存和磁盘使用上更为高效。

大部分项目也用 pnpm 而不是 npm 作为包管理工具了。

第二阶段:构建应用程序

1
2
3
4
5
FROM dependency-base AS production-baseCOPY . .RUN pnpm run build

在这一阶段,我们复制了项目代码并执行构建命令。这里的构建指的是 Nuxt.js 的构建过程,它会生成静态文件和服务器端渲染所需的资源。

第三阶段:生成生产镜像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
FROM $NODE_VERSION AS productionCOPY --from=production-base /app/.output /app/.outputENV NUXT_HOST=0.0.0.0 \    NUXT_APP_VERSION=latest \    DATABASE_URL=file:./db.sqlite \    NODE_ENV=productionWORKDIR /appEXPOSE 3000CMD ["node", "/app/.output/server/index.mjs"]

最后,我们创建了适用于生产环境的镜像。这个镜像仅包含用于运行应用程序的必要文件,减少了不必要的层,使得镜像尽可能地保持精简。

我们还定义了一些环境变量,比如 NUXT_HOSTDATABASE_URL,这些是 Nuxt.js 应用和 Prisma 所需要的。其中,DATABASE_URL 被设置为使用项目根目录下的 SQLite 文件作为数据库。

最终通过暴露端口 3000 并指定启动命令来运行 Nuxt.js 应用程序。

不同构建方式的镜像大小比较

分别为:

  • 3 步构建
  • 2 步构建
  • 直接构建

a3c345aaa51a4b8b802c25bc9d3591c0.png

Dockerfile 总览

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# Use a smaller base imageARG NODE_VERSION=node:20-alpine# Stage 1: Build dependenciesFROM $NODE_VERSION AS dependency-base# Create app directoryWORKDIR /app# Install pnpmRUN npm install -g pnpm# Copy the package filesCOPY package.json pnpm-lock.yaml ./# Install dependencies using pnpmRUN pnpm install --frozen-lockfile# Stage 2: Build the applicationFROM dependency-base AS production-base# Copy the source codeCOPY . .# Build the applicationRUN pnpm run build# Stage 3: Production imageFROM $NODE_VERSION AS production# Copy built assets from previous stageCOPY --from=production-base /app/.output /app/.output# Define environment variablesENV NUXT_HOST=0.0.0.0 \    NUXT_APP_VERSION=latest \    DATABASE_URL=file:./db.sqlite \    NODE_ENV=production# Set the working directoryWORKDIR /appEXPOSE 3000# Start the appCMD ["node", "/app/.output/server/index.mjs"]

Caddy, Docker 简单的自建 Tailscale DERP

作者 折影轻梦
2024年1月12日 08:00

作为一个拥有全端加密且能进行端到端连接的服务。Tailscale 现在的免费账户已经支持连接 100 台设备,这对于个人用户来说绰绰有余。我的内网设备几乎都在使用 Tailscale 连接。在前段时间发布的 用 VS Code 管理服务器,我有独特的服务器管理方式 中表明我很喜欢用 Remote SSH,我经常借住 Tailscale 组成的内网使用 Remote SSH 进行远程开发。

然而,Tailscale 在中国大陆的网络环境中存在一个问题,就是经常出现高延迟或者连接不上的情况。好在官方允许用户自建 DERP 服务,以充当中继,解决这个问题。再也不用担心写代码写一半就突然断了,而且优秀的网络体验也能提高 VS Code 的 Port Forward 的体验,方便远程预览开发。

由于我本身就有一台低配置的云服务器,过去曾经使用 Caddy 作为反向代理服务器来运行我的 Alist 项目。所以这次也考虑在同一台服务器上使用 Caddy 作为反向代理来部署 DERP 项目。

采用 Caddy 主要是他相比较于 Nginx 使用很简单的配置就能满足大部分需求,还有体验良好的自动 SSL 管理。能省很多事。

废话不多说,直接开始配置了。

配置 Docker

1
2
3
4
5
6
7
8
9
10
11
// docker-compose.ymlversion: '3'services:  derper:    image: fredliang/derper    restart: always    ports:      - 3478:3478/udp      - 23333:443    environment:      - DERP_DOMAIN=derp.example.com

然后启动

1
sudo docker compose up

配置 Caddy

1
2
3
4
// Caddyfilederp.example.com {    reverse_proxy localhost:23333}

重载 Caddy 的配置

1
sudo docker compose exec -w /etc/caddy caddy caddy reload

别忘了解析你的域名到你的 Caddy 服务器上。

配置 Tailscale

在 Access Controls 中配置

直达链接:https://login.tailscale.com/admin/acls/file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{  // ... 其他 ACL 配置  "derpMap": {    "OmitDefaultRegions": true, // 是否只连接自建 derper 节点    "Regions": {      "900": {        "RegionID": 900,        "RegionCode": "myderp",        "Nodes": [          {            "Name": "1",            "RegionID": 900,            "HostName": "derp.example.com", // 域名            "STUNPort": 3478,            "DERPPort": 443,          }        ]      }    }  }}

结束。

参考

  1. GitHub - fredliang44/derper-docker: tailscale‘s selfhosted derp-server docker image
  2. Custom DERP Servers
  3. How NAT traversal works
  4. Tailscale 基础教程:部署私有 DERP 中继服务器
  5. 浅探 Tailscale DERP 中转服务

使用 PNPM 的情况下,Jest 解决 ESM 依赖库的报错问题

作者 折影轻梦
2024年1月4日 08:00

环境

  • NX
  • PNPM
  • lodash-es
  • Jest

从 karma 转移到 Jest 遇到了如下报错

主要原因是 “node_modules” 文件夹中 ESM(ECMAScript Modules) 库不被 Jest 支持。

鉴于 Jest ESM 支持还在几乎不可用的试验阶段,而目前我主要是在公司项目上迁移到 Jest。所以本文主要采用 transformIgnorePatternsmoduleNameMapper 两种配置来解决这个问题。

11c629a593c4c8484b6cb8ca44d6aa5f.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Test suite failed to runJest encountered an unexpected tokenJest failed to parse a file. This happens e.g. when your code or its dependencies use non-standard JavaScript syntax, or when Jest is not configured to support such syntax.Out of the box Jest supports Babel, which will be used to transform your files into valid JS based on your Babel configuration.By default "node_modules" folder is ignored by transformers.Here's what you can do:    • If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/ecmascript-modules for how to enable it.    • If you are trying to use TypeScript, see https://jestjs.io/docs/getting-started#using-typescript    • To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.    • If you need a custom transformation specify a "transform" option in your config.    • If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.You'll find more details and examples of these config options in the docs:https://jestjs.io/docs/configurationFor information about custom transformations, see:https://jestjs.io/docs/code-transformation

以下配置主要以 lodash-es 作为参考。

transformIgnorePatterns

官方文档的解释是:正则表达式模式字符串的数组,在转换之前与所有源文件路径匹配。如果文件路径与任何模式匹配,则不会对其进行转换。
transformIgnorePatterns 用于指定在进行代码转换时应该忽略的文件或文件夹。

而在 NX 默认的 Jest 配置中,配置为 node_modules/(?!.*\\.mjs$)
这个正则表达式的含义是,匹配以 node_modules/ 开头的文件夹路径,但排除那些以 .mjs 为扩展名的文件夹路径。?! 是一个否定预查,表示不匹配这样的文件夹路径。

1
transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],

以上配置意思就是将会把以 .mjs 为扩展名的文件从 ESM 转换为 CommonJS,以支持 Jest。

添加转换 lodash-es

顺便支持一下 PNPM

1
2
3
4
5
6
7
const esModules = ['.*\\.mjs$', 'lodash-es'].join('|');export default {    ...    transformIgnorePatterns: [`node_modules/(?!.pnpm|${esModules})`],    ...}

转换后 failed 数量从 15 减少到 11,但是这么做会有一个转换的过程会有额外的支出,需要 51s。不过第一次转换完后貌似就会缓存然后就不用转换了。

ef4e6aeef369b021b707664f9c03549a.png

支出更少的方法 moduleNameMapper

这种方法需要库本身有对应的 CommonJS,就不需要转换了。可以跑到 12s

1
2
3
4
5
6
7
export default {    ...    moduleNameMapper: {        '^lodash-es$': 'lodash',    },  ...}

e87d8ad99b64c8f836a8c1777ec217bf.png

最终配置参考如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/* eslint-disable */const esModules = ['.*\\.mjs$'].join('|');export default {  displayName: 'pc',  preset: '../../jest.preset.js',  setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],  coverageDirectory: '../../coverage/apps/pc',  moduleNameMapper: {    '^lodash-es$': 'lodash',  },  transform: {    '^.+\\.(ts|mjs|js|html)$': [      'jest-preset-angular',      {        tsconfig: '<rootDir>/tsconfig.spec.json',        stringifyContentPathRegex: '\\.(html|svg)$',      },    ],  },  transformIgnorePatterns: [`node_modules/(?!.pnpm|${esModules})`],  snapshotSerializers: [    'jest-preset-angular/build/serializers/no-ng-attributes',    'jest-preset-angular/build/serializers/ng-snapshot',    'jest-preset-angular/build/serializers/html-comment',  ],};

参考

  1. Jest setup "SyntaxError: Unexpected token export"
  2. Configuring Jest · Jest
  3. ECMAScript Modules · Jest
  4. Configuring Jest · Jest

【前端十万个为什么】V0

作者 折影轻梦
2024年1月1日 08:00

为什么用 Composition API

c2f54277b2fb37d52596daa96202d926.png

  1. 使逻辑分离更容易:使用可组合函数可以将组件的逻辑分解为多个较小的部分,不再限制于 Options API 中组织代码,更容易重用有状态逻辑。
  2. 灵活性和代码重用性:可以提取和重用共享逻辑,分离关注点,使代码更加模块化和易于维护。
  3. 实现组件的复用和组合:将逻辑拆分为可重用的部分,使用可组合函数组合组件,避免重复编写代码,提高代码的重用性,减少重复和不一致性的风险。
  4. 更好的可读性和可理解性:每个可组合函数封装了特定方面的行为、方便推理和测试、有助于团队合作,使代码结构化和有组织。
  5. 更好的类型推断:使用变量和标准 JavaScript 函数处理组件逻辑。更容易在使用静态类型系统(如 TypeScript)构建大型 Vue 应用程序时进行类型推断

为什么解构 Proxy 会失去效应性

等待补坑

为什么 Vue 中解构 props 会失去响应性

在 Vue 3 中,当你解构 props 时,可能会丧失响应性。这意味着对 props 的更改不会触发组件的更新。

原因是 Vue 的响应性系统依赖 Proxy 来跟踪对象属性的更改。当组件接收到一个对象作为 props 时,Vue 会为该对象的每个属性设置响应性的 getter 和 setter。这使得 Vue 能够检测属性何时更改并相应地更新组件。

当你解构对象 props 时,实际上是创建了一个不再具有响应性的新对象。Vue 为原始对象创建的响应性 getter 和 setter 不会转移到新对象上。

参考

  1. Vue3 如果解构 props 会失去起响应性导致 setup 里一堆 pros.xxx 怎么办? - 这似谁的小鹿的回答 - 知乎
  2. Vue Tip: Destructure Props in Composition API Without Losing …
  3. How To Destructure Props In Vue 3 Without Losing Reactivity | by Nicky Christensen | Medium

为什么 Vue 项目很少用 RxJS

一句话解释

这是因为 Vue 希望成为一个轻量且灵活的框架,允许开发者选择他们喜欢的工具和库。虽然 RxJS 是一个强大的响应式编程库,但 Vue 采用了不同的方法,提供了自己的响应式系统。

详情点

  • 设计理念不同:Vue 注重简单和直观,便于响应式编程;而 RxJS 功能更强、更复杂,适合异步和事件驱动编程。
  • 库的大小与复杂性:RxJS 库大且学习曲线陡,若作为 Vue 的默认依赖,会增加框架大小和开发复杂性,与 Vue 的轻量和灵活理念不符。
  • 灵活性:Vue 设计为灵活且适应不同的项目需求。不将自己绑定到特定的响应式库(如 RxJS),允许开发人员选择最适合他们需求的工具和库。这种灵活性使开发人员能够无缝地将 RxJS 或其他任何库集成到 Vue 项目中。
  • 学习曲线:Vue 拥有平缓的学习曲线,特别是对于初级开发。通过提供自己的响应式系统,Vue 可以提供更简单、更渐进的学习体验。

参考

  1. Introduction to VueJS and RxJS - This Dot Labs
  2. Integrating RxJS with Vue.js | DigitalOcean
  3. Reactive Programming: The Good and the Bad | goodguydaniel.com
  4. A better practice to implement HTTP client in Vue with RxJS for enterprise Apps | by Pawel Woltschkow | Medium
  5. You might not want Rxjs

JavaScript 总结、比较 V2

作者 折影轻梦
2023年11月1日 08:00

Promise 与 RxJS Observables 的区别

Promise

  • Promise 是 JavaScript 中内置的,不需要任何额外的库。
  • Promise 表示可能现在或将来可用的单个值。
  • Promise 是急切的,也就是说一旦 Promise 被解析,.then()回调会立即执行。
  • Promise 只能发出单个值。
  • Promise 非常适合处理产生单个结果的简单异步操作。

RxJS Observables

  • Observables 是 RxJS 库的一部分,需要额外安装依赖。
  • Observable 表示可以随时间发出的值流。
  • Observable 是惰性的,也就是说在订阅之前不会执行任何操作。
  • Observable 可以发出多个值,包括零个或多个值。
  • 可以使用各种 RxJS 操作符对 Observable 进行转换和组合,以创建新的定制流。
  • Observable 非常适合处理复杂的异步操作,例如实时数据流或事件驱动编程。

参考

  1. JavaScript Theory: Promise vs Observable - Medium
  2. angular - What is the difference between Promises and Observables? - Stack Overflow
  3. JavaScript Promises vs. RxJS Observables

模版语法的简单实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const name = 'Nexmoe';const message = 'My name is {{name}} and I\'m {{getAge(20)}} years old.';function getAge(age) {  return age;}const replacedMessage = message.replace(/\{\{(.*?)\}\}/g, (match, variableOrFunction) => {  const trimmedValue = variableOrFunction.trim();  if (trimmedValue.includes('(')) {  // 如果占位符包含括号,则表示为带参数的函数替换    const [functionName, ...args] = trimmedValue.split(/\(|\)/).filter(Boolean);    const func = eval(functionName);    return func(...args);  } else {  // 否则为变量替换    return eval(trimmedValue);  }});onsole.log(replacedMessage);

先检查占位符中是否包含括号,如果包含括号,则表示是一个带参数的函数调用。使用split方法和正则表达式来解析函数名和参数,并将其存储在functionNameargs变量中。然后,使用eval函数将函数名转换为实际的函数对象,并使用扩展运算符 (...) 将参数作为参数列表传递给函数。函数执行后,将返回值作为替换后的字符串返回。

如果占位符不包含括号,则表示是一个变量。直接使用eval函数将变量名转换为实际的变量值,并返回其值作为替换后的字符串。

⚠️ 注意:使用eval函数执行代码具有一定的安全风险,因为它可以执行任意的 JavaScript 代码。有相当多的建议建议不使用eval。准备过段时间研究研究不用eval的方法。

MVVM 是什么

MVVM 代表 Model-View-ViewModel,在 MVVM 中,Model 表示应用程序的数据和业务逻辑,View 表示用户界面,ViewModel 充当 Model 和 View 之间的中介。

模型(Model)

  • 模型代表应用程序中的数据和业务逻辑。
  • 它可以是从服务器获取的数据、本地存储的数据或通过其他方式获取的数据。
  • 模型通常实现了一些方法来操作、存储和管理数据。
  • 对应的是组件中的 data、props 属性。

视图(View)

  • 视图是用户界面的可见部分。
  • 它负责展示数据给用户,并接收用户的交互操作。
  • 在 Vue.js 中,视图通常由 Vue 组件表示,可以包含 HTML 模板和样式。

视图模型(ViewModel)

  • 视图模型是连接模型和视图的中间层。
  • 视图模型通常包含了与视图相关的数据、计算属性和方法,以及与模型交互的逻辑。
  • 通过双向绑定(data-binding)将视图和模型连接起来。当模型中的数据发生变化时,视图会自动更新。通过 DOM 事件监听,当用户在视图中输入数据或进行其他交互操作时,视图模型会自动更新模型中的数据。

优势

  • 分离关注点:将数据逻辑与视图逻辑分离,使代码更易于维护和测试。
  • 提高开发效率:通过双向数据绑定和声明式编程风格,减少了手动操作 DOM 的代码量。
  • 可重用性:通过组件化的方式,视图和视图模型可以在不同的应用程序中进行复用。
  • 响应式更新:当模型中的数据发生变化时,视图自动更新,提供了更好的用户体验。

参考

  1. 为什么尤雨溪尤大说 VUE 没有完全遵循 MVVM? - 知乎
  2. Vue 的 MVVM 思想(包含三个常见面试题) - 掘金
  3. MVC,MVP 和 MVVM 的图示 - 阮一峰的网络日志
  4. Getting Started - vue.js
  5. Comparing Vue.js to new JavaScript frameworks - LogRocket Blog

MVC 是什么

MVC 这个概念已经存在很久了,用了这么多年,今天了解一下概念做个总结。

MVC(Model-View-Controller)设计模式将应用程序中的对象分为三个角色:模型(Model)、视图(View)和控制器(Controller)。该模式不仅定义了对象在应用程序中的角色,还定义了对象之间的通信方式。每种类型的对象都通过抽象边界与其他类型的对象分离,并在这些边界上与其他类型的对象进行通信。应用程序中某种 MVC 类型的对象的集合有时被称为层,例如模型层。

848723f97c7a1b862e10abe0445da348.png

模型(Model)

  • 封装应用程序特定的数据,并定义操作和处理数据的逻辑。
  • 可以表示应用程序中的实体,如游戏中的角色或地址簿中的联系人。
  • 可以与其他模型对象建立关联,形成对象图。
  • 应该存储应用程序的持久状态数据。
  • 不应与呈现数据和用户界面相关的视图对象直接连接。

视图(View)

  • 用户可见的对象,负责显示数据和响应用户操作。
  • 知道如何绘制自身,并可以与用户进行交互。
  • 通常通过控制器对象从模型对象中获取数据进行展示和编辑。
  • 在 MVC 应用程序中与模型对象解耦,提供一致性和重用性。

控制器(Controller)

  • 充当视图对象和模型对象之间的中介。
  • 负责处理用户操作,并将其传递给模型层进行数据处理和更新。
  • 可以执行应用程序的设置和协调任务,管理其他对象的生命周期。
  • 在模型对象发生变化时,将新的模型数据传递给视图对象进行显示。

优势

  • 提供良好的应用程序设计,使对象更具可重用性和接口定义明确性。
  • 支持应用程序的可扩展性,易于添加新功能和模块。
  • 分离关注点,使代码更易于维护和测试。
  • 应用程序的模型层、视图层和控制层之间保持了清晰的分离,实现了代码的结构化和职责的明确划分,从而提高了应用程序的可维护性和可扩展性。

参考

  1. https://developer.apple.com/library/archive/documentation/General/Conceptual/DevPedia-CocoaCore/MVC.html

为什么 Bun 这么快

JavaScriptCore 引擎

Bun 使用 JavaScriptCore 引擎,这是 Safari 浏览器使用的引擎,而不是基于 Chromium 的浏览器和 Node.js 使用的 V8 引擎。JavaScriptCore 引擎经过了针对更快启动时间的优化,这有助于 Bun 的速度。

性能分析和优化

大量的性能优化。Bun 的初衷就是要快。[2]

Zig 语言

Bun 利用 Zig 语言进行低级内存控制和消除隐藏控制流。Zig 的设计原则注重性能,通过利用 Zig,Bun 可以实现更好的内存管理和控制,从而提高速度 [2]

参考

  1. Bun 1.0 | Bun Blog
  2. A first look at Bun: is it really 3x faster than Node.js and Deno? - DEV Community

自建 Sentry 使用 script 启用时无效

作者 折影轻梦
2023年10月22日 08:00

最近在服务器上面自建了 Sentry。

用 script 方法加入到网站后,始终没有效果,然后在控制台中发现了下面的报错。

The Sentry loader you are trying to use isn’t working anymore, check your configuration.

于是去 Github 上找了下,看着应该是国内网络的问题。

在 sentry/sentry.conf.py 内添加下面内容可以解决。

1
JS_SDK_LOADER_DEFAULT_SDK_URL = "https://browser.sentry-cdn.com/%s/bundle.tracing.replay.debug.min.js"

然后记得重启 Sentry 的 Docker 服务

1
2
sudo docker compose restartsudo docker compose up -d

VS Code 插件 Monitor Pro - 监控一切你在意的资源信息

作者 折影轻梦
2023年10月7日 08:00

Monitor Pro 是一个全面的资源监控工具,旨在帮助你实时跟踪重要的系统指标并提供直观的展现方式。无论你是什么职业,如果你用 VS Code,请不要错过它。

安装使用

安装后会自动启用该插件。

https://marketplace.visualstudio.com/items?itemName=nexmoe.monitor-pro

屏幕截图

功能特点

  • 资源监控
    • CPU 使用率:监控 CPU 利用率的百分比,以了解系统正在利用多少处理能力。
    • CPU 频率:跟踪当前 CPU 频率,以了解系统如何动态调整其处理能力。
    • CPU 温度:(如果可以的话)监控温度。
    • 内存使用:关注计算机的内存消耗情况。
    • 网络使用:跟踪机器上的网络活动,包括传入和传出的数据传输速率。
    • 文件系统使用(Linux、macOS):提供磁盘的读写速率。
    • 电池百分比和充电状态:如果你使用的是笔记本电脑或便携设备,此功能可让你监控电池电量和充电状态。
    • 操作系统发行版名称
    • 磁盘使用
  • 排序:自定义监控资源的显示顺序,方便一目了然地监控它们。
  • 刷新间隔:设置更新资源指标的刷新间隔。
  • 无布局移位:确保状态栏中元素的位置和大小不会意外改变。
  • 远程 SSH 资源监控:你可以在远程 SSH 连接的设备上跟踪重要
    的系统指标。
  • 高占用率警报:当任何监控的资源达到高占用水平时,接收警报。
  • 仪表板:我希望在一个页面上显示你关心的所有信息,并配备丰富的图表。

愿景

我深知监控信息的重要性,所以我的目标是打造一个最全面、最直观的监控工具,让你轻松掌握系统状态。开发 Monitor Pro 的初衷是为了满足大家对系统监控的各种需求。

同时在未来我也希望集成图表的设计,让这些数据更加直观易懂。你可以通过这些图表清楚地看到系统各项指标的变化趋势和相互关系。这样,你就能轻松地了解系统的性能表现。并能够基于这些指标做出明智的决策。

为什么要开发这款插件?

为了在使用 VS Code 的 Remote SSH 时提供一种全面的资源监控工具,以便更好地管理和监控服务器的状态。

详细参考:https://juejin.cn/post/7284885060338155539

建议反馈

我非常重视用户的反馈和意见,因为它们对于我改进和完善产品至关重要。有好的建议或者遇到了 BUG,请前来反馈:

https://github.com/nexmoe/vscode-monitor-pro/issues

支持我

Github 点个 star 或是来 VS Code 市场 给个五星好评吧!

动画 PNG(APNG) 转 GIF 并无限循环

作者 折影轻梦
2023年10月6日 08:00

今天在网上找了些 PNG 格式的动态表情包我是不会告诉你是我是在 LINE 偷的表情包的,于是了解到是 APNG 这种格式。由于微信和 QQ 不支持 APNG,所以就把 APNG 转为 GIF 了,在使用 APNG 转换成 GIF 后,发现在微信上只能播放一次,就产生了如何批量修改 GIF 的循环次数的问题。

所以准备简单介绍一下 APNG。并提供了一个在线工具,可以将 APNG 批量转换为 GIF,但是该工具不能实现无限循环。所以分享了一个批量修改 GIF 循环次数的方法,使用了 Node.js 和批处理脚本两种不同的实现方式。方便 Node 开发者和使用 Windows 的普通用户直接批量处理。

APNG 是什么?

APNG(Animated Portable Network Graphics)是 PNG 的位图动画扩展,可以实现 PNG 格式的动态图片效果。APNG 相比于 GIF 在图片质量和细节表现方面更有优势,而且随着越来越多的浏览器对 APNG 的支持,它有望成为下一代动态图的标准之一。主要有以下区别:

  1. 图片质量:GIF 最多支持 256 种颜色,并且不支持 Alpha 透明通道,这导致 GIF 在色彩丰富的图片和含有半透明效果的图片上质量较差。而 APNG 可以支持更高质量的图片,包括更多的颜色和 Alpha 透明通道,使得动画效果更加细腻。

  2. 构成原理:APNG 和 GIF 都是由多帧构成的动画,但是 APNG 的构成原理允许超自然向下兼容。APNG 的第一帧是标准的 PNG 图片,即使浏览器不认识 APNG 后面的动画数据,也可以无障碍显示第一帧。而如果浏览器支持 APNG,就可以播放后面的帧,实现动画效果。

  3. 浏览器支持:从 Chrome 59 开始,Chrome 浏览器开始支持 APNG,使得大部分浏览器都能显示 APNG 动画。唯独 IE 浏览器不支持 APNG。

更多内容请参考:https://xtaolink.cn/268.html

APNG 批量转 GIF

该工具可以批量将 APNG 转为 GIF,不过不能无限循环。

https://cdkm.com/cn/png-to-gif

批量修改 GIF 为无限循环

bat(普通用户请使用该方法)

下面是使用批处理脚本(.bat)来实现相同的功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@echo offsetlocal enabledelayedexpansionset "directoryPath=C:\path\to\directory"for /r "%directoryPath%" %%f in (*.gif) do (    echo Modifying %%~nxf    call :modifyGif "%%f")exit /b:modifyGifset "filePath=%~1"set /p data=<"%filePath%"set "index=!data:~0,16!"set "modifiedData=!data:~0,16!!data:~16,1!!data:~17,1!!data:~19!"echo.!modifiedData!>"%filePath%"exit /b

请将C:\path\to\directory替换为实际的目录路径。将上述代码保存为.bat文件,双击运行即可。脚本将遍历指定目录下的所有.gif文件,并对其进行修改。

请注意,批处理脚本的功能相对有限,无法直接读取二进制文件。上述脚本通过读取文件的第一行来模拟读取文件内容。在修改文件时,它直接将修改后的数据写入文件,而不进行二进制操作。这种方法可能不适用于所有情况,尤其是处理大型文件时可能会有性能问题。如果需要更复杂的二进制文件处理,请考虑使用其他编程语言或工具来实现。

Node(Nexmoe 使用的该方法)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
const fs = require('fs');const path = require('path');function unlimitedGifRepetitions(path) {  const data = fs.readFileSync(path);  const index = data.indexOf(Buffer.from([0x21, 0xFF, 0x0B]));  if (index < 0) {    throw new Error(`Cannot find Gif Application Extension in ${path}`);  }  data[index + 16] = 255;  data[index + 17] = 255;  return data;}function batchModifyGifFilesInDirectory(directoryPath) {  fs.readdir(directoryPath, (err, files) => {    if (err) {      console.error('Error reading directory:', err);      return;    }    files.forEach(file => {      const filePath = path.join(directoryPath, file);      const fileExtension = path.extname(file);      if (fileExtension === '.gif') {        try {          const modifiedData = unlimitedGifRepetitions(filePath);          fs.writeFileSync(filePath, modifiedData);          console.log(`Modified ${file}`);        } catch (error) {          console.error(`Error modifying ${file}:`, error);        }      }    });  });}const directoryPath = './path/to/directory';batchModifyGifFilesInDirectory(directoryPath);

请注意,上述代码使用了 Node.js 的文件系统模块(fs)来读取和写入文件。此外,需要将./path/to/directory替换为实际的目录路径。在执行该脚本之前,请确保已经安装了 Node.js。

该脚本将批量遍历指定目录下的所有文件,并对后缀名为.gif的文件调用unlimitedGifRepetitions函数进行修改。修改后的数据将写回原始文件。在控制台输出中,你可以看到每个已修改的文件的信息或任何出现的错误信息。

更多内容参考:https://www.b612.me/golang/232.html

更好的工具

这个批处理工具可以将多个 APNG 文件批量转换为 GIF 文件,并且可以对转换后的 GIF 文件批量设置为无限循环。

https://github.com/nexmoe/batch-apng2gif

用 VS Code 管理服务器,我有独特的服务器管理方式

作者 折影轻梦
2023年10月3日 08:00

自从 Typora 开始收费之后,我彻底转向使用 VS Code(Visual Studio Code) 进行文章撰写。作为一款 Markdown 编辑器,它已经完全满足了我的需求。

然而,我开始思考是否可以将 Visual Studio Code 用作服务器管理器。在此之前,我一直使用 FinalShell 进行服务器管理,这款工具具备以下特点,也是我所喜欢的:

  • 简单的服务器资源监控
  • 服务器文件浏览
  • 终端功能
  • 多服务器管理

当 VS Code 发布 Remote SSH 功能时,我并没有太过关注。该功能的初衷是用于远程开发,而我并没有远程开发的需求。然而,当我开始进行远程开发时,我决定尝试使用 Remote SSH。结果令我惊喜地发现,Remote SSH 非常适合用于服务器管理工作。

那么,VS Code 有哪些特点,并且满足了我哪些需求呢?

VS Code 的特点

多服务器管理

通过在你需要访问的远程服务器中配置好 SSH Key,便可以轻松地设置 Remote SSH,并指定服务器的 IP 地址,从而直接通过 Remote SSH 访问服务器。

1
2
3
4
5
6
7
Host server1    HostName 服务器 1 的 IP 地址    User 用户名Host server2    HostName 服务器 2 的 IP 地址    User 用户名

通过这样的配置,然后就可以方便地在 VS Code 中访问和管理多个服务器。只需单击服务器列表中的相应服务器,即可快速连接到目标服务器,并在远程环境中执行所需的操作。

文件浏览器

和正常一个项目的使用一样,VS Code 可以打开服务器的一个文件夹。然后我们就可以进行各种各样的文件浏览器的常规操作。还可以使用搜索功能快速查找和定位特定的文件。

我通常就会直接把账号目录直接打开。

同时还可以直接集成 VS Code 本身拥有的强大的文件编辑能力。

从此告别 lsmkdirtouchvi 等操作。

方便快捷的终端体验

可以同时打开多个终端实例,并在它们之间切换。每个终端实例都可以独立运行命令,并保留其输出历史记录。

还可以在编辑器的多个标签页或分割视图中同时打开不同的终端实例,以便同时执行不同的命令。

除此之外,在 VS Code 中,可以通过右键单击文件或文件夹,选择"在终端中打开",快速打开终端并自动切换到对应的路径。再也不用痛苦的到处 cd 了。

Docker GUI 管理

由于我大部分服务都是放在 Docker 上,所以对于 Docker 的使用是非常高频的。

如果你在服务器上使用 Docker 进行容器化管理,VS Code 通常就会推荐你安装 Docker 扩展,然后就可以并以图形化界面的形式管理和操作 Docker 容器。可以方便地查看和管理容器、镜像、网络和卷等 Docker 资源,执行常见的 Docker 命令,以及监控容器的状态和日志。

这基本覆盖了大部分 Docker 常用的操作,也让我大部分时间不再需要使用 Portainer 或是命令行了。

Git GUI 集成

VS Code 提供了强大的 Git GUI 集成功能,可以在代码仓库上进行版本控制和协作。可以直接通过 GUI 进行查看提交历史、比较文件差异、切换分支、合并代码,以及推送和拉取代码等操作。

丰富的个性化主题、插件生态

如果本身就使用 VS Code,便可以直接继承自己的审美。同时 VS Code 比其他终端管理软件拥有更为丰富丰富的个性化主题选项,可以根据自己的喜好和习惯选择适合的主题。也具有丰富的插件社区。

其它

除此之外,VS Code 本身就具有跨平台支持、多语言支持等特性,而且它完全免费。

如何使用 VS Code 进行服务器管理

你需要满足如下条件

  • 能够运行 VS Code 的电脑
  • 正版的 VS Code
  • 生成 SSH Key 并完成配置
  • Remote SSH 插件

其实你需要的并不多,核心是 VS Code 中的 Remote SSH 插件。

配置 SSH Key

你需要在你的电脑上生成 SSH Key,并将公钥配置到服务器上以实现免密登录。你可以在网上查找相关教程了解如何生成和配置 SSH Key。

配置 Remote SSH

通过 这个链接 安装 Remote SSH 后。

你可以按照以下步骤来打开和配置 SSH 主机:

  1. 在 VS Code 左下方找到 Remote SSH 的图标按钮。
  2. 点击该按钮,然后选择 “Connect to Host” 选项。
  3. 再次点击 “Configure SSH Hosts”。

就可以在 VS Code 中进行配置,指定服务器的 IP 地址和用户名。示例配置如下:

1
2
3
4
5
6
7
Host server1    HostName 服务器 1 的 IP 地址    User 用户名Host server2    HostName 服务器 2 的 IP 地址    User 用户名

完成配置后便可以在左下角直接连接服务器了。

插件以及其他推荐

Monitor Pro 插件

资源监控,由我开发。

Monitor Pro 是一款资源监控工具,实时跟踪系统指标。监测 CPU、内存、网络、文件系统使用率,电池百分比和充电状态。可自定义顺序和刷新间隔,提供高占用警报。适用于开发人员、系统管理员和普通用户。

https://marketplace.visualstudio.com/items?itemName=nexmoe.monitor-pro

Docker 插件

如果你在使用 Docker 容器来部署应用程序,这个插件可以帮助你在 VS Code 中管理和调试 Docker 容器。

Wakatime 插件

统计你在服务器上的摸鱼时间。

zsh 与 ohmyzsh

使用 ohmyzsh 以及它的生态,为你的命令行集成自动补全和纠错功能。

累积布局偏移优化 CLS 完全指南

作者 折影轻梦
2023年9月16日 08:00

什么是布局偏移

一个十几秒的短视频解释清楚。

更详细的解释是:布局偏移指的是在网页上发生突然变化时,页面中的内容位置发生意外移动的现象。这种情况常常让人感到困扰,因为它会导致阅读中断或误操作。布局偏移通常是由于资源异步加载或动态添加到页面上的 DOM 元素导致的。可能的原因包括具有未知尺寸的图像或视频、字体与其备用字体渲染大小不同,或者第三方广告或小部件动态调整大小。

难受的是,网站在开发过程中的功能通常与用户体验有很大不同。个性化或第三方内容在开发中的行为通常与生产环境中不同,测试图像通常已经存在于开发者的浏览器缓存中,本地运行的 API 调用通常非常快,延迟几乎不可察觉。

什么是 CLS

累积布局偏移 CLS(Cumulative Layout Shift)是一个指标。

是对页面整个生命周期中发生的每个意外布局变化的最大布局变化分数的度量。

CLS 通过测量实际用户遇到布局偏移的频率来帮助解决布局偏移问题。它可以帮助开发者了解布局偏移在真实用户中发生的情况,从而采取相应的措施进行修复。

为什么要优化 CLS

布局偏移是一个非常影响用户体验的问题,通过上面那一个简短的视频也能理解。

布局偏移通常会导致意外点击、页面方向的迷失,最终导致用户受挫。用户往往不会逗留太久。有时也会使用户不按照预计的产品流程走。

通常优化好布局偏移能够很好的提高用户粘性、用户停留时间等指标。

Yahoo! JAPAN News 通过降低 CLS 0.2 分,得到如下成果。

如何降低 CLS

图片等媒体元素占位

在图像、视频等媒体资源元素中始终包含宽度和高度大小属性。或用 CSS 中的 min-heightaspect-ratio 或类似的方式保留所需的空间。

aspect-ratio

可以用来直接指定当前元素的比例。

https://developer.mozilla.org/zh-CN/docs/Web/CSS/aspect-ratio

对浏览器的支持:

padding-bottom

如果考虑浏览器支持问题仍然可以考虑使用目前一个被广泛接受的基解决方案 “Padding-Top Hack”。这个解决方案需要一个父元素和一个绝对型的子元素。然后计算出长宽比的百分比来设置为 padding-top。例如:

1
2
3
<div class="container">  <img class="media" src="..." alt="..."></div>
1
2
3
4
5
6
7
8
9
10
.container {  position: relative;  width: 100%;  padding-top: 56.25%; /* 16:9 Aspect Ratio */}.media {  position: absolute;  top: 0;}

使用不易产生偏移的 CSS

其中 transfrom 表现很好,以下举几个例子。
用例可以在这里找到:https://play.tailwindcss.com/26PxFA6UVI

zoom VS transform: scale

zoom 会撑大页面并向右偏移时,transform: scale 只是在原地放大。

margin VS transform: translate

margin 造成父元素变大,transform: translate 只是让当前元素移动。

border VS box-shadow

border 会撑起父元素,而 box-shadow 并不会。

小心你的懒加载

懒加载会引起布局的偏移,如果你在有懒加载长列表的里进行跳转,请小心!
无动画进行跳转,能够一定程度上避免该问题。

小心使用 transition: all

在页面首次加载或者跳转页面时,transition: all 可能会导致元素的 padding 等从参数为 0 开始渲染,照成页面的抖动。

这都是痛:
Commit:表格以及友情链接图标抖动
Commit:修复导航栏抖动问题

标签顺序导致的偏移问题

由于在移动端上优先展示主要内容,因此侧边栏的 markup 位于主要内容的后面;而在更大的屏幕上,则通过设置 CSS order 的方式进行排序,将主要内容移到中间(即第二列),伪代码如下:

1
2
3
4
5
6
7
8
9
export default function MainLayout(props) {  return (    <Container>      <Main className={css`@media screen and (min-width: breakpoint) { order: 0 }`} />      <Left className={css`@media screen and (min-width: breakpoint) { order: -1 }`} />      <Right className={css`@media screen and (min-width: breakpoint) { order: 1 }`} />    </Container>  )}

浏览器在首次绘制时并没有完整解析 DOM、只知道 <Main /> 的存在、但不知道 <Left /> 或者 <Right /> 的存在,才因此将 <Main /> 渲染进第一列而不是第二列;直到第二次绘制时,浏览器才将 <Main /> 渲染进第二列、将 <Left /> 渲染进第一列。

Chrome 并不是一次完整解析 HTML 的,在以下两种情况下,Chrome 会暂停解析、开始渲染和绘制:

  1. Chrome 解析器在读取了 65535 字节的 HTML 后暂停
  2. Chrome 在遇到 <script> 标签后,会继续读取约 50 个「Token」之后暂停

详细了解请看:优化博客的累计布局偏移(CLS)问题

网页跳转与前进后退缓存

默认情况下,所有浏览器都使用 bfcache,但由于各种原因,有些站点不适合使用 bfcache。有关如何测试和识别阻止 bfcache 使用的任何问题的更多详细信息,请阅读 bfcache 文章

在你离开后,bfcache 将页面保存在浏览器内存中很短的一段时间,所以如果你返回它们,那么它们将完全恢复为你离开时的样子。这意味着完全加载的页面立即可用,而不会出现任何变化。

现在的 SPA 应用也能很轻易的保证路由跳转页面布局的一致性。记住始终保持你的目录和导航栏在页面的固定位置。

字体

在下载和渲染网络字体之前,通常有两种处理方式:

  1. 使用网络字体替代备用字体(FOUT——未样式化文本的闪烁)。
  2. 使用备用字体显示“不可见”文本,直到网络字体可用并且文本可见(FOIT——不可见文本的闪烁)。

着两种方式都可能导致布局变化。即使文本是不可见的,它仍然使用备用字体进行布局。这意味着使用该字体的文本块以及周围的内容在网络字体加载时会发生布局变化,与 FOUT 的可见字体完全相同。

以下方法可以帮助你最小化这种问题:

  1. 使用 font-display: optional 可以避免重新布局,因为只有在初始布局时网络字体可用时才会使用它。
  2. 使用匹配度高的备用字体。例如,使用 font-family: "Google Sans", sans-serif; 将确保在加载"Google Sans"字体时使用浏览器的无衬线备用字体。如果只使用 font-family: "Google Sans" 而不指定备用字体,将使用默认字体,而在 Chrome 上默认字体是"Times",它是比默认无衬线字体的匹配度更差。
  3. 使用新的 size-adjustascent-overridedescent-overrideline-gap-override API 来尽量减小备用字体和网络字体之间的大小差异,详细信息请参阅“Improved font fallbacks”文章。
  4. 使用 Font Loading API 可以减少获取所需字体的时间。
  5. 使用 <link rel=preload> 尽早加载关键的网络字体。预加载的字体有更高的机会达到首次绘制,这样就不会发生布局变化。
  6. 阅读有关字体最佳实践的“Best practices for fonts”文章。

使用真正的骨架屏

骨架屏好坏示例

测量 CLS 分数

生产阶段

实验阶段

Lighthouse in DevTools

能够针对移动设备和桌面设备生成网页的实际性能报告,并能够提供关于如何改进相应网页的建议。

在本地开发期间从 DevTools 运行 Lighthouse 非常方便。

PageSpeed Insights

应该就是在线版的 Lighthouse。

Performance in DevTools

性能选项卡在 Chrome 的 DevTools 配置文件的所有页面行为在一段时间内记录。时间轴上会出现一个标记为“Experience”的图层,突出显示布局的变化和发生变化的元素。

Web Vitals extension

最好将 Web vital 扩展视为查找性能问题的抽查工具,而不是全面的调试工具——这是 Chrome 的 DevTools 中的性能选项卡的工作。

结语

作为一个对自己项目有较高要求的人,平常几乎都会接触到布局偏移优化或者 Lighthouse,只不过之前自己瞎折腾的时候还没有 CLS 这个概念,现在算是对 CLS 有了较为清晰的概念了。
CLS 作为一个非常基础的优化指标,在用户体验上非常重要,任何项目都应该针对 CLS 做优化。

如有勘误,请及时指出,感谢!

参考

  1. https://web.dev/cls/
  2. https://web.dev/optimize-cls
  3. https://developers.google.com/publisher-tag/guides/minimize-layout-shift
  4. https://web.dev/yahoo-japan-news/
  5. https://addyosmani.com/blog/infinite-scroll-without-layout-shifts/
  6. https://blog.skk.moe/post/fix-blog-cls/
  7. https://developer.mozilla.org/en-US/docs/Web/CSS/aspect-ratio

过了两百天,谈谈 Microsoft Edge 浏览器开拓者大赛

作者 折影轻梦
2023年4月13日 08:00

为什么要谈谈这个比赛

作为一个独立参赛选手,我有幸获得了本比赛的第三名(当然全靠运气,不过也不乏一些方法论)。比赛的奖品嘛,我本来比较看重他的微软实习机会。不过猜测是互联网寒冬的原因,完全没有后续了,没人联系我实习的事情,后续去询问了对接比赛的工作人员、在群里咨询也没有任何情况。

获奖情况

三等奖,就是第三名,奖金 5000 税后 4000,还有一堆实物奖品。还有一个挺好看的玻璃制奖杯。然后就去请室友吃自助餐了。

image

送来的快递有这么大,路上一个人搬回寝室累死了。

image

不知道是 11.4 公斤还是 11.4 斤,11.4 斤应该不会搬的我累死吧?

image

image

这个比赛是什么

参赛者择长开发,以“后疫情时代的变化与挑战”大主题,聚焦“科技改善生活”、“赋能生产力提高”、“多元与包容”三类主题,开发创意小插件,帮助你我看见更大的世界。

这个比赛的官网 https://edgecontest.microsoft.com/index.html 目前已经不能访问了。其实我们从中可以猜测到这个比赛是 Edge 中国区团队为了丰富 Edge 浏览器的扩展生态而举办的。

image

image

一些比赛信息

以下是比较简短且关键的信息,将有助于下面我对比赛的分析。

image

image

image

分析得出的方法论

轻量级技术

简单分析上面比赛信息内四个要求,作为一个技术混子,一眼就能看出什么?没有技术要求!比赛这种形式,在一定时间内需要完成一个项目,确实是非常难完成技术需求高的项目的。大家能发挥的技术都差不太多。我们就不需要把重心放在技术力上了。

产品能力

实用性、易用性、美观性、创新性其实说的就是产品能力。那段时间前不久才开始培养产品能力,正好拿这个比赛试试手。而产品能力又恰好是在比赛里面实现弯道超车的能力。因为参加比赛的有很多都是技术型选手,我确实是比不过人家。

重综合能力

除了产品本身,比赛还要求做 PPT,视频等等,而且产品产出与上架都能为产品加分。则需要行动力和营销能力了。平常喜欢看一些产品人的文章,能大概猜测到作为产品的评审员爱看什么,可以向着那个方向写一下。除此之外,毕竟是一个需要从规划到上线的项目,作为个人参赛,完全就是需要综合能力。

我的项目

这个比赛是在提交截止前几天我才知道的,群友在群里提了一嘴,我才知道(非常感谢群友,不然完全不知道)。

我一想,几天了怎么参加?混吧!但又不能完全摆烂啊,得稍微分析一下,所以有了上一节的那些内容。不过当时也没这么细致的分析,只是简单看了官网然后凭本能做决策。

接下来介绍一下我的参赛项目和当时的一些思考。

Meteor New Tab

image

image

在此之前

image

小舒同学 当时遇到了几个问题

  • 命名不够直白,难以瞬间理解名称含义,毕竟当时起名的时候天天看一些文学作品有文人意识在里面。
  • 界面没有科技感,因为想打造一种舒适具有禅意的感觉。
  • 为了让产品有精神力,用了一些比较任性的口号和宣传。不够直!
  • 产品设计没有满足简洁的需求,平铺这种布局形式并不能满足所有人的需求

当时的几个想法

  • 英文名,更有科技感
  • 界面设计更有科技感
  • 产品名称更直白
  • 口号更加直白,而不是传递理念
  • 产品描述更加直白,而不是传递理念

项目总结

总体来说,参赛项目主要基于小舒同学二次创作。针对不同市场,打造不同的产品形象,更有不同的风格气势。如今 Meteor 仍然还在维护,并朝着向小舒同学越来越远的方向发展。我希望这对孪生兄弟都各具特色。

全篇总结

我认为我是非常幸运的,因为鲜有这样的比赛,评委有很多产品经理。此前我也体验过互联网+之类的比赛,感觉评委没有产品人的那种气息。我在“互联网+” 里面也是显得有点不适应,拿了个校奖就寄了。老师后来安慰我说是 PPT 没念好,答辩的时候没跟评委客气啥的。

这个比赛考察的方向刚好比较适合我,难得有这样的比赛,所以我是非常幸运的,也因为幸运作为个人参赛我才能拿到这样的结果。如果让我去参加什么算法比赛,可能是拿不到什么好结果的。我当然希望以后能有更多这类更加开放,更加百花齐放的比赛。不过我想我已经没机会了,我就要毕业了。回首校园生活,没什么精彩,如此平淡。

新功能!你想要的他来了 !

作者 折影轻梦
2023年2月19日 08:00

a9e0dfb376f64bfc455b912b130c0ab7.png

右键移动卡片,移动卡片时可以搜索文件夹

7c1feea42323cfb6b1f65e109cc890a2.png

比起拖动,更精准。移动到偏远文件夹更快捷

74e699e58f9f3536d67e4f9179ddf810.png

搜索补全,输入时可显示相关提示

89b2e747f0d55525bf1cc74402b6be0c.png

同时,搜索框现在失去焦点后会自动收起啦 😊

打开本地文件

现在可以在这里收藏你的 PDF 文件,也能用小舒同学直接打开了 🙂

0f9fea79fed3d0a1f6f34848a9b9a8af.png

片状卡片,展示更简洁美观的卡片界面

万番呼吁,它来了

467b3b4ce499fbe642a116c4a7989b88.png

全新分享功能,与你的账号联动

想要把一部分收藏的内容分享给朋友怎么办,简单,点几下就行 🚀

cc0fa7f79fa660a11979ff43e472e8cd.png

然后就会生成分享链接和二维码了

https://store.chainwon.com/bookmarks/63908420e127c076e239

d0b59f8d689ddfb98cae80edbf896462.png

搜索框自动获取焦点

可控制搜索框是否在打开时获取焦点

打卡全部卡片需要确认

不用再怕误触了

9190f18dd9c16d0b8f7cc9e5df510949.png

2c133700e9743ae20b76c10ce7429b62.png

网络自习室,赛博伴学师。伴学OS1

作者 折影轻梦
2023年1月22日 08:00

在群里整了个机器人统计打卡,欢迎大家一起来打卡,体验赛博伴学

预览

自动统计
bdf3437a7bc3e7cbeb42ec1acb248468.jpg
日报
周报

ToDo

  • 自动打卡统计
  • 每日结束自动公布今日打卡结果
  • 每周结束自动公布本周打卡结果
  • 每月结束自动公布本月打卡结果
  • 打卡提醒
  • 排行榜
  • 长期不打卡的惩罚

规则

打卡

  1. 常见英语学习软件可直接分享到群内完成自动打卡
  2. AI 识别成功的可以打卡
  3. 手动在群内发送“打卡”以完成打卡

报告

  1. 每天 23:59 会自动在群内通报今日打卡情况
  2. 每周周日 23:59 会自动在群内通报本周打卡情况
  3. 每月最后一天 23:59 会自动在群内通报本月打卡情况

打卡提醒

满足以下条件则提醒打卡

  1. 加机器人好友
  2. 今天没打卡
  3. 三天内打过卡
  4. 每天 22:00 或 23:00

加群体验

1e62df52d951e3bb974019e236a54a2d.jpg/nexmoe
42cc02be9f4e898791f66251e7cd37fc.jpg/nexmoe
3c001cc5299e5e39da692ac2dac034fc.jpg/nexmoe
332b8d7a22cb3e48c1e647134af8aebc.jpg/nexmoe

2022,没有记忆的一年

作者 折影轻梦
2023年1月9日 08:00

那些消失的时间

年初,要放寒假。于是回家,喜提 14+14。2022 少了 28 天。十月份底,喜提次密接,集中隔离 7 天,然后无限期封寝室直到 11 月 20 日左右回家。然后回家后喜提 7 天居家隔离,在仓库待了 7 天。
再过一会,就放开了。在放开的大浪潮下,我们这些小地方自然是啥也做不了。为了应对可能的医疗资源挤兑,我至今几乎一天门没出,说实话也没什么出门的意义。一算下来,2022 年只剩 9 个月不到的时间了。

那么其它时间我干了啥

总览整个 2022 年,属实没有多少记忆点。翻遍相册,也不过都是在家宅着吃点东西。今年是几乎毫不特别的一年。

最深刻的事情

全年最深刻的,就是在群友推荐下参加了 Microsoft Edge 浏览器开拓者大赛,然后获得了个第三名。
本来说是可以参加后续的实习,结果这小半年过去了,也没啥消息。

e0014a33eada08c943bea4807e9cb2a8.png

两次外出

今年离开家附近或学校只有两次。

第一次在暑假,去武汉东湖,面基网友。在朋友家住了一晚上。在东湖骑车是个非常享受非常自由的事情,不过很累,所以第二天就回家了。还第一次去猫咖爽了爽。

东湖里的店铺
猫咖
朋友家的猫

第二次在国庆,学校在多方情况下允许我们请假出去。那肯定得抓紧这个机会。大三了,我仍然对郑州非常陌生。国庆几天,随便玩了玩,吃了吃,然后就没了。

烤羊腿
aaa71db16de796fb4fc23c5f5f2a7358.png
21142466ef2218bac6f9f13de0d57f23.png

KTV,始于 2022 年的爱好

以前始终觉得 KTV 没什么意思,但是今年去了好几次 KTV,因为开始觉得 KTV 能够释放自己、暂时的忘掉一切。还能和朋友一起相处一会,让疫情中的生活多一丝丝社会性。也是从这个时候开始,学着唱歌,虽然都是随便乱喊乱叫。不过最近阳了过后一直咳嗽,话都不想讲,更别说唱歌了。

76f233c15835872c818e34755e2a82a7.png

说了这么多,那岂不是几乎什么都没干嘛?

对,是几乎什么都没干。今年是没有记忆的一年。再过一年,我也许只记得 2022 参加过一个比赛。然后其他的都是一片空白。

2022 年是

仓促的

两次放假,都是突然性的通知。学校里有了一些传闻,然后我觉得要放假了。虽然非常令人难以相信,室友也觉得不会如此仓促的放假,但第二天就放假了。

无意识的

说实话,2023 年 1 月 5 日我对完全不知道 2022 结束了。直到在空间刷到网友的年终。

往年年终

朋友们的年终

用小舒同学做笔记

作者 折影轻梦
2022年10月29日 08:00

忘记一个书签的作用?别怕

现在你可以给书签做笔记备注了,同时可供你在搜索中快速找到。

6581eee54349dd6f10504729882c9bbb.png

156b3ffc82c9fb7db94c264e02234507.png

df32a4ceb39438ac86c686fd09188059.png

更加智能的数据备份

现在小舒同学会自动定期帮你备份数据。同时记录你使用的浏览器和版本号,方便你恢复数据。

b953f3b3f0c45a009807a773703c479b.png

全新 Transparent 主题

055d40088371f6bb08beffca6ed692a6.png

小舒同学的搜索框终于能够自动获取焦点了,方便你更好的使用小舒同学的搜索框

6baf2722dd26059e463f5f716bcd926e.png

搜索框用键盘选取建议结果

全新上传壁纸

现在,你可以上传跟随你账号同步的壁纸了。

f76cc5d3b740b2aaea875cae355e7f9b.png

拖动你的文件夹标题

现在你可以通过拖动文件夹标题来进行文件夹排序了

e414cfd155ef53290fc0c3a68df05a03.png

拖动到屏幕按钮上实现跨屏分组排序

29ba3751ac7b7340b818c4f3eb38f3be.png

❌
❌