마이크로 프론트엔드 아키텍쳐를 리액트를 가지고 실제로 적용시켜 보며 개념을 정리해보자.
아래와 같은 구조로 애플리케이션들을 구현하고 마이크로 프론트엔드 아키텍쳐로 합쳐서 서비스를 해볼 것 이다. 이 내용에서 필요하게 되는 애플리케이션은 아래와 같다.
마이크로 프론트엔드를 구현하는데 있어서 build-time, 그리고 run-time 총 두 가지 방법으로 접근을 할 수 있다.
build-time integration은 컨테이너가 브라우저에서 로드되기전에 상품리스트 소스코드 접근하는 것을 의미한다.
컨테이너가 로드 된 이후에, 상품리스트에 대한 소스코드를 접근한다.
Run-Time Integration을 활용해서 마이크로프론트엔드 아키텍쳐를 구현해볼 것이다.
우선 기본적인 구조를 알아보기 위해 프레임워크를 안쓰고 구현해보자. 일단 워크스페이스 파일을 하나 만들어주도록 하자. 그리고 그 안에 products라는 폴더를 만들어주고 아래 명령어들을 차례대로 입력해보자.
// package.json 파일 생성
npm init -y
// 웹팩 설정 및 필요한 모듈 설치
npm install webpack@5.68.0 webpack-cli@4.10.0 webpack-dev-server@4.7.4 faker@5.1.0 html-webpack-plugin@5.5.0
아래의 경로처럼 폴더와 파일을 만들어주고 더미 데이터를 만들어주는 코드를 작성해보자.
import faker from "faker";
let products = "";
for (let i = 0; i < 3; i++) {
const name = faker.commerce.productName();
products += `<div>${name}</div>`;
}
document.querySelector("#dev-products").innerHTML = products;
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
mode: "development",
// 개발 서버 설정
devServer: {
port: 8081,
},
// html에 버들링 된 스크립트를 자동으로 넣어주는 플러그인
plugins: [
new HtmlWebpackPlugin({
template: "./public/index.html",
}),
],
};
"scripts": {
"start": "webpack serve"
},
이 파일은 사실상 개발환경에서 테스트하기 위해 필요한 것이고 최종적으로는 container 프로젝트의 index.html만 있으면 된다.
<!DOCTYPE html>
<html>
<head> </head>
<body>
<div id="dev-products"></div>
</body>
</html>
이제 npm run start를 해주고 http://localhost:8081/ 에 접속해서 아래와 같은 화면이 나오면 성공적으로 products 프로젝트를 만든 것이다.
이번엔 컨테이너 프로젝트를 생성해보자 위에랑 동일한 세팅을 하면서 이번엔 facker 모듈을 빼고 아래처럼 노드몬이라는 모듈을 추가로 설치해주도록 하자. 그리고 PORT를 8080으로 설정해준다.
npm install webpack@5.68.0 webpack-cli@4.10.0 webpack-dev-server@4.7.4 html-webpack-plugin@5.5.0 nodemon
<!DOCTYPE html>
<html>
<head></head>
<body>
<div id="dev-products"></div>
</body>
</html>
이제 웹팩에 내장되어 있는 모듈페더레이션 플러그인 가지고 마이크로 프론트엔드를 구현해보자. 애플리케이션의 Host(Container)에서 Remote(Products)를 불러와서 사용할 수 있게 세팅해야 한다. 그러기 위해선 아래의 절차가 필요하다.
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
module.exports = {
mode: "development",
devServer: {
port: 8081,
},
plugins: [
new ModuleFederationPlugin({
name: "products",
filename: "remoteEntry.js",
exposes: {
"./ProductsIndex": "./src/index",
},
}),
new HtmlWebpackPlugin({
template: "./public/index.html",
}),
],
};
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
module.exports = {
mode: "development",
devServer: {
port: 8080,
},
plugins: [
new ModuleFederationPlugin({
name: "container",
remotes: {
products: "products@http://localhost:8081/remoteEntry.js",
},
}),
new HtmlWebpackPlugin({
template: "./public/index.html",
}),
],
};
import 구문을 사용해서 boostrap을 먼저 불러들이는 행위는 웹팩한테 product를 bootstrap.js가 실행되기전에 준비할 수 있게 해주는 아주 중요한 요소이다.
import("./bootstrap");
import "products/ProductsIndex";
console.log("Container!");
모듈 페더레이션의 원리를 이해하기 위해 잠시 네트워크 텝을 열어 8080포트일때 로드되는 파일들이 무엇들인지 확인해보자.
보다시피 8081포트인 products 프로젝트에서 쓰이는 faker모듈과 index.js 파일이 로드 된 것을 볼 수 있다. 모듈페더레이션을 사용해 번들을 빌드하게 되면 웹팩은 총 두가지의 작업을 수행한다.
이제 장바구니 프로젝트를 한번 만들어보도록 하자. 세팅은 products 별 다를게 없다.
이 파일은 사실상 개발환경에서 테스트하기 위해 필요한 것이고 최종적으로는 container 프로젝트의 index.html만 있으면 된다.
<!DOCTYPE html>
<html>
<head></head>
<body>
<div id="cart-dev"></div>
</body>
</html>
import faker from "faker";
const cartText = `<div>You have ${faker.random.number()}</div>`;
document.querySelector("#cart-dev").innerHTML = cartText;
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
module.exports = {
mode: "development",
devServer: {
port: 8082,
},
plugins: [
new ModuleFederationPlugin({
name: "cart",
filename: "remoteEntry.js",
exposes: {
"./CartShow": "./src/index",
},
}),
new HtmlWebpackPlugin({
template: "./public/index.html",
}),
],
};
이제 다시 Container로 돌아가서 cart를 import 해주는 작업을 해주자.
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
module.exports = {
mode: "development",
devServer: {
port: 8080,
},
plugins: [
new ModuleFederationPlugin({
name: "container",
remotes: {
products: "products@http://localhost:8081/remoteEntry.js",
cart: "cart@http://localhost:8082/remoteEntry.js",
},
}),
new HtmlWebpackPlugin({
template: "./public/index.html",
}),
],
};
<!DOCTYPE html>
<html>
<head></head>
<body>
<div id="dev-products"></div>
<div id="cart-dev"></div>
</body>
</html>
이렇게하면 다음과 같이 container에서 products와 cart 프로젝트를 한 화면에 불러오는걸 확인 할 수 있다.