Files
2nd/10_Wiki/Topics/Frontend/Micro-frontends.md
T
koriweb d8a80f6272 chore(wiki): dangling 링크 canonical 정규화 (768파일/1200건)
이름만 다른(표기 변형) [[위키링크]]를 대상 문서의 canonical 제목으로 치환해
끊겼던 1,200개 링크를 연결. 제목/파일명 정규화 일치만 적용하고 별칭 매칭은
과병합 위험으로 제외(애매성 가드). 원본은 _link_reconcile_backup/ 에 백업.
도구: Datacollect/scripts/link_reconcile_apply.mjs

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 12:24:15 +09:00

7.8 KiB

id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
id title category status canonical_id aliases duplicate_of source_trust_level confidence_score verification_status tags raw_sources last_reinforced github_commit tech_stack
wiki-2026-0508-micro-frontends Micro frontends 10_Wiki/Topics verified self
MFE
Micro-frontend Architecture
none A 0.9 applied
frontend
architecture
modular
2026-05-10 pending
language framework
TypeScript Module Federation / Single-SPA

Micro frontends

매 한 줄

"매 microservices 매 frontend 적용 — 매 large UI 매 independent deployable team-owned vertical slices 매 분할". ThoughtWorks Tech Radar (2016) 매 이름 채택, 매 Webpack 5 Module Federation (2020) 매 mainstream 진입, 매 2026 매 large enterprise frontend (Spotify, IKEA, DAZN) 매 standard, 매 Vite Module Federation + Native Federation 매 modern stack.

매 핵심

매 핵심 가치 (vs monolith)

  • Independent deploy: 매 team 매 자기 slice 매 release pipeline.
  • Tech heterogeneity: 매 React + Vue + Svelte 매 공존 (단 cost ↑).
  • Team scalability: 매 vertical team ownership — 매 Conway's law 매 align.
  • Incremental migration: 매 legacy → modern 매 점진적 교체.

매 cost

  • Bundle duplication: 매 framework 매 여러 번 load.
  • Cross-MFE state: 매 shared store 매 design.
  • Routing coordination: 매 shell + child route 매 sync.
  • Versioning skew: 매 shared dep 매 version conflict.
  • DX overhead: 매 dev 매 multi-repo / multi-server.

매 composition strategies

  • Build-time: npm package — 매 monorepo + 매 publish (closest to monolith).
  • Server-side: SSI/ESI/Tailor — 매 edge composition (Podium, Mosaic).
  • Run-time iframe: 매 ultimate isolation — 매 worst UX.
  • Run-time Web Components: 매 framework-agnostic embed.
  • Run-time Module Federation (Webpack 5 / Vite): 매 sharing dep + dynamic import — 매 dominant 2026.
  • Run-time Single-SPA: 매 lifecycle orchestration framework.

매 응용

  1. Large e-commerce (header/cart/product/checkout 매 별도 team).
  2. Multi-tenant SaaS (workspace + apps marketplace).
  3. Legacy modernization (strangler fig pattern).
  4. White-label platforms (per-customer customization).

💻 패턴

Webpack Module Federation — host (shell)

// shell/webpack.config.js
const { ModuleFederationPlugin } = require('webpack').container

module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: 'shell',
      remotes: {
        cart: 'cart@https://cart.example.com/remoteEntry.js',
        product: 'product@https://product.example.com/remoteEntry.js',
      },
      shared: {
        react: { singleton: true, requiredVersion: '^18.0.0' },
        'react-dom': { singleton: true, requiredVersion: '^18.0.0' },
      },
    }),
  ],
}

Module Federation — remote (cart MFE)

// cart/webpack.config.js
new ModuleFederationPlugin({
  name: 'cart',
  filename: 'remoteEntry.js',
  exposes: {
    './CartWidget': './src/CartWidget',
    './useCart': './src/hooks/useCart',
  },
  shared: {
    react: { singleton: true },
    'react-dom': { singleton: true },
  },
})

Host consume (React lazy)

// shell/App.tsx
import React, { lazy, Suspense } from 'react'

const CartWidget = lazy(() => import('cart/CartWidget'))

export function App() {
  return (
    <div>
      <Header />
      <Suspense fallback={<div>Loading cart</div>}>
        <CartWidget />
      </Suspense>
    </div>
  )
}

Vite Module Federation

// cart/vite.config.ts
import federation from '@originjs/vite-plugin-federation'

