将Web 项目打包成浏览器插件
最近重新思考如何将一个Web项目打包成浏览器插件,利用浏览器插件的options页面来作为Web项目的入口index.html
。具体就是,如何不改动doocs/md 项目源码,仅通过WXT
框架及打包命令完成改造。这是一款微信 Markdown 编辑器在线项目,功能非常丰富,为了尽最大的可能迁移所有功能,改造过程比较曲折,这里将遇到的主要问题及解决方案记录如下,那就让我们开始吧!
项目初始化与配置
1.1 项目初始化
采用From Scratch 方式,为已有的项目增加wxt.config.ts
等配置,这一步可以参考官方指引
为了插件能够基本启动起来,需要至少配置一个WXT
要求的入口点,那么可以学习官方的demo 做法,
WXT
的项目结构有点特殊,所以结合doocs/md 项目原有结构调整 wxt.config.ts
配置,主要是调整 srcDir
publicDir
base
等属性,
同时也可以看到,在 wxt.config.ts
可以沿用原来项目中的 vite.config.ts
配置。
1.2 配置增加入口点 (EntryPoint)
由于很难同时满足两种项目的结构形式,此时index.html
并不是 WXT
的一个入口点,所以需要动态方式配置,这一个环节需要参考 WXT
框架的 hooks 相关说明。 同时也要了解下 WXT Modules
,到时候会用到。
解决办法如下,在 srcDir/modules
目录下新增一个WXT Modules
定义,在WXT
解析完整个 wxt.config.ts
后会调用这个模块的方法。
CDN资源本地化处理
由于原来项目中的Tex数学公式转svg、一键发布功能,引用了外部CDN js资源,而这个行为是被浏览器插件禁止的。其实包括内联的script内容也是不被允许的。
这一步我通过阅读 WXT
框架自己实现的 devHtmlPrerender
vite 插件源码进行模仿解决的。从它的源码中可以找到相关介绍说明
2.1 将CDN JS转换为虚拟文件
这一步的做法是将 CDN js资源下载下来,保存到内存中,然后修改原始CDN js链接,改为引用请求虚拟文件地址。 参考:虚拟模块相关说明
大部分的代码思路是参考了 devHtmlPrerender
插件的。
然后需要把这个插件引入到 wxt
中,同样是刚才的 build-extension.ts
模块加入这个插件,
在此之前以为浏览器插件形式下是无法使用Vue DevTools
的,也无从下手解决这个问题,一般是屏蔽掉这个插件。
自从了解了vite虚拟模块虚拟文件后,观察Vue DevTools引入后在html中的引用形式,
解决方案就比较明显了,调整script引用链接,在url前加${server.origin}
, 调整后html中的这两个脚本就是
这样子才能发起http请求,走vite server的虚拟模块匹配逻辑。要不然,其实请求的最终地址是,类似
当然就无法处理的。
解决方案:用vite 插件做一个hack,
相关讨论,how to use vue-devtools in chrome extension options page #727
打包构建方案
3.1 虚拟文件持久化
经过同事的提醒,刚开始的调研方向是将虚拟文件打包进最终的产物,但是忽略了dev和build模式的区别。
在dev模式下,html页面中的script引用地址被修改为http请求虚拟文件地址,但是build模式下并不会直接沿用dev的这个过程,而且进一步分析,build模式下,script引用地址也不应该修改成http地址形式,应该是本地地址或者相对地址。
3.2 将CDN JS转换为本地文件
经过这一番分析后,还是决定针对build模式再重新写一个vite插件来处理,同时一并考虑保存地址及html引用地址,插件如下,
相关讨论:how to deal with cdn js files #1255
最终引入自实现的插件配置如下,
解决打包体积过大问题
这是一个遗留了大半年的问题,通过vite等官方指引配置build?.rollupOptions.output.manualChunks
并没有效果,而且还可能导致build 出错。。
相关讨论file of zip output is too large that expend firefox 4MB limit #765
其中打包后单文件体积超过4MB的是options这个chunk,意思就是 option entrypoint 把所有依赖都打包一起了。 本次研究出来cdn js本地化的方案过程中,对WXT
框架源码增加了不少认识,经过一番hacking,算是找到了改变打包配置的WXT
hook。
解决方案,选择哪些依赖单独分包,可以通过npx wxt build --analyze
命令得到报告。
之所以不能在全局配置manualChunks
,是由于WXT
是多模块的打包方式,在background
这个entrypoint打包的时候配置分包方式会由于不支持而报错。而针对option entrypoint单独修改,在WXT
调用vite#build
方法前修改(请在WXT
源码中搜索关键方法:buildEntrypoints),就可以顺利完成分包。分包的效果是options chunk主包体积减少,其他分包/chunks
目录,被options chunk引入。
结语
本次的改造保留了原有项目100%的功能,非常不容易,主要的举措是动态配置Entrypoint入口文件,利用Vite插件处理cdn js资源,hack Vue DevTools插件地址引用错误问题。对于dev和build两种模式区别处理cdn js资源的做法或许可以合并成一种,有待后续研究改进。
这款插件的最大好处就是引入了公众号素材库(图床)功能,在撰写公众号文章的时候不用使用其他图床,而且通过openapi形式与公众号素材库接口打通,粘贴图片即可上传并使用,包括预览效果都是支持的。
相关使用教程,请参考公众号文章编辑器插件教程。新版本插件即将发布审核上架,敬请期待!