Scalable Front-End Architecture for Marketing Tools: Component Reuse and Micro‑Frontend Design
To meet soaring marketing‑tool demand with limited front‑end staff, the team built a three‑layer, micro‑frontend architecture—page container, scenario template, and business customization—augmented by a plugin‑style micro‑kernel, enabling over 50 % faster development, consistent UI, and configurable blocks, while acknowledging added complexity and performance trade‑offs.
In response to a surge of marketing‑tool business demands and limited front‑end manpower, the team needed a way to support a much larger volume of pages while maintaining delivery quality and user experience.
The core problem was phrased as: How to efficiently and with high quality support more requirements than before? The initial idea was to increase code reuse.
A three‑layer architecture was designed:
Page Container Layer : consolidates common infrastructure such as UI framework, configurable modules (e.g., banner, announcements), request utilities, and global dependencies.
Scenario Template Layer : abstracts reusable parts of business modules that share a common > different relationship (e.g., list pages consisting of Tab, filter form, list, pagination). This layer is optional and can be shared across tools.
Business Customization Layer : implements tool‑specific differences.
Implementation leverages a micro‑frontend approach. The main application routes to different micro‑modules and injects a shared pageContext for communication:
import { MicroModule } from '@ice/stark-module';
// route → module mapping
const MPathToModuleBaseInfo = {
'/toolA/home': { name: 'toolA-home-module', url: 'https://xxx.xxx.xxx' },
'/toolA/create': { name: 'toolA-create-module', url: 'https://xxx.xxx.xxx' },
// ...
};
export default function App() {
const [state, setState] = useState(1);
const pageContext = useMemo(() => ({ setState }), []);
return (
<MicroModule moduleInfo={MPathToModuleBaseInfo[location.pathname]} pageContext={pageContext} />
);
}The corresponding micro‑module receives the context and can trigger state changes:
export default function Module(props) {
const { pageContext } = props || {};
const handleClick = () => {
pageContext.setState(pre => pre + 1);
};
return <button onClick={handleClick}>state + 1</button>;
}To avoid coupling the scenario template layer to the main app or each micro‑module, a micro‑kernel (plugin) architecture was introduced, similar to Chrome or VS Code extensions. The core system loads plugins that extend the template:
// Core (plugin base)
export default function CoreApp() {
const [tabList, setTabList] = useState([]);
const pluginApi = useMemo(() => ({ tabs: { add: setTabList } }), []);
const plugin = registerPlugin(MPathToPluginInfo[location.pathname]);
plugin(pluginApi);
return <Tab>{tabList.map(tab => <Tab.Item key={tab.key} title={tab.title}>{tab.content}</Tab.Item>)}
</Tab>;
} // Plugin module
export default function plugin(api) {
api.tabs.add(() => ({ key: 'demo', title: 'Title', content: <Content /> }));
}This design achieves the original goals:
Improves development efficiency (over 50% time reduction) by reusing components and templates.
Ensures consistent product shape and design standards across tools.
Allows product managers to configure certain UI blocks without code changes.
However, it also introduces challenges such as higher architectural complexity, performance considerations, and larger impact scopes when making changes.
Future work includes reducing the side‑effects of the architecture, exploring template abstraction for form scenarios, and further boosting efficiency for legacy page demands.
DaTaobao Tech
Official account of DaTaobao Technology
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.