分类
技术

欢迎欢迎

欢迎来到我的博客,我是 Meathill,想了解我可以点 关于我

我工作日晚上 9:00~10:00 会在 B 站直播,https://live.bilibili.com/5126601,大部分都是全栈开发相关,感兴趣的同学可以关注下。

06-07 ~ 06-11 直播计划:

6-7Showman 的最新进展:视频录制
6-8bb酱挂件开发
6-9bb酱挂件开发
6-10设计模式:适配器模式
6-11设计模式:适配器模式
直播计划

欢迎留言点播各种内容。


近期作品

分类
js

检查超宽元素的脚本

有时候我们制作页面,搞着搞着发现超宽,出现横向滚动条。于是我们就要想办法调整样式,但是往往超宽的只有那么一两个元素,并不是很好找,所以我就写了下面一个脚本,在页面里跑一下就能找到超宽的元素,然后针对性调整一下样式就可以了:

// 这里的 375 主要针对基于 iPhone 6 开发移动端页面时
function traverse(parent) {
  let target;
  for (const elem of parent.children) {
    const rect = elem.getBoundingClientRect();
    const {left, width} = rect;
    if (left + width > 375) {
      target = elem;
      break;
    }
    target = traverse(elem);
    if (target) {
      return target;
    }
  }
  if (target) {
    return target;
  }
}

使用的时候,打开页面的开发者工具,将这段代码复制到 console 里面,然后执行 traverse(document.body) 就可以找到超宽的元素,然后想办法调整它即可。

当然我们也可以继续用这个函数探索可疑元素,找到更具体的超宽元素;或者找到其它超宽元素。这些就留给大家自行探索吧。

分类
作品

超全面全栈入门项目:fastest

TL;DR.

前些天做了个覆盖面很广的项目:FastTest。涉及到静态网站、node.js 后端 API、响应式、多语言、Vue3 全家桶、前端工具链、nginx 配置等一系列技术,都是很基础的应用,相信对大家入门很有帮助。

GitHub:https://github.com/meathill/fasttest

欢迎阅读学习,有任何问题均可提问或提 issue。


前些日子有个朋友找到我,想请我帮他做个项目。我看了一眼需求,不太想接:这个项目太小,要多了不合适;要少了感觉又不值当——有那时间还不如砍两把胖虎。

后来我仔细一想,感觉这个项目很适合拿来做教程,而且是非常全面的全栈入门教程。

先来看需求。他的需求很简单:开发一个测速应用。用户打开页面,点击按钮,然后下载一些东西,下载完成之后,告诉他他的网速是多少。与之前的测速产品不同,这个应用不下载大文件,而是从各种 CDN 下载 JS 库和 SDK,因为大部分 web 应用都依赖这些资源,所以可能更接近真实体验。

关于需求我们不深入讨论(我觉得挺有道理,但也未必有道理到哪儿去……),只看实现。为了满足这个需求,我们需要开发这些东西:

  1. 静态页,让用户能够测速。这就需要:
    1. HTML+CSS+JS,静态资源
    2. 响应式,支持桌面和移动端
    3. 多语言支持
  2. 后台,能调整待测资源、修改翻译、控制广告、查看数据。这就需要:
    1. 友好的 Admin panel:vue 全家桶
    2. 后端 API:express.js + node.js server
    3. 自动发布静态页(webpack 前端工具链)
  3. 部署到服务器:
    1. 静态服务供给用户端页面和资源
    2. SPA 服务,提供后台 Admin Panel 给管理员
    3. 反向代理 express.js API
    4. 配置 CDN
  4. 其它,比如版本管理、前端预处理工具,等等

这些东西可以说是非常全栈,除了没有移动 App、没有数据库操作,其它 Web 开发的东西都用到了。而且涉及到技术也都很基础,没有特别深入的东西。再加上,这个项目会上线,会迭代,是个真实产品。所以,很适合拿来做教程,大部分观众,不管是什么背景,都可以拿来入门。

于是我就答应了,然后断断续续在直播的时间把它做了出来。当然还有一些问题,不过大部分功能都就绪了。

