微前端之qiankun

296 阅读1分钟

微前端该怎么理解呢?微小的前端吗?根据字面意思好像可以这么拆解,实际呢,在我们的前端应用中可以把一个大的项目,分为多个小应用,多个应用之间相互独立,互不影响,独立的技术栈,独立的部署环境,最终把这些独立的子应用,放入到我们的主应用中,称之为微前端,这是大面包的理解。

1651559580(1).png

一、准备一个框架,作为项目的主应用

项目安装此处省略,大面包用vue项目作为主应用

二、安装qiankun

在主应用安装qiankun

npm i qiankun //默认安装到dep

三、在主应用使用qiankun

//App.vue
<div>
    <div class="tab">
        <router-link :to="item.path" v-for="item in routerPath" :key="item.name">
            <span class="span" :class="{'active': $route.path === item.path}">{{item.name}}</span>
        </router-link>
    </div>
    <!-- 页面渲染 -->
    <router-view></router-view>
    <div id="sub-container"></div>
</div>

//routerPath
routerPath: [
    {
            name: 'Home',
            path: '/home'
    },
    {
            name: 'Vue',
            path: '/vue'
    },
    {
            name: 'React',
            path: '/react'
    }
]
//main.js
//1.引入qiankun
import { registerMicroApps, start } from 'qiankun';

//路由为哈希时或许可以用到
//const getActiveRule = (hash) => (location) => location.hash.startsWith(hash);

//2.配置子应用
const apps = [
    // 子应用1:qiankun-vue
    {
        // 子应用名称
        name: "vueAPP",
        // 子应用入口:默认会加载这个 html 并解析里里面的 js 然后动态的执行(子应用必须支持跨域)
        entry: process.env.VUE_APP_SUB_VUE,
        // 容器:将子应用挂载到 #sub-container 元素上
        container: "#sub-container",
        // 激活规则:访问 /vue 时将子应用挂载到 #sub-container 上
        activeRule: '/vue',
        // 传递属性
        props: {
            name: "大面包",
            sex: "男",
        },
    },
    // 子应用2:qiankun-react
    {
        // 子应用名称
        name: "reactAPP",
        // 子应用入口:默认会加载这个 html 并解析里里面的 js 然后动态的执行(子应用必须支持跨域)
        entry: process.env.VUE_APP_SUB_REACT,
        // 容器:将子应用挂载到 #sub-container 元素上
        container: "#sub-container",
        // 激活规则:访问 /react 时将子应用挂载到 #sub-container 上
        activeRule: "/react",
        // 给子应用传递属性
        props: {
            name: "Chess",
            sex: "男",
        },
    },
];

//3.注册apps
registerMicroApps(apps);

//4.启动微前端
start();

四、新建一个vue子应用

//main.js
let instance = null;
function render() {
    instance = new Vue({
        router,
        render: h => h(App),
    }).$mount('#vue-app')
}
// 动态添加 publicPath
if (window.__POWERED_BY_QIANKUN__) {
    //处理资源
    __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}

// 判断当前应用是否不在 qiankun 中渲染
if (!window.__POWERED_BY_QIANKUN__) {
    // 如果不在 qiankun 中,则直接渲染
    render();
}

// 需要导出 qiankun 内部的三个生命周期钩子,以供主应用在合适的时机调用。
// 第一次进入时;props 包含主应用传递的参数,也包括为子应用创建的节点信息。
export async function bootstrap() {
    console.log("子应用 2 加载完成");
}

// 每次进入子应用时
export async function mount(props) {
    render(props)
}

// 每次退出子应用时
export async function unmount() {
    // 卸载子应用
    instance.$destroy()
    console.log("子应用 2 卸载完成");
}
//vue.config.js
devServer: {
    port: 8000,
    // 配置头信息
    headers:{
        // 设置访问此网站的域名
        'Access-Control-Allow-Origin' : '*'
    },
},

五、我们再来新建一个react的子应用

//1.首先准备一个react项目
//2.安装一个react-app-rewired重写配置文件
npm i react-app-rewired 

//3.修改package.json
"scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-app-rewired eject"
}

//4.根目录下新建一个config.overrides.js
module.exports = {  
    webpack:(config) => {    
        config.output.library = 'reactApp';    
        config.output.libraryTarget = 'umd';    
        config.output.publicPath = 'http://localhost:3000/';    
        return config;  
    },  
    devServer:(configFunction) => {    
        return function (proxy, allowedHost) {      
            const config = configFunction(proxy, allowedHost)     
             config.port = '3000'      
             config.headers = {        
                 'Access-Control-Allow-Origin': '*'     
            }      
            return config    
        }  
    }
}

//修改index.js, 导入qiankun内部的三个生命周期钩子
function render() {
    ReactDOM.render(
        <Test />,
        document.getElementById('root')
    );
}
// 判断当前应用是否不在 qiankun 中渲染
if(!window.__POWERED_BY_QIANKUN__){
    render();
}

export async function bootstrap(){

}

export async function mount() {
    console.log('react')
    render()
}

export async function unmount(){
    ReactDOM.unmountComponentAtNode( document.getElementById('root'));  // 卸载节点
}

此时我们的页面效果已经出来的

1651574656.jpg

1651574656(1).jpg

1651574656(2).jpg

在搬砖的道路上砥砺前行~