Chrome插件踩坑日志(二)vite插件手动实现“热更新”

2,949 阅读4分钟

在现在前端开发中,热更新是必不可少的配置,但是来到了chrome插件的环境中,这就是一个比较头疼的事情了,虽说市面上有一些插件和解决方案,但是v3升级带来的限制,很多方案就不能用了。最近在这方面一直探索,踩了很多坑,才有一个还算过得去的解决方案,虽然不算完美,但至少是个MVP版本了。

背景知识

v2的热更新原理

目前很多能搜到的插件热更新解决方案,可以简单理解成下图

步骤:

  1. 打包工具层起两个服务器,一个普通server,一个是websocket

  2. 监听打包结果文件的变化,如果有变化就通知websocket,websocket再通知浏览器

  3. 浏览器拿到代码更新的信号后,就对dev-server发起静态资源的请求

  4. 利用JSONP的原理进行代码执行覆盖

当前其中还有相当多的细节,比如hash判断,热更替,容错兜底等,其实和我们正常开发前端页面区别不大。

v3的的困境

到了V3版本的插件里,这一套方案就有点问题了,主要的环节出在JSONP这一段,之前V2的方案里去动态加载远程代码,是需要在manifest.json中添加配置的:

image.png

这个配置表示可以用script标签执行来自http://localhost:3333的js资源。

V3环节中,如果还这么干,那么浏览器就会有类似如下的报错:

这个意思就是在插件环境中只能执行插件目录下的文件,其他远程或eval的执行都会被拒。

如何平替实现(MVP)

架构图

上面就是针对V3环境进行调整的一个架构图,变动如下:

  1. 去掉了devServer这一层,改成直接输出静态文件
  2. 有任何更新都直接通知Background
  3. 对于Background有变动,那么就reloadContentScript也通过Background这个桥梁更新

hotReload细节

下图是Background的更新代码,收到通知reload即可

下图是ContentScript如何通过Background来更新代码

通过上面的代码可以知道,每次websocket发出更新的指令,就会触发对当前已打开页面执行新脚本的命令(exectuScript)。

但是重复执行代码肯定会有隐患存在,毕竟作用域都是同一个window下的,所以下面代码就是为了清除之前留下来的节点:

自定义vite插件

image.png

在vite插件层,需要做的事情是下面两件:

  1. 在配置解析前启动websocket服务
  2. 每次Bundle打包结束就通过wss通知所有的连接进行更新代码

image.png

这里再顺便解释下为什么用writeBundle这个钩子,因为到了这个阶段,基本可以确保文件都已经写入到了本地环境,这时候插件更新或执行代码就能实时找到,不会出现不存在的报错。

image.png

同时,这里插件定义了两种,因为在系列的第一篇文章里说过,模板里定义了两个vite配置,所以在不同环境上的代码会有所区别,比如端口差别,首次触发reload等。

实际体验

下面就来看看实际体验:

动图里左侧是按钮所在的ContentScript代码,可以看到修改完代码后,动图的右上角的按钮很快就从蓝色变成了红色,说明热更新生效了,效果不错。

下面继续贴上仓库的地址供大家一起讨论学习:

github.com/Tinsson/vit…

结束

这是本系列的第二篇文章,关于Chrome插件这个题材更新起来还是挺费力的,因为目前可以参考的资料都很少,不过目前至少已经简单实现了“热更新”,在效率上有很大提升了。

创造不易,希望jym多多 点赞 + 关注 + 收藏 三连,持续更新中!!!

PS: 文中有任何错误,欢迎掘友指正

往期精彩📌