项目放在 GitHub 上:https://github.com/meathill/fasttest,有需要的同学请自由取用。对其中任何技术点有问题都可以提问或者开 issue。

网站地址在 https://afasttest.com

视频还需要一些时间来整理,将来慢慢放出来吧。着急且有时间的同学可以自行从百度网盘下载:https://pan.baidu.com/s/1KPuCM-9gPd0hQsr5Df_PnA 提取码: w8f2。

分类
服务器端

nginx 笔记

基础配置

# daemon on;
# worker_processes 1;
error_log logs/travis.error.log error;
pid logs/travis.nginx.pid;

events {
    accept_mutex off;
}

http {

    server {
        listen 9000;

        include mime.types;

        location / {
            rewrite ^ /static/edge/index.html last;
        }

        location /admin-api/ {
            proxy_pass https://admin-dev.openresty.com.cn;
            proxy_set_header Host admin-dev.openresty.com.cn;
            proxy_ssl_name "admin-dev.openresty.com.cn";
            proxy_ssl_server_name on;
        }

        location /static/ {
            alias fe/dist/static/;
        }
    }
}

启动 nginx

nginx -p $PWD -c conf/travis.conf

其中,-p $PWD 指定当前目录为工作目录。-c 指定配置文件。

reload

找到配置中的 pid 文件,从里面找到 pid

kill -s HUP ${pid}
分类
linux

在 Fedora 34 上启动 VNC DISPLAY

大家可以先阅读 使用 Node.js 驱动 FFmpeg 在 Linux + vncserver 下完成视频录制 了解产品目标和技术选型。

前两天在系统更新里看到 Fedora 34 发布,作为更新党,我当然迫不及待就升级了。升级过程蛮顺利的,升级后,系统里的“在线账户”也能正常走 VPN 了,感觉还蛮好的。

然后,前两天需要调试录视频的程序,发现新系统的 tigerVNC 有一个巨大的变化:不再支持用 vncserver 命令创建虚拟显示器,必须用 systemctl start service,目的是方便绑定系统启动,因为很多服务器的运维需要自动化。

不过这可苦了我。我是系统运维菜鸡,基本只能照抄文章,搞了半天也没搞好。不过感谢开源,在 GitHub issue 里讨论的只言片语让我知道了其实 vncserver 是个脚本,它调用的其实是 Xvnc 这个命令。

那就好办了,我开始按图索骥,寻找 vncserverXvnc 之间的关联。最终找到解决方法如下:

  1. 修改 /etc/X11/Xwrapper.config,加入 allowed_users=anybody。这样才能直接使用 Xvnc 创建虚拟显示器,不然会报告只有 console 用户才能创建的错误。
  2. 使用 vncpasswd 命令创建密码文件,创建后的密码文件位于 ~/.vnc/passwd
  3. 然后用 Xvnc :5 -geometry 1280x720 -PasswordFile ~/.vnc/passwd 创建显示器,跟之前的命令很类似,不过需要 -PasswordFile 选项指定密码
  4. 使用 VNC viewer 登录 VNC,输入密码。(我不知道这一步是否必须)
  5. 可以继续使用 DISPLAY=:5

不过问题并没有完美解决,虽然我的 puppeteer JS 能跑,FFmpeg 也能录。但是 DISPLAY=:5 firefox https://cn.bing.com 只会在当前屏幕打开窗口,不知道为什么。留待以后解决吧。

最后吐槽下,这种稳定版里换大版本的行为真的要不得,开源团队也不能滥用自己的地位。


参考阅读

分类
puppeteer

移除 Puppeteer 里的保存密码提示窗

大家知道,当我们使用 Chrome 完成登录的时候,Chrome 会询问我们是否要保存密码,如下图所示:

图一 询问是否保存密码的弹窗

但是在录制视频的时候,这个弹窗就不太必要了,甚至有些干扰,所以我们就想把它移除。如果搜索“puppteer prevent save password modal”,多半会被引导到这个页面,并得到结果:

--enable-automation 添加到启动标记里。

