跳转到内容

❧ 微前端qiankun应用

官方文档

问题解决:

1、报错 Target container with #container not existed while xxx mounting

子应用中不能包含 document.write 改变dom会使容器丢失

2、提取复用公共依赖

子项目 index.html 中公共依赖的 scriptlink 标签加上 ignore 属性(自定义的属性,非标准属性)

<link ignore rel="stylesheet" href="//cnd.com/antd.css">
<script ignore src="//cnd.com/antd.js"></script>

qiankun 便不会再去加载这个 js/css,而子项目独立运行,这些 js/css 仍能被加载

需要注意的是,主项目中的公共依赖需要暴露出来(挂载到 window 上),且需要和子项目版本保持一致。

3、第三方CDN的css引入的资源404解决

将相对url标识变换为绝对url

let getAsStyle=(url)=> {
return fetch(url, {
method: 'GET',
headers: {
'accept': 'text/css,*/*;q=0.1'
}
}).then((res)=>{
if(!res.ok){
throw new Error('Error loading '+url+' '+res.status+' ('+res.statusText+')');
}
let contentType=res.headers.get('content-type');
let type=contentType?contentType.split(/; ?/)[0]:'text/css';
if(type!=='text/css')
console.warn('Resource interpreted as Stylesheet but transferred with MIME type '+type+': "'+url+'".');
return res.text();
}).then((text)=>{
let rUrl=/(https?|data):/;
let replacement=($0, prefix, path, suffix)=>{
if(rUrl.test(path)){
return $0;
}else if(path.charAt(0)==='/' && new URL(url).origin===location.origin){
return $0;
}else{
return prefix+new URL(path, url)+suffix;
}
};
// transform leading `@import 'xxx.css'`
text=text.replace(/(@import\s*['"])([^'"]+)(['"])/g, replacement);
// transform `url(xxx.jpg)`
text = text.replace(/(url\(\s*['"]?)([^'"\s()]+)(['"]?\s*\))/g, replacement);
// transform trailing `sourceMappingURL=xxx.map`
text = text.replace(/(\/[*\/][@#] sourceMappingURL=)(\S+)(( \*\/)?[\r\n]*)$/mg, replacement);
return text;
}).then((text)=>{
let style=document.createElement('style');
style.type='text/css';
style.setAttribute('data-src', url);
style.appendChild(document.createTextNode(text));
return style;
});
};

子应用中的使用方法:

let instance = null;
function render(props = {}) {
const { container } = props;
if (!container) {
instance = new Vue({
router,
store,
render: (h) => h(App),
}).$mount('#app');
return;
}
getAsStyle('https://cdn.bootcdn.net/ajax/libs/element-ui/2.9.2/theme-chalk/index.css').then((style)=>{
// container.appendChild(style);
// 插入前边儿防止样式覆盖
container.insertBefore(style, container.childNodes[0]);
instance = new Vue({
router,
store,
render: (h) => h(App),
}).$mount(container.querySelector('#app'));
});
}

4、nginx多服务器部署

主应用配置

registerMicroApps([
{
name: 'lucky', // app name registered
entry: '/app1/',
container: '#main-app-container',
loader: loading => render({ loading }),
activeRule: '/lucky',
}
]);

activeRule 不可以和 entry 一样(否则主应用页面刷新就变成微应用)

微应用配置

vue.config.js
module.exports = {
publicPath: process.env.NODE_ENV === 'production' ? '/app1/' : `//localhost:${port}`,
}
// 路由配置
export default new VueRouter({
base: window.__POWERED_BY_QIANKUN__ ? '/lucky/' : '/',
mode: 'history', //后端支持可开
});

nginx配置

Terminal window
# 主应用
server {
listen 3000;
#server_name 0.0.0.0;
root /home/difei/test/qiankun-gm/mainapp/dist;
location /app1 {
proxy_pass http://localhost:8080/app1/;
proxy_set_header Host $host:$server_port;
}
location / {
try_files $uri $uri/ /index.html;
}
}
# 子应用
server {
listen 8080;
#server_name 0.0.0.0;
root /home/difei/test/qiankun-gm/LuckyGM/dist;
location /app1/ {
alias /home/difei/test/qiankun-gm/LuckyGM/dist/;
}
location ~ /index {
try_files $uri $uri/ /index.html;
}
}

5、路由混乱问题

微应用每次挂载都要重新初始化 路由 对象

若其他文件使用router实例化对象,main.js文件导出一个函数返回router对象,确保拿到实例化后的对象