公司老项目多了,却想用新版本的框架,最好的解决办法就是用微前端。
本文说下我们在用阿里微前端框架qiankun,遇到的一些问题,以及一些巧妙的解决办法。
背景
因为接入微前端很长时间了,导致现在的微应用变成了实际意义上的主应用,主应用反而没有多少功能。于是,想着能不能把两个项目的角色换一下,老的主应用项目,变成微应用;微应用项目变成主应用。这样做有两个好处:
- 如果当前需求不涉及老业务,微应用的老代码就不用发版了。
- 可以顺便升级项目的路由、鉴权等基础逻辑。
于是,开整。
遇到问题
很快,升级工作进行的差不多了,提测的过程中,发现有些资源文件无法加载,如下图:
于是快速定位,发现是老代码变成微应用之后,在加载资源时,路径还是走主应用。比如:
- 主应用: http: //my.proj.com/
main-proj
/static/select.png - 微应用: http: //my.proj.com/
micro-proj
/static/select.png
本来应该是下面的路径才对,却显示成上面的路径,所以找不到资源。
官方答疑
其实这个问题很多人有遇到 ,于是去官方看下有没有解决方案:
一看还真有,在官方常见问题中有提到:
添加publicPath 、调整静态资源的地址和转Base64.
尝试解决
首先,我们真实环境,老项目是用vue1.x是5年前的项目,我看了下,vue-router还是0.7.x的版本,那个时候,路由配置还没有base,也就是官方教程里的配置:
vue-router0.7.x版本源码:
即使你按照官方的配置走了,也是不起作用的,因为早期版本不支持。找不到base相关的代码。
那为什么不升级老项目呢?
这个问题我也想过,只是项目太复杂且工作量太大,我情愿找到一个能解决资源路径的办法也不想去动老代码。
继续想办法
如果启动的时候配置不了base,那打包的时候行吗?答案是可以,但是有问题。我尝试在webpack中添加publicpath。
module.exports = function (config) {const webpack = require(path.resolve(config.mumbleDir, './node_modules/webpack'));const cfg = {......module: {noParse: [/vue-router\.js/]},devServer: {headers: {'Access-Control-Allow-Origin': '*'}},output: {filename: '[name].js', // 输出文件名library: `${name}-[name]`, // 暴露给全局变量的名称libraryTarget: 'umd', // 导出库方式umdNamedDefine: true, // 是否将AMD模块命名publicPath: `${config.env === 'develop' ? 'http://my.proj.com/micro-proj' : 'http://my.prod.proj.com/micro-proj'}/static/`}};return cfg;
};
通过这样的配置,可以部分资源能够使用,为啥说部分资源呢?因为老的webpack在打包静态资源的时候有些资源在Css文件中的路径是相对路径。
往后讲,我们也有CDN资源,但是这个只用于对外的项目,内部项目一般都是资源打包,所以不太妥。
base64也解决不了问题,因为有些字体就很大,不适合用这种方式。
新的思路
突然想到,如果我能通过webpack插件来把资源都改成微应用路径不就行了?于是找了个插件string-replace-webpack-plugin
var StringReplacePlugin = require("string-replace-webpack-plugin");
module.exports = {module: {loaders: [// configure replacements for file patterns{ test: /index.html$/,loader: StringReplacePlugin.replace({replacements: [{pattern: /<!-- @secret (\w*?) -->/ig,replacement: function (match, p1, offset, string) {return secrets.web[p1];}}]})}]},plugins: [// an instance of the plugin must be presentnew StringReplacePlugin()]
}
配置好了没有一点反应,不知道是不是因为老项目的webpack版本太低还是其他原因。然后还想到,我们项目有生产和测试环境,测试环境还有好多个,这种绝对路径替换的方案也不太行的通。
巧妙解决
在上面的思路基础上,再回想下现在的现象,就是资源文件总是会跑到主应用的路径上去,那如果把微应用的资源移到主应用中去,不就能找到了?
select{width: 200px;height: 30px;padding: 4px 10px;border: $border;-webkit-appearance: none;-moz-appearance: none;appearance: none;background-image: url("/select.png");background-repeat: no-repeat;background-position: right 10px center;background-color: $white;
}
资源文件用绝对路径,同时,把资源放到主应用的public下面(基于框架,我们的框架放到这个目录会自动打包Copy到Dist)
最后,顺利加载:
总结
在官方的解决方案上找不到想要的结果,就只能自己因地制宜了。希望这个思路可以帮到你们,谢谢!