这次,我们的项目需要支持多个国家的用户访问。为了让子应用的访问速度更快,原本考虑使用DNS动态解析IP映射到对应的域名,但由于成本方面的原因,这个方案无法实施。于是,我们只能为子应用申请多个域名,通过主应用根据不同国家进行映射和路由来解决问题。
我们使用的微前端框架是qiankun。在使用qiankun时,有个需要注意的地方:子应用打包的时候得设置publicPath
。要是不设置,访问静态资源时,子应用可能会跑到主应用里去找,这样就容易出现异常。qiankun官方给出的解决办法是把publicPath
的相对路径设置成一个绝对地址的URL,具体的技术细节可以参考qiankun的常见问题文档。不过,按照我们多个域名的实际需求来看,这个方法并不适用。
面对这个难题,团队里的小伙伴很给力,很快就想出了一个解决方案。思路是在打包配置里多生成几个html文件,然后写个插件,用正则表达式把html里引入的静态资源路径替换成对应的域名。这样,主应用访问子应用时,子应用就能根据域名找到对应的html文件,问题似乎就解决了。实现代码如下:
// 编译
replaceDomainPlugin(env),
createHtmlPlugin({
minify: true,
pages: [
{
entry: "src/main.tsx",
filename: "index.html",
template: "index.html"
},
{
entry: "src/main.tsx",
filename: "malaysia.html",
template: "malaysia.html"
}
]
})
// 替换
const replaceDomain = (env: Record<string, string>) => {
const {
VITE_PUBLIC_STATIC_URL,
VITE_PUBLIC_MY_STATIC_URL
} = env;
const regex = new RegExp(VITE_PUBLIC_STATIC_URL, "g");
return {
name: "html-transform",
transformIndexHtml(html: string, options: any) {
switch(options.path) {
case "/malaysia.html":
return html.replace(regex, VITE_PUBLIC_MY_STATIC_URL);
default:
return html;
}
}
};
};
export default replaceDomain;
这个方案虽然可行,但操作起来有点繁琐。后来在空闲时间,我重新查阅qiankun的文档,想看看有没有更简单、更优雅的解决办法。在文档的常见问题版块,我看到了一个关于解决运营商动态插入脚本加载异常导致微应用加载失败的问题,它提到可以使用自定义的getTemplate
方法对子应用的模版进行劫持并修改后再返回。这给了我灵感,我想着能不能在主应用中也用这个方法,对子应用的模版进行劫持,然后把事先约定好的标识位用正则表达式替换掉呢?这样既能解决打包的问题,又能搞定多个域名的维护和加速问题,这不正是我想要的吗?
想到就做!因为我们采用的是手动加载子应用的方式,所以我在loadMicroApp
方法里传入了第二个参数:
loadMicroApp(
{
name: 'microApp',
entry: self.entry,
container: '#microAppContainer',
activeRule: '/#/first/second',
},
{
getTemplate(tpl) {
const newTpl = tpl.replace(/\/regionTag\//g, self.entry);
console.log(`${new Date()} 🚀🚀🚀 ~ newTpl ~ newTpl:`, newTpl);
return newTpl;
}
}
);
从打印的结果来看,完全符合我们的预期。上线之后,替换后的模版也能正常运行,达到了我们的要求。
不过在这个过程中,我也遇到了一个坑。在getTemplate
方法里,没办法获取到vue实例的this
。所以在上面的代码里,我用self
代替了this
。
经过这一番探索和实践,这个关于qiankun微应用动态设置静态资源访问路径的问题算是圆满解决了。希望我的这些经验能给大家在遇到类似问题时提供一些参考和帮助。