qiankun 마이크로 프론트엔드 프레임워크 사용 경험과 실제 적용

qiankun이란 무엇인가?

qiankun은 single-spa 기반의 마이크로 프론트엔드 구현 라이브러리로, 앤트핀테크팀에 의해 개발되었습니다. 이 프레임워크는 생산 환경에서 사용 가능한 마이크로 프론트엔드 아키텍처 시스템을 더 간단하고 무통점으로 구축할 수 있도록 돕습니다.

최근 프로젝트에서 여러 독립적인 프론트엔드 애플리케이션을 통합하기 위해 qiankun을 사용할 기회가 있었으며, 오늘은 제 사용 경험과 실제 사례를 공유하고자 합니다.

왜 마이크로 프론트엔드를 선택하는가?

qiankun의 구체적인 사용법을 소개하기 전에, 우리가 마이크로 프론트엔드가 필요한 이유를 간단히 살펴보겠습니다:

  1. 기술 스택 무관성 - 각 서브 애플리케이션은 다른 기술 스택(React, Vue, Angular 등)을 사용할 수 있습니다
  2. 독립적인 개발 - 각 팀은 자신의 애플리케이션을 독립적으로 개발, 테스트, 배포할 수 있습니다
  3. 점진적 마이그레이션 - 기존 시스템을 한 번에 다시 작성하는 대신 단계적으로 마이그레이션할 수 있습니다
  4. 애플리케이션 자치성 - 각 마이크로 애플리케이션은 독립된 코드베이스를 가지며 자체 출시 프로세스를 가집니다

기본 사례: 메인 애플리케이션 설정

1. qiankun 설치

npm install qiankun
# 또는
yarn add qiankun

2. 메인 애플리케이션 진입 파일 설정

// main.js
import { registerMicroApps, start } from 'qiankun';

// 마이크로 애플리케이션 등록
registerMicroApps([
  {
    name: 'react-app', // 마이크로 애플리케이션 이름
    entry: '//localhost:7100', // 마이크로 애플리케이션 진입점
    container: '#subapp-container', // 마이크로 애플리케이션 마운트 노드
    activeRule: '/react', // 마이크로 애플리케이션 활성화 규칙
  },
  {
    name: 'vue-app',
    entry: '//localhost:7101',
    container: '#subapp-container',
    activeRule: '/vue',
  },
]);

// qiankun 시작
start({
  sandbox: {
    strictStyleIsolation: true, // 스타일 격리 활성화
  },
});

3. HTML 템플릿 설정


<html>
<head>
  <meta charset="utf-8">
  <title>메인 애플리케이션</title>
</head>
<body>
  <div id="root">
    <h1>메인 애플리케이션</h1>
    - [React 애플리케이션](/react)
- [Vue 애플리케이션](/vue)
    <div id="subapp-container"></div>
  </div>
</body>
</html>

마이크로 애플리케이션 설정

React 마이크로 애플리케이션 설정

// react-app/src/public-path.js
if (window.__POWERED_BY_QIANKUN__) {
  // 웹팩 publicPath 동적으로 설정하여 리소스 로딩 오류 방지
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}

// react-app/src/index.js
import './public-path';
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

function render(props) {
  const { container } = props;
  ReactDOM.render(
    <App />,
    container ? container.querySelector('#root') : document.querySelector('#root')
  );
}

// 독립 실행 시
if (!window.__POWERED_BY_QIANKUN__) {
  render({});
}

// 라이프사이클 함수는 Promise를 반환해야 함
export async function bootstrap() {
  console.log('[react16] react 앱 부트스트랩됨');
}

export async function mount(props) {
  console.log('[react16] 메인 프레임워크로부터 전달된 props', props);
  render(props);
}

export async function unmount(props) {
  const { container } = props;
  ReactDOM.unmountComponentAtNode(
    container ? container.querySelector('#root') : document.querySelector('#root')
  );
}

Vue 마이크로 애플리케이션 설정

// vue-app/src/public-path.js
if (window.__POWERED_BY_QIANKUN__) {
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}

// vue-app/src/main.js
import './public-path';
import Vue from 'vue';
import App from './App.vue';

let instance = null;

function render(props = {}) {
  const { container } = props;
  instance = new Vue({
    render: h => h(App),
  }).$mount(container ? container.querySelector('#app') : '#app');
}

// 독립 실행 시
if (!window.__POWERED_BY_QIANKUN__) {
  render();
}

export async function bootstrap() {
  console.log('[vue] vue 앱 부트스트랩됨');
}

export async function mount(props) {
  console.log('[vue] 메인 프레임워크로부터 전달된 props', props);
  render(props);
}

