本文最后更新于:2024-11-02T17:08:04+08:00
前言
分享一个近期工作中遇到的关于IFrame的需求,以及解决方案。
需求大致是说在我们系统中嵌套了另一个文档页面,这个文档页面是爬取的,并且页面是原先使用后端渲染实现的,取到的css和script标签都是相对路径比如: “./mian.css” 这种,这么写会导致当origin发生变化时取不到静态资源,怎么解决这个问题呢?
解决方案思考
使用Nginx做反向代理
配置Nginx反向代理,在Nginx配置中添加一个代理规则,将请求定向到目标文档页面的地址。
后端动态修改页面路径
将相对路径改为绝对路径,通过解析文档页面,找到其中的相对路径资源引用,将其改为绝对路径。这样不受origin变化的影响。
前端代理(只能在dev环境下实现)
使用vite的proxy实现反向代理效果
先说结论,上述三种方式均被pass了
第一种方法由于页面请求到了宿主的网址下,导致Nginx监听不到资源请求,再有是前端想配置Nginx并不容易。。。
第二种缺乏可复用性,如果宿主的origin发送变化,则后端规则也要跟着改变
第三种就更不用说了,只能在开发环境下实现,不过这种方式给了我一定的启发,如果将静态资源打包进正式包里,再动态修改IFrame的资源路径,或许可以解决相关问题
设计概要
有了方案就需要技术的实施,总共有两步:
第一步是将静态资源打包进正式包中,这里可以使用rollup的插件rollup-plugin-copy来达到复制静态资源的目的
第二步是动态修改iframe中的link标签的href地址,达到资源替换的效果
方案实现
静态资源打包
和webpack有些不同,webpack可以通过CopyWebpackPlugin或者IgnorePlugin等方式复制或排除文件,而使用vite则需要借助其他plugs工具实现,比如vite-plugin-cp或者vite-plugin-static-copy,然而事情并没有这么简单,由于项目环境的复杂性较高,在esm和cjs上发生了错误,有些包是以esm导入的,但是项目中什么文件都有,无法兼顾既要又要,就像下面这样:
为了尽量不改变项目结构,我决定自己造轮子,自己写个插件,在vite的closeBundle生命时将上面要用到的静态文件复制到dist文件夹下
在项目根目录下新建script文件夹,创建新的脚本
其中helpers是工具函数
接着实现一下复制文件夹的node脚本
然后实现一下vite插件的hook函数,需要注意的是,在我的脚本之前有个打包zip的插件,为了在zip打包之前进行复制静态文件操作,我做了个异步响应操作
最后是在vite.config中使用
实现效果就是下面这样的
打包后的效果
iframe的通信及标签动态修改
参考之前写的博客,我们可以取iframe的标签并对其dom进行操作,这里我是在react中进行操作,所以写个ref获取标签,其中我们通过iframe.contentWindow.document获取到iframe的dom对象,然后对其内容进行修改,由于操作的步骤不多,使用ipc反而会增加代码量,完整的代码如下
上述代码中,我们将iframe中的相对资源路径改到了项目的./static中,修复了资源缺失的问题。
效果展示
在使用了上述方案对项目打包后,之前的资源未找到的问题也被解决,效果如下
可以看到在iframe中首先会加载两次资源,在未取到资源后,又会重新获取两个css资源,随后DOM树和CSS树发生重排操作重新渲染,虽然有比较明显的样式过渡,但是这已经是目前最佳的解决方案了
写在最后
本文分享了通过打包静态资源并动态替换 iframe 中的资源路径,成功解决了因 origin 变化导致的资源加载问题。这种方案也让我想起了原先写的:基于内网穿透+Fiddler的私有化项目调试前端解决方案_fiddler onbeforerequest-CSDN博客
二者在实现方案上不太相同,但是思路还是有相似之处的
以上就是文章全部内容了,感谢你看到了最后,如果觉得文章不错的话,还望三连支持一下,谢谢!