Frontend Development 20 min read

Wujie Micro Frontend Implementation Guide

This article details a practical implementation of the Wujie micro‑frontend framework across three Vue‑based management systems, covering preparation of the host app, login state handling, layout selection, event bus integration, network request management, UI adjustments, and shared state synchronization, with code snippets and lessons learned.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Wujie Micro Frontend Implementation Guide

This article is aimed at readers who already have some understanding of Wujie and micro‑frontends and does not repeat basic concepts.

Background

The author’s department maintains three management systems with the following technology stacks:

A: Vue2 + Webpack4 + [email protected]

B: Vue3 + Webpack5 + [email protected]

C: Vue3 + Vite2 + [email protected]

All three are pure business‑oriented systems that users frequently switch between, leading to a large number of browser tabs.

Why Choose Wujie?

The author lists three personal reasons for selecting Wujie over alternatives such as qiankun:

Desire to try something new; previous qiankun experience felt unexciting.

Low‑intrusion integration: most sub‑applications can be added with almost zero code changes.

Independent development and deployment: Wujie’s WebComponent + iframe approach preserves existing domains and deployment pipelines while providing a fallback if the micro‑frontend fails.

Practical Steps (Dry‑Goods)

Prepare the host application.

Manage sub‑application login state.

Choose a layout strategy based on the host environment.

Install wujieEventBus , a wrapper around Wujie’s built‑in event bus.

Handle the afterMount lifecycle of sub‑applications.

Manage network requests and CORS.

Fix UI component positioning issues.

Promote shared state to the host.

1. Prepare the Host Application

The host uses the same stack as system C: Vue3 + Vite2 + [email protected] . The directory structure is straightforward and does not require special packaging.

2. Sub‑Application Login State Management

When a sub‑application’s login expires, it should redirect to the host’s login page instead of its own. Two places need handling:

HTTP response interceptor (example with Axios):

if (response.status === 401) {
if (window.__POWERED_BY_WUJIE__) {
wujieEventBus.$emit("LOGIN_EXPIRED", APP_NAME_IN_WUJIE);
} else {
message.error("登录失效,请重新登录");
router.replace("/login");
}
}

The global variable window.__POWERED_BY_WUJIE__ indicates that the code runs inside a Wujie container, and wujieEventBus is the custom event bus used to notify the host.

Router guard (example using beforeEach ):

router.beforeEach((to, from, next) => {
if (validToken()) {
// your logic …
next();
} else {
wujieEventBus.$emit("LOGIN_EXPIRED", APP_NAME_IN_WUJIE);
}
});

3. Layout Selection

Three layout ideas are discussed. The author finally adopts the third approach: the host provides a global Header and Menu , while sub‑applications only render their Content . This reduces the need to modify each sub‑application’s menu.

<template v-if="!isInWujieContainer">
<Menu />
<Layout>
<Header />
<Layout>
<keep-alive>
<router-view />
</keep-alive>
</Layout>
</Layout>
</template>
<template v-else>
<keep-alive>
<router-view />
</keep-alive>
</template>
// const isInWujieContainer = window.__POWERED_BY_WUJIE__

When a menu item is clicked, the host emits a CHANGE_ROUTE event via wujieEventBus , and the target sub‑application updates its router accordingly.

// Host side
export const openChildRoute = (_router, app) => {
EventBus.$registerMountedQueue(app, "CHANGE_ROUTE", { path: _router.path, app });
router.push(fullPath);
store.commit("tabs/setList", { fullPath, name: _router?.name || "", title: _router?.name });
setActiveKey(fullPath);
};
// Sub‑application side
wujieEventBus.$on("CHANGE_ROUTE", ({ path, query, app }) => {
if (app !== APP_NAME_IN_WUJIE) return;
router.push({ path, query });
});

4. Install wujieEventBus

The author wraps Wujie’s native bus with a small utility that supports event registration before a sub‑application is mounted. The utility queues events and flushes them once the sub‑application’s afterMount hook runs.

import WujieVue from "wujie-vue3";
import { AppCollection } from "@/constant";
import store from '@/store';
const { bus } = WujieVue;
type EventList = "LOGIN_EXPIRED" | "EVENT_NAME1" | "EVENT_NAME2";
type EventBusInstance = {
$emit: (e, params) => void,
$on: (e, fn) => void,
$registerMountedQueue: (app, e, params) => void,
$cleanMountedQueue: (app) => void,
};
let instance;
export default () => {
const queue = {};
if (!instance) {
instance = {
$emit: (event, params) => bus.$emit(event, params),
$on: (event, fn) => bus.$on(event, fn),
$registerMountedQueue: (app, event, params) => {
const isMounted = store.state.globalState.appMounted[app];
const fn = () => bus.$emit(event, params);
if (isMounted) return fn();
queue[app] ? queue[app].push(fn) : (queue[app] = [fn]);
},
$cleanMountedQueue: (app) => {
while (queue[app] && queue[app].length) {
const fn = queue[app].shift();
fn();
}
},
};
}
return instance;
};

5. afterMount Lifecycle

In the sub‑application’s afterMount hook, the author records the mount status in the Vuex store and clears the queued events:

// Example inside afterMount
store.commit('globalState/appMounted', { [APP_NAME_IN_WUJIE]: true });
wujieEventBus.$cleanMountedQueue(APP_NAME_IN_WUJIE);

6. Network Request Management

Two CORS scenarios are covered:

Calling backend services: if authentication uses cookies, forward the host’s fetch to the sub‑application; if JWT is used, configure the backend to allow the host’s origin (avoid Access-Control-Allow-Origin: * in production).

Fetching static assets of sub‑applications: adjust the static server (e.g., Nginx) to allow the host’s origin.

7. UI Component Position Fixes

Issues with element-plus pop‑ups and Ant Design Vue drawers are described. The temporary fixes involve adding position: relative to the body for pop‑ups and switching drawer placement from left to right when the fixed container’s positioning interferes.

8. Shared State Promotion

Common enumeration data (e.g., dictionaries) are fetched once by the host and pushed to sub‑applications via the event bus, avoiding duplicate requests. Example code shows the host registering a SYNC_STATE event and the sub‑application applying the received data to its Vuex store.

// Host side
bus.$registerMountedQueue('APP_NAME', "SYNC_STATE", { type, data: toRaw(data) });
// Sub‑application side
if (window.__POWERED_BY_WUJIE__) {
wujieEventBus.$on("SYNC_STATE", ({ type, data }) => {
const [updateFn, stateKey, ...restPath] = type;
let config = state[stateKey];
if (restPath.length) { set(config, restPath, data); } else { config = data; }
mutations[updateFn](state, config);
});
} else { /* old init logic */ }

Conclusion

The author reflects that the implementation took about a week, acknowledges that some details were rushed, and invites readers to ask questions or share experiences. The article is not a complete end‑to‑end solution but a collection of practical insights gained during the rollout.

frontendlayoutmicro‑frontendVueEvent Buslogin-managementwujie
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.