All Projects → canyuegongzi → qiankun-simple-main-app-web

canyuegongzi / qiankun-simple-main-app-web

Licence: other
react微前端聚合系统(qiankun.js)

Programming Languages

javascript
184084 projects - #8 most used programming language
HTML
75241 projects
CSS
56736 projects
Dockerfile
14818 projects

Projects that are alternatives of or similar to qiankun-simple-main-app-web

react-micro-frontend-example
One approach for a micro frontend in React.
Stars: ✭ 51 (+168.42%)
Mutual labels:  micro-frontends
scalecube-js
Toolkit for working in microservices/micro-frontends architecture.
Stars: ✭ 63 (+231.58%)
Mutual labels:  micro-frontends
vue-mfe
✨ The easiest way to build a Vue.js micro front-end App.
Stars: ✭ 38 (+100%)
Mutual labels:  micro-frontends
micro-frontend-gateway
🌐 Micro Frontends PoC in Angular - GATEWAY
Stars: ✭ 26 (+36.84%)
Mutual labels:  micro-frontends
fronts
A progressive micro frontends framework for building Web applications
Stars: ✭ 493 (+2494.74%)
Mutual labels:  micro-frontends
ragu
🔪 A micro-frontend framework with Server Side Rendering.
Stars: ✭ 85 (+347.37%)
Mutual labels:  micro-frontends
admincraft
Admincraft is a vue admin application quick build tool
Stars: ✭ 36 (+89.47%)
Mutual labels:  micro-frontends
symbiote.js
Simple, light and very powerful library to create embedded components for any purpose, with a data flow management included.
Stars: ✭ 40 (+110.53%)
Mutual labels:  micro-frontends
angular-react-microfrontend
🚧 React vs Angular ? Why not both ! Micro frontend demo using Angular and React alongs with a NodeJS API
Stars: ✭ 17 (-10.53%)
Mutual labels:  micro-frontends
micro-frontends
example repo for micro frontends with react and dependency inversion as integration pattern
Stars: ✭ 28 (+47.37%)
Mutual labels:  micro-frontends
m-app
📦 微应用容器组件,对 DOM、CSS、JS 进行硬隔离,达到真正的技术栈无关,并且运行时集成,微应用可独立开发、部署、升级。使用如 iframe 般简便,却超脱 iframe 的局限,你值得一试!
Stars: ✭ 81 (+326.32%)
Mutual labels:  micro-frontends
application-modernization-javaee-quarkus
Application Modernization Sample - From Java EE (2010) to Cloud-Native (2021)
Stars: ✭ 99 (+421.05%)
Mutual labels:  micro-frontends
micro-lc
An open source micro-frontend orchestrator
Stars: ✭ 199 (+947.37%)
Mutual labels:  micro-frontends
Microfrontends
Micro-frontend Architecture in Action-微前端的那些事儿
Stars: ✭ 2,696 (+14089.47%)
Mutual labels:  micro-frontends
Qiankun
📦 🚀 Blazing fast, simple and complete solution for micro frontends.
Stars: ✭ 11,497 (+60410.53%)
Mutual labels:  micro-frontends
Micro Frontends
extending the microservice paradigms to web development
Stars: ✭ 3,862 (+20226.32%)
Mutual labels:  micro-frontends
wasedatime-web
An unofficial web app for syllabus searching, classroom finding, and bus schedule checking at Waseda University.
Stars: ✭ 30 (+57.89%)
Mutual labels:  micro-frontends
event-bus
Typesafe cross-platform pubsub event bus ensuring reliable communication between fragments and micro frontends.
Stars: ✭ 15 (-21.05%)
Mutual labels:  micro-frontends

概述

主系统采用乾坤集成react技术栈,子系统技术栈不限,docker部署; 乾坤

预览

技术栈:

  • 主系统:React + Antd + qiankun
  • 子系统:Vue

演示地址

演示地址 github

系统截图

rootwebapp1.png rootwebapp1.png rootwebapp1.png

主系统设计

框架搭建

  1. 系统基础搭建
// 脚手架创建基础代码
npx create-react-app simple-main-app-web
// 暴露配置(能更好的优化webpack打包)
npm run eject
  1. qiankun常用api a. registerMicroApps服务注册 registerMicroApps
