公司老项目多了,却想用新版本的框架,最好的解决办法就是用微前端。
本文说下我们在用阿里微前端框架qiankun,遇到的一些问题,以及一些巧妙的解决办法。
因为接入微前端很长时间了,导致现在的微应用变成了实际意义上的主应用,主应用反而没有多少功能。于是,想着能不能把两个项目的角色换一下,老的主应用项目,变成微应用;微应用项目变成主应用。这样做有两个好处:
于是,开整。
很快,升级工作进行的差不多了,提测的过程中,发现有些资源文件无法加载,如下图:
于是快速定位,发现是老代码变成微应用之后,在加载资源时,路径还是走主应用。比如:
main-proj
/static/select.pngmicro-proj
/static/select.png本来应该是下面的路径才对,却显示成上面的路径,所以找不到资源。
其实这个问题很多人有遇到 ,于是去官方看下有没有解决方案:
一看还真有,在官方常见问题中有提到:
添加publicPath 、调整静态资源的地址和转Base64.
首先,我们真实环境,老项目是用vue1.x是5年前的项目,我看了下,vue-router还是0.7.x的版本,那个时候,路由配置还没有base,也就是官方教程里的配置:
即使你按照官方的配置走了,也是不起作用的,因为早期版本不支持。找不到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: //ig,
replacement: function (match, p1, offset, string) {
return secrets.web[p1];
}
}
]})
}
]
},
plugins: [
// an instance of the plugin must be present
new 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)
最后,顺利加载:
在官方的解决方案上找不到想要的结果,就只能自己因地制宜了。希望这个思路可以帮到你们,谢谢!