export default {
  plugins: [
    federation({
      name: 'cart',
      filename: 'remoteEntry.js',
      exposes: { './CartWidget': './src/CartWidget.tsx' },
      shared: ['react', 'react-dom'],
    }),
  ],
  build: { target: 'esnext', minify: false, cssCodeSplit: true },
}

Single-SPA root config

// root-config/index.ts
import { registerApplication, start } from 'single-spa'

registerApplication({
  name: '@org/cart',
  app: () => System.import('@org/cart'),
  activeWhen: ['/cart'],
})

registerApplication({
  name: '@org/product',
  app: () => System.import('@org/product'),
  activeWhen: ['/products'],
})

start()

Single-SPA child lifecycle

// cart-app/src/main.ts
import { h, createApp } from 'vue'
import singleSpaVue from 'single-spa-vue'
import Root from './Root.vue'

const lifecycles = singleSpaVue({
  createApp,
  appOptions: { render: () => h(Root) },
})

export const bootstrap = lifecycles.bootstrap
export const mount = lifecycles.mount
export const unmount = lifecycles.unmount

Web Components 매 framework-agnostic embed

// cart-mfe.ts
class CartElement extends HTMLElement {
  connectedCallback() {
    const root = this.attachShadow({ mode: 'open' })
    // mount React/Vue/Svelte into shadow DOM
    mountReact(<CartWidget />, root)
  }
  disconnectedCallback() { unmountReact(this.shadowRoot!) }
}
customElements.define('app-cart', CartElement)
<!-- 매 host page (any framework) -->
<script src="https://cart.example.com/cart.js" type="module"></script>
<app-cart></app-cart>

Cross-MFE communication — Custom Events

// 매 publish
window.dispatchEvent(new CustomEvent('cart:item-added', {
  detail: { sku: 'A123', qty: 1 },
}))

// 매 subscribe
window.addEventListener('cart:item-added', (e) => {
  console.log('item added:', (e as CustomEvent).detail)
})

Shared shell store (BroadcastChannel)

const channel = new BroadcastChannel('app-state')

// MFE A
channel.postMessage({ type: 'auth/login', user })

// MFE B
channel.onmessage = ({ data }) => {
  if (data.type === 'auth/login') updateLocalState(data.user)
}

CSS isolation strategies

1. Shadow DOM (Web Components 매 자동 scope)
2. CSS Modules (build-time hash)
3. CSS-in-JS (runtime scope, e.g., styled-components)
4. PostCSS namespace plugin (legacy)
5. Tailwind prefix per MFE: `tw-cart-`, `tw-product-`

매 결정 기준

상황 Approach
Single team, single product Monolith (MFE overkill)
Multiple teams, shared shell Module Federation
Legacy → React migration iframe → Web Components → MF
Framework heterogeneity Web Components / Single-SPA
Maximum isolation (security) iframe (last resort)
Tight budget (LCP critical) Build-time composition
SSR + MFE Server-side composition (Tailor, Mosaic)
Vite stack Native Federation / vite-plugin-federation

기본값: 매 React/Vue 균일 stack 매 Module Federation, 매 framework 혼재 매 Single-SPA + Web Components.

🔗 Graph

🤖 LLM 활용

언제: 매 large team (50+ FE devs), 매 independent deploy 필요, 매 legacy modernization, 매 multi-tenant white-label. 언제 X: 매 small team (<10), 매 single-page simple SPA, 매 LCP-critical landing — 매 monolith 적합.

안티패턴

  • 매 component-level MFE: 매 button 매 MFE — 매 latency overhead — 매 vertical slice 매 단위.
  • Shared global state via window: 매 race condition + 매 hidden coupling.
  • Framework version skew: 매 React 17 + 18 매 host — 매 hooks 깨짐.
  • No design system: 매 visual inconsistency — 매 shared tokens/components 필수.
  • Synchronous load chain: 매 cascade waterfall — 매 lazy + 매 parallel 매 host.
  • MFE 매 small team 매 도입: 매 over-engineering — 매 monolith + 매 module boundary 매 충분.

🧪 검증 / 중복

  • Verified (ThoughtWorks Tech Radar, micro-frontends.org, Module Federation docs).
  • 신뢰도 A.

🕓 Changelog

날짜 변경
2026-05-08 Phase 1
2026-05-10 Manual cleanup — composition strategies + MF/Single-SPA/WC patterns + comm matrix