const app1 = [
    {
        name: 'app1',                 // 微服务名:需要和子系统中package.json中的name保持一致
        entry: '//localhost:8080',    // 微服务系统地址:子系统入口地址(注意:采坑点)
        container: '#container',      // 子系统需要挂载的节点
        activeRule: '/react',         // 子系统的触发规则可以自定义函数(见genActiveRule)
    }
]
function genActiveRule(routerPrefix) {
    return location => location.pathname.startsWith(routerPrefix);
}
registerMicroApps(app1, {
        beforeLoad: [
            app => {},
        ],
        beforeMount: [
            app => {},
        ],
        afterUnmount: [
            app => {},
        ],
    });

b. start主应用启动 start

// 自定义请求方式
const request = url =>  {return fetch(url, {referrerPolicy: 'origin-when-cross-origin'})};
start({ prefetch: true, fetch: request });

c. setDefaultMountApp设置默认应用 setDefaultMountApp

setDefaultMountApp()

d. runAfterFirstMounted 第一个微应用 mount 后需要调用的方法,比如开启一些监控或者埋点脚本。 runAfterFirstMounted

runAfterFirstMounted(() => doSoming());

用户权限

用户鉴权实现

/**
 * 初始化用户信息
 * @returns {Promise<any>}
 */
export const initUserLogin = (token) => {
    return new Promise(async (resolve) => {
        const userInfo = await $post(userCenterApi.getUerInfoByToken.url, {token: token}, userCenterApi.getUerInfoByToken.server)
        resolve(userInfo);
    })
}
/**
 * 获取微服务列表
 * @returns {Promise<void>}
 */
export const getMicroApps = async () => {
    return new Promise(async (resolve) => {
        const res = await $get(userCenterApi.systemList.url, {page: 1, pageSize: 20}, userCenterApi.systemList.server);
        let systemList = [];
        const resultList = [];
        if (res && res.data && res.data.data) {
            systemList = res.data.data.data;
        }
        for (let i = 0; i < systemList.length; i ++) {
            const value = systemList[i].attrValue.split('::');
            if (value.length > 2 && value[2] === true + '') {
                resultList.push({
                    name: value[0], entry: value[1]
                })
            }
        }
        resolve(resultList);
    })
}
/**
 * 校验用户登录信息
 * @returns {Promise<any>}
 */
export const checkUserInfo = () => {
    return new Promise(async(resolve) => {
        const mimeStorage = new MimeStorage();
        let sessionStorageToken = mimeStorage.getItem('token') || sessionStorage.getItem('token');
        if (sessionStorageToken === "null" || !sessionStorageToken) {
            illegalityUserCallback();
            return;
        }
        const userInfo = await initUserLogin(sessionStorageToken);
        if (userInfo && userInfo.data && userInfo.data.success) {
            const appWebList = await getMicroApps();
            const menus = await getUserMenusList(userInfo.data.data.name, userInfo.data.data.role.id);
            let firstMenus = {}
            if (window.location.hash && window.location.pathname) {
                firstMenus = getFirstmenusByUrl(menus);
            }else {
                firstMenus = getFirstMenus(menus);
            }
            if (firstMenus && firstMenus.firstKey) {
                window.history.pushState({}, '聚合管理系统', firstMenus.firstKey);
            }
            resolve({success: userInfo.data.success, userInfo: userInfo.data.data, appWebList: appWebList, menus, firstMenus })
            return;
        }
        illegalityUserCallback();
    })
}

自定义hooks

  1. 个人配置hooks 主要用户存储用户的个性化的配置信息
/**
 * 个人配置
 */
export function usePerrsonSetting() {
    const [theme, setTheme] = useState(loadPersonConfig() ? loadPersonConfig().theme : 'dark');
    const [navModal, setNavModal] = useState(loadPersonConfig() ? loadPersonConfig().navModal : 'vertical');

    /**
     * 加载个人配置
     * @returns {null}
     */
    const loadConfig = () => {
        const storeConfig = window.localStorage.getItem('personConfig');
        return storeConfig ? JSON.parse(storeConfig) : null;
    }

    /**
     * 保存配置
     * @type {Function|*}
     */
    const setConfig = useCallback((data = {theme: 'dark', navModal: 'vertical'}) => {
        setNavModal(data.navModal);
        setTheme(data.theme);
        const newConfig = loadConfig() ? {...loadConfig(), theme: data.theme, navModal: data.navModal }: {theme: data.theme, navModal: data.navModal};
        window.localStorage.setItem('personConfig', JSON.stringify(newConfig));
    }, [theme, navModal]);

    return {
        setConfig, theme, navModal, loadConfig
    }
}
  1. 上一状态hooks
