마이크로 프론트엔드 without Frontend Frameworks 2

Dan·2022년 11월 18일
0

웹팩

목록 보기
5/8
post-thumbnail

지난번에 이어서 마이크로 프론트엔드를 좀 더 파헤쳐 보자.

중첩 모듈 공유하기

저번에 구현 부분을 네트워크탭에서 확인해보면 cart와 products에서 동시에 faker 모듈을 분리해서 불러오고 있는것을 볼 수 있다. 하지만 faker은 중첩된 모듈이고 번들 사이즈도 매우 큰편이기에 효율적이지 않다. 이 중첩된 모듈을 하나로 공유할 수 있도록 만들어보자.

방법은 굉장히 단순하다 module federation에서 제공하는 shared 옵션을 사용하면 된다. 하지만 이 옵션을 사용하기전에 product와 cart를 비동기적으로 불러올 수 있게하는 작업을 해줘야한다.

  • cart/src/index.js
import("./bootstrap");
  • cart/src/bootstrap.js
import faker from "faker";

const cartText = `<div>You have ${faker.random.number()}</div>`;

document.querySelector("#cart-dev").innerHTML = cartText;

위와 같이 bootstrap.js를 생성해서 index.js에서 import() 구문을 사용해서 불러와주도록 하자. import를 ()처럼 함수형으로 불러오게 되면 페이지가 로드 되기전에 bootstrap 파일을 비동기적으로 먼저 준비할 수 있도록 할 수 있다. 위와 같은 세팅은 product에도 똑같이 적용시키자.
그 다음 prdouct와 cart에 아래와 같이 shared 옵션을 추가해주자.

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",
      },
      // faker 모듈을 다른곳에서 이미 로드했다면 중첩이 안되도록 도와주는 기능이다.
      shared: ["faker"],
    }),
    new HtmlWebpackPlugin({
      template: "./public/index.html",
    }),
  ],
};

이제 결과물을 네트워크 텝을 확인해보면 faker 모듈을 한번만 불러오는것을 확인할 수 있다.

의존성 변경

현재는 container에서 다른 프로젝트를 불러주기 위해선 product나 cart에서 지정해준 id값을 container index.html에도 똑같은 id값을 지정해줘야지만 렌더링 되는것을 볼 수 있다. 그러기 위해선 다른 프로젝트의 개발환경도 다 고려하고 있어야해서 자율도가 떨어진다. 이를 해결하기 위해 프로젝트 구성들을 좀 바꿔보도록하자.

Refactoring

현재 환경이 local에서 개발되고 있는지 container 환경에서 개발되고 있는지를 판단해서 그 환경에 맞는 index.html를 가져와서 원하는 view를 그려주도록 한다.

  • products/src/bootstrap.js
import faker from "faker";

const mount = (el) => {
  let products = "";

  for (let i = 0; i < 3; i++) {
    const name = faker.commerce.productName();
    products += `<div>${name}</div>`;
  }

  el.innerHTML = products;
};

// Context/Situation #1
// We are running this file in develpment in isolation
// We are using our local index.html file
// Which DEFNITELY has an element with an id of 'dev-product'
// We want to immediately render our app into that element

if (process.env.NODE_ENV === "development") {
  const el = document.querySelector("#dev-products");

  // Assuming our container doesnt have an element
  // with id 'dev-products'...
  if (el) {
    // We are probably runnning in isolation
    mount(el);
  }
}

// Context/Situation #2
// We are running this file in develpment or production
// through the CONTAINER app
// NO GUARANTEE that an element with an id of 'dev-products'
// WE DO NOT WANT try to immediately render the app
export { mount };
  • container/public/index.html
<!DOCTYPE html>
<html>
  <head></head>
  <body>
    <div id="my-products"></div>
    <div id="my-cart"></div>
  </body>
</html>
  • container/src/bootstrap.js
import { mount as productsMount } from "products/ProductsIndex";
import { mount as cartMount } from "cart/CartShow";

console.log("Container!");

productsMount(document.querySelector("#my-products"));
cartMount(document.querySelector("#my-cart"));

이렇게 구현함으로써 container에서 유동적으로 내가 원하는 위치에 원하는 id를 지정해서 다른 프로젝트를 보여줄 수 있게 되었다.

profile
만들고 싶은게 많은 개발자

0개의 댓글