❧ 微前端qiankun应用
问题解决:
1、报错 Target container with #container not existed while xxx mounting
子应用中不能包含 document.write 改变dom会使容器丢失
2、提取复用公共依赖
子项目 index.html 中公共依赖的 script 和 link 标签加上 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 一样(否则主应用页面刷新就变成微应用)
微应用配置
module.exports = { publicPath: process.env.NODE_ENV === 'production' ? '/app1/' : `//localhost:${port}`,}
// 路由配置export default new VueRouter({ base: window.__POWERED_BY_QIANKUN__ ? '/lucky/' : '/', mode: 'history', //后端支持可开});nginx配置
# 主应用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对象,确保拿到实例化后的对象