/**
 * 上一状态
 * @type
 */
export const usePrevious = (function (state, compare) {
    const prevRef = useRef();
    const curRef = useRef();
    const needUpdate = typeof compare === 'function' ? compare(curRef.current, state) : true;

    if (needUpdate) {
        prevRef.current = curRef.current;
        curRef.current = state;
    }

    return prevRef.current;
});

子系统设计

生命周期改造

  1. webpack配置修改 a. publicPath保持绝对路径或者 './'
publicPath: './', || 'http://canyuegongzi.xyz/simple-user-center-web/'

b. output打包格式修改 打包输出文件修改为umd, 方便主应用采用fetch拉取代码

output: {
            library: '[name]',
            filename: '[name].js',
            libraryTarget: 'umd',
        },

c. 生命周期暴露 主应用需要识别子系统暴露的生命周期函数

/**
 * bootstrap 只会在微应用初始化的时候调用一次,下次微应用重新进入时会直接调用 mount 钩子,不会再重复触发 bootstrap。
 * 通常我们可以在这里做一些全局变量的初始化,比如不会在 unmount 阶段被销毁的应用级别的缓存等。
 */
export async function bootstrap() {
  console.log("VueMicroApp bootstraped");
}

/**
 * 应用每次进入都会调用 mount 方法,通常我们在这里触发应用的渲染方法
 */
export async function mount(props: any) {
  console.log("VueMicroApp mount", props);
  render(props);
}

/**
 * 应用每次 切出/卸载 会调用的方法,通常在这里我们会卸载微应用的应用实例
 */
export async function unmount() {
  console.log("VueMicroApp unmount");
  instance.$destroy();
  instance = null;
  router = null;
}

d. 子应用保持活性 子应用需要通过判断是否是微服务聚合系统中,来创建不同性质的Vue实例(子系需要能单独访问也能在聚合系统中访问)

if (window.__POWERED_BY_QIANKUN__) {
  // 动态设置 webpack publicPath,防止资源加载出错
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}

example
let router: any = null;
let instance: any = null;

function render({ data = {} , container } = {}) {
  console.log(container)
  instance = new Vue({
    router: getRouter(allMenus),
    store,
    render: h => h(App),
  }).$mount("#app");
}
if (!window.__POWERED_BY_QIANKUN__) {
  escapeCheckSession$().then((router: any) => {
    instance = new Vue({
      router,
      store,
      render: (h) => h(App),
    }).$mount("#app");
  });
}

部署

为最大限度的保持系统稳定性(刷新问题,微应用触发),系统部署是主应用采用history路由格式,子应用(通常部署在二级目录下)采用hash路由

子应用部署

rootwebapp4.png

主应用部署

主应用采用history路由,为保证刷新不存在问题部署在nginx一级目录下(也可以通过nginx的重定向配置解决);

  1. Dockerfile
FROM nginx:latest
MAINTAINER canyuegongzi
EXPOSE 10010
COPY micro-apps-web/  /usr/local/nginx/dist/
COPY nginx.conf /etc/nginx/nginx.conf
RUN echo 'build image success!!'
  1. nginx.conf
worker_processes auto;
#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    client_max_body_size   20m;
    server {
        listen       10010;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;
     location / {
        root   /usr/local/nginx/dist;
        index  index.html index.htm;
        try_files $uri $uri/ /index.html;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }

    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}

}

容器化

docker build -t microapp:latest .

容器启动

ocker run -d -it --restart=on-failure:3 --name microapp -p 10010:10010 244341b5bc37

采坑点

主系统接入子系统

子系统接入系统入口必须为目录(针对子系统部署在二级目录的情况) rootwebapp5.png

子系统部署

子应用部署和普通工程相同(最好采用hash路由格式)

主系统部署

主应用部署最好部署在一级目录下(多级目录下需要自定义子应用注册的activeRule函数特殊处理)

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].