对应 Puppeteer 就是 puppeteer.launch(options) 里的 args,默认已经启用。但是使用这个选项会提示“Chrome is being controlled by automated test software.”,对录视频来说也不够理想。所以只能另辟蹊径,再找别的方法。

图二 标记浏览器被自动测试软件控制

后来我发现在 设置 > 密码(chrome://settings/passwords)里,可以关闭“提示保存密码”的选项,就不会再弹窗了。那么,我们只要修改浏览器的默认设置,即可。

我的第一反应是用 puppeteer 打开这个页面,然后修改配置。尝试之后发现不行,Puppeteer 不能打开非 http/https/file 协议的页面。接下来尝试修改 userDataDir 目录里的内容,我发现,如果使用 headless 即无窗口模式启动 puppeteer,生成的 user data 目录里的内容就很少,尤其没有 Default/Preferences 这个 json 文件,而后者才是保存浏览器设置的位置。

所以正确的解法就是:

  1. 先用 headless: false 模式启动一次 puppeteer,获得全是默认值的 userDataDir
  2. 修改 userDataDir/Default/Preferences 文件,在根对象上添加 "credentials_enable_service": false,不保存密码
  3. 启动新的 puppeteer 录制视频前,先复制 userDataDir 到目标位置
  4. puppeteer.launch({ignoreDefaultArgs: ['--enable-automation'], userDataDir: '/path/to/userDataDir'}) 启动窗口时禁用 --enable-automation 选项,避免出现图二的提示条,并且使用刚才复制的 userDataDir 保存缓存等信息

目前看来,这套解决方案最合适,希望对大家有帮助。

分类
linux

Linux 命令行科学上网

前些天因为工作需要,装了 Fedora 33 开发 Showman 的视频录制功能。准备顺势双机工作一段时间,自然也就需要给新系统配置好科学上网。这里简单记录一下过程,方便日后回查。

0. 更新系统

第一部当然是更新系统,保证系统组件均为最新版,这样可以规避大多数问题。

sudo dnf update

1. 使用 pip 安装 shadowsocks 客户端

Fedora 33 自带 python 3.9,所以直接使用 pip 安装 shadowsocks 客户端即可:

sudo pip install shadowsocks

这里可以用 sudo 也可以不用,差别就在于,sudo 之后会将执行脚本安装到 /usr/local/bin;而不带 sudo 则会安装到 ~/.local/bin。两者的执行环境不一样。我无意间使用了后者,所以后面也会按照后者来记录。

2. 配置客户端

接下来编辑配置文件,如果是图形界面,建议使用 IDE,纯命令行的话用 vim 也可以。配置文件一般放在 /etc/shadowsocks.json。内容大概如下,顾名思义,我就不一一解释了:

{
  "server":"server-ip",
  "server_port":8000,
  "local_address": "127.0.0.1",
  "local_port":1080,
  "password":"your-password",
  "timeout":600,
  "method":"aes-256-cfb"
}

与前面 Ubuntu 20.04 科学上网 一样,本文不打算介绍服务器的制备——其实我也不建议大家自己制备服务器,除非你本来就有一些资源或者需求。不然的话,以我的经验,比较出名的迷你 VPS(类似 Vultr,DO,$5/月甚至 $2.5/月),IP 大部分都在规则库里,流量大一点,比如看个视频,不出半个小时 IP 就被封了,然后一个月后解封,基本没法用。

如果你是 macOS 或者 iPhone,或者其它可以用 anyconnect 的系统,可以考虑直接买现成的,比如链接里这个

3. 配置系统代理

然后启动服务:

sslocal -c /etc/shadowsocks.json -d start
  • -c 用来指定配置文件的地址
  • -d 表示启动服务

这里可能会遇到几个问题(也是上次我放弃命令行转投 qt5 客户端的原因)。我们来逐个解决它们:

3.1 openssl 错误

执行后报错:

$ sslocal -c /etc/shadowsocks.json -d start
INFO: loading config from /etc/shadowsocks.json
 2021-05-05 15:17:00 INFO     loading libcrypto from /root/anaconda3/lib/libcrypto.so.1.1
 Traceback (most recent call last):
   File "/root/anaconda3/bin/sslocal", line 8, in <module>
     sys.exit(main())
   File "/root/anaconda3/lib/python3.9/site-packages/shadowsocks/local.py", line 39, in main
     config = shell.get_config(True)
   File "/root/anaconda3/lib/python3.9/site-packages/shadowsocks/shell.py", line 262, in get_config
     check_config(config, is_local)
   File "/root/anaconda3/lib/python3.9/site-packages/shadowsocks/shell.py", line 124, in check_config
     encrypt.try_cipher(config['password'], config['method'])
   File "/root/anaconda3/lib/python3.9/site-packages/shadowsocks/encrypt.py", line 44, in try_cipher
     Encryptor(key, method)
   File "/root/anaconda3/lib/python3.9/site-packages/shadowsocks/encrypt.py", line 82, in __init__
     self.cipher = self.get_cipher(key, method, 1,
   File "/root/anaconda3/lib/python3.9/site-packages/shadowsocks/encrypt.py", line 109, in get_cipher
     return m[2](method, key, iv, op)
   File "/root/anaconda3/lib/python3.9/site-packages/shadowsocks/crypto/openssl.py", line 76, in __init__
     load_openssl()
   File "/root/anaconda3/lib/python3.9/site-packages/shadowsocks/crypto/openssl.py", line 52, in load_openssl
     libcrypto.EVP_CIPHER_CTX_cleanup.argtypes = (c_void_p,)
   File "/root/anaconda3/lib/python3.9/ctypes/__init__.py", line 395, in __getattr__
     func = self.__getitem__(name)
   File "/root/anaconda3/lib/python3.9/ctypes/__init__.py", line 400, in __getitem__
     func = self._FuncPtr((name_or_ordinal, self))
 AttributeError: /root/anaconda3/lib/python3.9/lib-dynload/../../libcrypto.so.1.1: undefined symbol: EVP_CIPHER_CTX_cleanup

其中文件、行号可能有所不同,不过错误内容大多一致。

这是因为 OpenSSL 升级至 1.1.0 以上后,内部 API 有一些变化,废弃了 EVP_CIPHER_CTX_cleanup() 函数而引入了 EVE_CIPHER_CTX_reset(),shadowsocks 客户端处于无人维护的状态,没有适配这些变化。

好在修复方案并不复杂,我们只需要修改文件 ~/.local/lib/python3.9/site-packages/shadowsocks/crypto/openssl.py,将里面的 cleanup 都替换成 reset 即可。

3.2 permission denied /var/run/shadowsocks.pid

前面写过,因为我安装的时候没使用 sudo,所以把客户端装在当前用户的目录里。于是面临一个矛盾:

  1. 直接使用当前用户启动客户端,会报告标题里的错误
  2. 使用 root 即 sudo 启动客户端,会报告库有错误(即 3.1),因为我修改的是当前用户的本地库

这里有两个解决方案,一是手动创建 pid,然后修改权限:

sudo touch /var/run/shadowsocks.pid
sudo chmod 777 /var/run/shadowsocks.pid

这个方法重启后会失效,还得再跑一遍。所以我比较推荐另一种做法:使用 sudo -u $user -i 的方式,sudo 的同时仍然使用当前用户的环境(这个方案实测失败了,还要再研究下):

sudo -u meathill -i sslocal -c /etc/shadowsocks.pid -d start

4. 加入自动启动

上一步测试成功之后就可以把这段代码加入 /etc/rc.local,以便实现开机自动启动。

5. 其它步骤

接下来,需要配置 pac 文件、文件服务和系统代理,可以完全参考 Ubuntu 20.04 科学上网 一文。

其中下载 gfwlist.txt 时,如果访问不到 https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt,可以试着修改 /etc/hosts,加入下一行:

199.232.28.133 raw.githubusercontent.com

完成剩余步骤后,配置成功。


在 macOS/iOS 设备上使用科学上网有更简单的方法,扫码可得:

分类
扩展

Chrome 扩展大升级 Manifest V3:变化

上一篇博客 聊了聊 Manifest V3 的设计思路,接下来就该详细介绍下这个版本的变化。按照 官方介绍,V3 的变化主要有以下五点:

  1. 需使用 Service worker 替换 background scripts/pages。这个变化对我影响很大,未来开发新扩展的时候,需要使用全新的代码架构;老扩展要升级,多半也要彻底重构。
  2. 修改网络请求的 API 换作 chrome.declarativeNetRequest。这个变化我暂时没用到,将来有机会再说。
  3. 禁止运行远程代码,所有将会运行的代码都必须事先打包进扩展,接受商店的审查。这点对我厂的影响非常大,很可能我厂的 Showman 要彻底改变实现方式——最大的可能就是停留在 Manifest V2,如果 Manifest V2 被废弃,那就使用新技术栈开发下一代产品。
  4. API 全部提供 Promise。这是应该的,小改善。
  5. 其它一大批杂七杂八的功能变化。

其中 2 暂时不好评价,3 只能被动接受,4、5没啥好说的,所以接下来谈谈 1,background script => service worker。

Background Scripts/Pages

Background scripts/pages(后面简称 background script)的地位很重要,是浏览器扩展的重要组成部分,可以作为联系其它组件的中心、主控,在扩展功能复杂时,作用很大。比如我厂的 Showman,既需要用 content script 注入功能到目标网页,也需要单独打开页面让用户交互,这里每个 JS 都要跑在独立环境,彼此隔离,所以就需要有一个中控,一方面连接各个独立的组件,另一方面常驻内存存储一些全局数据。

相信大家不难想到,这种常驻内存的东西,虽然给开发带来了便利,但是也会给内存带来不小的压力。况且,在 Manifest V2 阶段,甚至还支持一个浏览器扩展注册多个 background scripts 和 background pages。每个页面和脚本都要独享一个环境,哪怕只有短短几行代码,于是就会吃掉大量的内存。

Chrome 对内存使用方面的不检点,被大家诟病已久。其开发团队当然也知道,所以最近几个版本 Chrome 都在试图改进这些问题。既然新版本要降低系统要求提高性能表现,尽量节省内存、同时减少运行时间就是必须考虑的事情。所以,新版本扩展规范规定,background script 有且只有一个,而且只能是 service worker。

Service worker 只能注册事件侦听器,不能持续运行。这样一来,就可以让 background script 的执行之间降到最低,并且随需而动,减少内存占用。

Service worker 的特殊用法

1. 事件侦听器都要放在顶层

事件侦听器都要放在顶层,非顶层的事件侦听器会被直接忽略。

2. 使用 storage API 存储持久化状态

不要用全局变量,把一些需要用到的数据都放到 storage 里,如下:

// 不要这样做
const foo = 'bar'
chrome.runtime.onMessage.addListener(({ type, name }) => {
  if (type === "set-name") {
    name = foo;
  }
});

// 这样做
chrome.runtime.onMessage.addListener(({ type, name }) => {
  const foo = await chrome.storage.local.get(['name']);
  if (type === "set-name") {
    name = foo.name || 'bar';
  }
});

3. 使用 chrome.alarms 取代定时器

我们以前一般习惯于用 setTimeoutsetInterval 定时执行,但它们在 service worker 里都会失效。此时,要用专门的 Alarms API 代替,使用方法倒也不难:

chrome.alarms.create({ delayInMinutes: 3 });
chrome.alarms.onAlarm.addListener(() => {
  // do something
});

需要注意的是,content script 里虽然仍支持 setTimeout,但是太长的定时器会被直接忽略掉,时间阈值是 13s,即短于这个时间的仍然会触发,但是超过的会被忽略。建议如果 content script 需要定时器,那么也交给 background script 来做。

4. 其它一些常见场景的处理

包括解析 HTML/XML、处理音视频播放、使用 <canvas> 绘图等,因为我暂时都没用到,所以就先不说了。

分类
技术

使用 Node.js 驱动 FFmpeg 在 Linux + vncserver 下完成视频录制

自动化录制屏幕有很多用途,比如生成教学视频、生成产品文档,等等。对比人工,自动化有很多好处:

  1. 避免创作者的设备和环境问题(比如邻居装修、麦克风不好等)
  2. 避免创作者的语言、发音问题(比如普通话不标准、不会说某种语言)
  3. 录制环境出现变化,可以方便的重录(比如换个背景图,界面有升级)
  4. 就像写博客一样,任何时候,拿出电脑或者手机都能编辑一段

所以目前研究这方面应用的很多,我厂也是。我近期就投入大量时间在这项工作上面,现在终于有所成果,写篇博客分享一下。

0. 准备环境

首先推荐大家使用 Linux。Linux 开源,有很多开源免费的工具可以完成各种操作,不仅可以录屏,还可以很容易地模拟各种用户操作,给我们留下大量开发空间。

建议选择有图形界面的 Linux 发行版,我尝试过 fedora 33 和 Debian 10 树莓派版,都很容易配置。如果使用纯命令行版本,然后自己完成安装图形界面,比如 gnome,再完成剩下来的配置,会很麻烦。

然后记得把系统更新到最新版,以规避可能遇到的问题。

1. 配置 vncserver

如果只能在主屏录制,这个产品的实用性就会大打折扣。所以我们选择用 vncserver 创建虚拟屏幕,然后在虚拟屏幕上完成录制。如果需要的话,也可以随时用 vnc viewer 之类的软件连上 VNC 实时查看效果,非常方便。

有些系统自带 vncserver,比如 Debian 10 树莓派,那就不用安装。我们选用 fedora 33,需要手动安装,这里推荐 TigerVNC,安装使用都很方便:

sudo dnf install tigervnc

安装完成后,使用:

vncserver :5 -geometry 1280x720

就可以创建虚拟显示器了。其中,:5 是显示器 id,可以顺延,比如 :6:7、甚至 :99,至于上限在哪里我暂时不知道。-geometry 1280x720 是设定显示器分辨率为 1280×720。

另外,还可以使用下面的命令查看和关闭显示器:

 vncserver -list
 vncserver -kill :5 

1.1 测试

配置完成之后,可以用 Firefox 测试一下效果。

# 安装 firefox
sudo dnf install firefox

# 在指定虚拟显示器打开 firefox
DISPLAY=:5 firefox https://cn.bing.com

# 截图,可能需要安装 xwd
xwd -root -display :5 > screen.xwd

# 转换成 png,可能需要安装 ImageMagick
convert screen.xwd screen.png

然后把图片下载到本地,或者启动一个 http 服务器就能看到了。

1.2 关闭桌面

默认的 VNC server 会启动桌面,此时可能会要求我们登录什么的。我们在这套系统当中并不需要桌面,只要有显示器即可,所以可以修改 ~/.vnc/xstartup 禁用:

#!/bin/sh
 

unset SESSION_MANAGER
unset DBUS_SESSION_BUS_ADDRESS
# 把下面这行注释掉 
# exec /etc/X11/xinit/xinitr

2. 使用 FFmpeg 捕获屏幕内容

使用 FFmpeg 录屏比较简单,将输入源设置为指定显示器即可,formatx11grab,命令大体如下:

ffmpeg -y -f x11grab -video_size 1280x720 -framerate 30 -i :5.0+0,0 -c:v h264 a.mp4

其中,

  • -y 意思是自动覆盖前面生成的视频
  • :5.0+0,0 是使用刚才创建的 :5 显示器,用它的 0 号桌面,启动位置是 0,0 即左上角
  • -f x11grab 是使用 X server 抓取格式,Linux 下的图形界面一版是基于这个系统

注意,上面这条命令里参数的顺序很重要,否则可能遇到 Protocol not found 等错误。

3. 使用 node.js 驱动

最后只要用 node.js 的 child_process.spawn() 功能调用上面的命令即可。这段代码属于公司,我就不贴了,主要分享几点经验教训:

  1. 要用 spawn,因为录制过程中我们需要用输出来判断录制状态,exec 这种只能在结束时提供输出的没法用
  2. FFmpeg 会把输出输出到 stderr,理由不明,不过记得要用 stderr 来检查
  3. 录像完成,如果在命令行,按 q 或者 ctrl+C 都可以停止录像,并开始封装视频文件。在 node.js 里,我们可以调用 cp.kill('SIGINT') 。注意,调用之后,FFmpeg 子进程并没有立刻结束,它要把前面的录像进行封装,这个过程也是需要时间的,所以如果你接下来还要对视频文件进行操作,应该等待子进程彻底结束
  4. 判断录像开始的依据,我目前用的是:输出里包含 Output #0, mp4, to 'a.mp4'
  5. 判断录像结束,视频已经生成的依据,我用的是 cp.on('exit', onExit),然后在 onExit 里处理。注意,其它情况导致 ffpmeg 子进程退出时也会触发这个函数,所以我们必须检查 code。此时,在我的机器上,code 是 255,表示它是用户手动中止的,可以当作判断依据。

总结

剩下来的内容基本就是怎么驱动图形界面程序运行了。一般来说用 puppeteer 比较好,可以很容易的跟 node.js 联动,我厂的 showman 也是基于这个方案来实现的,最后贴一段视频,大家看下效果:

一段用上述技术生成的视频

参考阅读

分类
扩展

Chrome 扩展大升级 Manifest V3:设计原则

Chrome 前阵子发布了 Chrome Extension Manifest V3 规范,算是为浏览器扩展开发的下一步明确了方向。虽然目前只在 Chrome 浏览器里有效,不过鉴于 Chrome 的统治级地位,相信只要不出大问题,将来肯定会成为 Browser Extension 规范——实际上,Browser Extension API 就约等于 Chrome Extension Manifest V2。

我最近一两年的工作大多围绕浏览器扩展展开,所以对这个规范很关注,近期也研读了不少,准备写几篇博客分享一下。这是第一篇,主要分享下 MV3 规范的设计原则。


1. 保护隐私

最初的浏览器扩展给了开发者非常大的自由,可以让浏览器扩展大大加强浏览器的能力,但是也会给普通用户带来大量数据外泄的风险。

新规范支持浏览器扩展在不需要特殊权限的时候先正常运行,有用到某个权限的时候,再向用户请求使用许可。另外,权限的授予也不再是永久的,避免长期授权可能导致的问题。

2. 保障安全

扩展要上商店,必须经过审核,很多功能可能没那么容易过审。于是很多应用开发者都会想方设法使用外部资源来绕开平台对应用的监管,这样做能带来更强大的功能,也会带来更大的隐患。比如我厂,Showman 必须用外部 JS 才能驱动网页;但如果是恶意开发者,他们可能会利用这点干坏事。

对于外部资源的使用,新规范采用了更严格的限制。V3 里,只能使用静态外部资源,比如图片视频等,外部脚本彻底不能跑了。这对我厂 Showman 是不利消息。

3. 提高性能

Chrome 的性能一直被人诟病,内存杀手的恶名背负已久。可能很多人不知道,其实 Chrome 扩展架构一直是个大问题。出于安全考虑,扩展里的 JS 会运行在很多不同环境下,比如 content script,background script,都会跑在独立的沙箱里,也就是说,哪怕你一个页面都不开,可能也有好几个扩展 background page/script 在悄悄运行,占用你的内存。

所以新版本也作出改进,强制限制只能使用一个 background script,而且这个 background script 必须以 service worker 形式来跑。保证浏览器扩展不会吞噬掉所有系统资源。

4. 追随统一的 Web 平台

以前为了提供更强大的功能,给扩展增添了很多专享 API,比如文件读写。如今 Web 平台不断发展,一些经过验证的 API 被吸纳到 Web 标准,一些步子太大的 API 被证明其实没啥用。总之,为了让降低开发者的心智负担,也让更多的代码可以一次开发导出运行,新规范会尽量向 Web 平台靠拢,减少专享 API,鼓励使用 Web API。

5. 改善功能

当然,说到底,大家之所以用浏览器扩展,还是因为它的功能比 Web 强。所以新版本还会继续探索新的可能性,让扩展平台更强大、功能更丰富,以便给用户带来更大的价值。

总结

MV2 已经过去了大约十年,确实有一些不合时宜之处,各个平台也逐步摸索了一些更好的策略,比如,权限和安全性的改进很明显是从 iOS、Android 学习而来。至于性能表现,我也很期待。

以上内容主要来自于我对新老 API 的理解和这篇官方介绍:Extensions platform vision – Chrome Developers。推荐阅读。

分类
直播

年后直播总结及初版 BB 酱

今年,我本着再努力一把试一试的想法,重新开始直播。一开始还在斗鱼,后来在群里同学的建议下转移到 B 站。每个工作日晚 9:00 至 10:00,除了个别情况,基本上都播了。

现在小小总结一下。

观看人数:个位数

首先,观看人数基本上都在个位数。群里有几个同学比较捧场,来得挺积极;不过可能跟开播时间有关,来看的人并不多。接下来还要再努力一些:

  1. 下周把 b 站送的礼品卡用掉,看能不能多拉几位观众
  2. 微博上要介绍直播内容和直播时间
  3. 朋友圈也保留一周一次的公告频率
  4. 适当找亲朋好友刷点量

直播内容

接下来说直播内容。一开始直播很大程度上是想逼自己赶紧把实战教程录完,现在等待平台审核,就开始随便播。尝试了讲解设计模式、开发浏览器扩展、以及直播加班(如果内容合适直播的话)。总结,如果完全不做准备,想一次性播好,还是很难。即使是以前写过的内容,比如 jQuery 设计模式,因为没有做 PPT,也没有画图,讲起来还是比较枯涩。

直播写代码更是各种翻车,尤其是浏览器扩展。我本以为我现在天天写 Showman,随便抄起 Vue 3 写个扩展还不是探囊取物。结果赶上 Chrome 更新 Manifest V3,background script 大改,导致我现在都还没法顺利推进。争取这个周末把 background script => service worker 这一关给过了。

直播编程比较难做。首先需要大量时间作准备,不然就会被迫各种现场读文档,信息密度急剧下降,一些观众就流失了;可是我白天要上班,没有那么多时间作准备。相对来说,游戏直播只要有现场反应就行,主播技术不行反而可以让弹幕找到智力上的优越感。

另一方面,讲道理不能光用嘴,还得画图、写字。所以教室里都要备黑板。但是直播过程里切换不同内容输出设备也没那么容易,尤其还要留出足够的空间放 IDE 和预览窗口。这方面需要补充工具。

直播平台对比:斗鱼 vs B站

我一开始在斗鱼播,后来在群里做了个小调查,大家都建议我去 B 站,看来 B 站在严肃内容方面,已经基本上占据了大家的思维定位。

不过我个人感受,斗鱼直播做得更好一些。首先带宽充足,连接稳定;其次互动工具更多,弹幕抽奖、弹幕投票等都有;第三有很多免费小礼物,方便观众和主播互动。另外,B站不提供直播录像下载,得自己记得录。

B站在与视频结合方面比较有优势。因为以前就传过很多视频,所以可以方便地设置录像联播。相对来说,B站更强调直播是 up 主作品的一部分,而斗鱼基本直接跟直播划等号。

BB酱

B站产品力不足也给我们留下了一些空间,比如我就做了一个弹幕扩展:BB酱,可以记录弹幕,并且提供一些增强功能。

接下来会开发用户登录以及弹幕投票功能,开发完成后就提交市场,争取找一些直播主来试用。

关于这个项目的其它想法都会更新在:应用(直播)创意:弹幕收集器

这个项目使用了 Vue3 全家桶、Manifest V3、Bootstrap 5、Leancloud(Serverless),开发过程全程录像,将来计划剪辑成一个教学视频。

计划&总结

我的目标是直播一年,年底实现 100 人在线(DAU),目前来看还很遥远。希望随着几个开源项目发布,能多渠道获取一些观众。