export async function unmount() {
  instance.$destroy();
  instance.$el.innerHTML = '';
  instance = null;
}

Webpack 설정 수정

// vue.config.js 또는 webpack.config.js
const packageName = require('./package.json').name;

module.exports = {
  devServer: {
    headers: {
      'Access-Control-Allow-Origin': '*', // 크로스 도메인 허용
    },
  },
  configureWebpack: {
    output: {
      library: `${packageName}-[name]`,
      libraryTarget: 'umd',
      jsonpFunction: `webpackJsonp_${packageName}`,
    },
  },
};

실제 사용에서의 경험과 교훈

1. 스타일 격리 문제

qiankun은 두 가지 스타일 격리 방식을 제공합니다:

start({
  sandbox: {
    strictStyleIsolation: true, // Shadow DOM을 사용한 엄격한 격리
    experimentalStyleIsolation: true, // 실험적 스타일 격리
  }
});

실제 사용에서, strictStyleIsolation은 격리 효과가 좋지만 일부 UI 라이브러리의 스타일에 영향을 줄 수 있습니다. 반면 experimentalStyleIsolation은 스타일에 접두사를 추가하여 구현되어 호환성이 더 좋습니다.

2. 애플리케이션 간 통신

qiankun은 간단한 통신 메커니즘을 제공합니다:

// 메인 애플리케이션 초기화
import { initGlobalState } from 'qiankun';

const actions = initGlobalState({
  user: { name: '장삼' },
});

// 상태 변화 감지
actions.onGlobalStateChange((state, prev) => {
  console.log('메인 애플리케이션: 상태 변화', state, prev);
});

// 마이크로 애플리케이션에서 상태 가져오기 및 설정
export function mount(props) {
  // 상태 변화 감지
  props.onGlobalStateChange((state, prev) => {
    console.log('마이크로 애플리케이션: 상태 변화', state, prev);
  });
  
  // 전역 상태 설정
  props.setGlobalState({ user: { name: '이사' } });
}

3. 라우팅 처리 기술

// 메인 애플리케이션 라우팅 설정 registerMicroApps([ { name: 'app1', entry: '//localhost:7100', container: '#subapp-container', activeRule: '/app1', props: { routerBase: '/app1', // 라우팅 기본 경로 전달 } }, ]);

// 마이크로 애플리케이션에서 사용 if (window.POWERED_BY_QIANKUN) { // 메인 애플리케이션에서 전달된 props에서 라우팅 기본 경로 가져오기 const { routerBase } = props; // 마이크로 애플리케이션 라우팅 설정에서 사용 }

겪었던 문제점과 해결 방안

1. 정적 리소스 경로 문제

마이크로 애플리케이션의 정적 리소스 경로는 특히 주의해야 하며, 해결책은 상대 경로 사용 또는 publicPath 동적 설정입니다.

2. 타사 스크립트 충돌

일부 타사 라이브러리는 전역 객체를 수정하여 충돌을 유발할 수 있습니다. 해결책은 마이크로 애플리케이션 언마운트 시 전역 상태를 정리하는 것입니다.

3. 개발 환경 디버깅

개발 시 window.__POWERED_BY_QIANKUN__ = true를 설정하여 마이크로 프론트엔드 환경을 시뮬레이션하여 디버깅할 수 있습니다.

요약

수개월간의 실제 사용 경험을 통해, qiankun은 상당히 성숙된 마이크로 프론트엔드 솔루션이라고 생각합니다. 이는 마이크로 프론트엔드 아키텍처에서 발생하는 많은 복잡한 문제를 해결하여 개발자가 비즈니스 로직에 더 집중할 수 있게 해줍니다.

장점:

  • 통합이 간단하고 학습 비용이 낮음
  • 기능이 완비되고 문서가 명확함
  • 활발한 커뮤니티로 문제 해결이 신속함

주의해야 할 점:

  • 스타일 격리는 실제 상황에 맞게 적절한 방식을 선택해야 함
  • 애플리케이션 간 통신은 과도한 결합을 피하기 위해 합리적으로 설계해야 함
  • 배포 및 운영이 상대적으로 복잡함

전반적으로, 만약 프로젝트에서 여러 프론트엔드 애플리케이션을 통합해야 하거나 프론트엔드 아키텍처의 현대화를 진행 중이라면, qiankun은 반드시 시도해볼 가치가 있습니다. 제 경험이 도움이 되기를 바랍니다!

태그: qiankun 마이크로 프론트엔드 single-spa React vue

7월 8일 22:59에 게시됨