// 5개의 애플리케이션을 생성하고, SASS, webpack을 선택하여 생성한다.
nx g @nrwl/react:app micro-apps/dashboard
nx g @nrwl/react:app micro-apps/asset
nx g @nrwl/react:app micro-apps/management
nx g @nrwl/react:app micro-apps/system
nx g @nrwl/react:app micro-apps/user
패키지를 생성한다.
// SASS, jest, rollup 을 선택한다.
nx g @nrwl/react:lib web/login/default --publishable --importPath=@gv/web-login-default
새로운 패키지와 애플리케이션이 생성된 폴더에 모든 soucre files 을 copy & paste 한다.
버전업 이후 수정사항
React v17 -> v18 업데이트후 변경점. main.tsx 에서 root 생성 방법이 변경되었다.
// React v17
import * as ReactDOM from 'react-dom';
...
ReactDOM.render(
<Suspense fallback={<GVSpinner isFull />}>
<GVMicroApp />
</Suspense>,
document.getElementById('root')
);
// React v18
import * as ReactDOM from 'react-dom/client';
...
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
root.render(
<Suspense fallback={<GVSpinner isFull />}>
<GVMicroApp />
</Suspense>
);
AntD v4 -> v5 로 변경되면서 v5에서 cssinjs 방식을 사용하면서 *.less 방식이 사라졌다. 기본적인 reset.css만을 설정한다.
// styles.scss 에 reset.css 포함
// AntD reset
@import "~antd/dist/reset.css";
// project.json에 styles.scss 포함
"options": {
"compiler": "babel",
...
"styles": ["apps/micro-apps/dashboard/src/styles.scss"],
...
"webpackConfig": "apps/micro-apps/dashboard/webpack.config.js"
},
Webpack의 min-css-extract-plugin을 사용하면서 build warning 나오는 import ordering 메세지 제거하기
// webpack.config.js
module.exports = composePlugins(withNx(), withReact(), (config) => {
// Update the webpack config as needed here.
// e.g. `config.plugins.push(new MyPlugin())`
// .tsx 에서 import 구문 ordering 경고 문구 발생 해결하기
// https://github.com/facebook/create-react-app/issues/5372
const instanceOfMiniCssExtractPlugin = config.plugins.find(
(plugin) => plugin.constructor.name === 'MiniCssExtractPlugin'
);
if (instanceOfMiniCssExtractPlugin) {
instanceOfMiniCssExtractPlugin.options.ignoreOrder = true;
}
return config;
});
Nx를 업데이트하면 기존의 workspace.json 파일을 사용하지 않는다. 그리고 webpack v5.* 버전을 사용한다. webpack v5는 Module Federation을 지원하므로 이에 대한 설정을 진행해 본다.
domain: 업무 api 호출(react-query or graphql query) 및 결과 data model, custom Hook 기반
page에서 view와 domain을 조합한다.
SSR에서 Next.JS 기반으로 진행시 feature의 domain을 통해 데이터를 다룬다.
NextJS 개념
최신것이 항상 좋은 것이 아니다. SPA 프레임워크의 CSR(Client Side Rendering)만으로 개발하다가 예전의 JSP, ASP같은 SSR(Server Side Rendering)의 이점이 있었다. NextJS는 CSR, SSR 뿐만아니라 SSG(Static Site Generation)도 지원을 한다.
CSR
SSR
SSG
SSG를 위한 getStaticProps, getStaticPaths
getStaticProps와 getStaticPaths는 async이다.
getStaticProps, getStaticPaths에서 데이터를 가져오는 domain에 위치한 api를 호출한다.
NX + Angular 기반 개발시 엔터프라이즈 애플리케이션 개발방법에 대한 글을 정리한다. Micro Frontend 개발방법이라기 보다는 애플리케이션을 개발하며 지속적으로 확장할 필요가 있을 때 관심사들을 어떻게 분리하여(Bounded Context) 개발할 수 있을지 보여준다.
Angular v6부터 Web Components에 대한 지원으로 @angular/elements 기능이 추가되어 Custom HTML Tag을 만들 수 있도록 지원한다. 본 글은 해당 사이트의 글을 Nx.dev 환경과 통합하여 개발하는 과정을 설명한다. Nx 환경은 mono repository 기반으로 multi application을 개발 할 수 있는 환경을 제공한다. Angular/CLI기반이지만 Angular, React, Node.js 개발까지 하나의 Git Repository안에서 개발하고 번들링 할 수 있도록 지원한다. 따라서 micro frontend에서 multi application 개발 잇점을 갖는다.
// NodeJS
$ nvm install 12.16.2
$ nvm alias default 12.16.2
$ nvm use 12.16.2
// Angular/CLI 최신버전 사용
$ npm i -g @angular/cli@latest
$ npm i -g @nrwl/cli@latest
$ npm i -g yarn@latest
// local 설치
$ yarn add
NX workspace를 생성한다.
$ npx create-nx-workspace@latest
// 선택 및 입력
? Workspace name (e.g., org name) micro-demo
? What to create in the new workspace angular [a workspace with a single Angular application]
? Application name app-container
? Default stylesheet format SASS(.scss) [ http://sass-lang.com ]
Web Components 개발 환경 설정
@angular/elements 를 설치한다.
$ yarn add @angular/elements
UI Component로 ng-antd v9.1.* 를 사용한다. yarn 이 아니라 angular/cli의 'ng' 명령을 사용한다. Yes와 sidemenu 형태 선택한다.
$ ng add ng-zorro-antd
선택하기
? Enable icon dynamic loading [ Detail: https://ng.ant.design/components/icon/en ] Yes
? Set up custom theme file [ Detail: https://ng.ant.design/docs/customize-theme/en ] Yes
? Choose your locale code: en_US
? Choose template to create project: sidemenu
설정 수정후 실행을 하면 sidemenu가 있는 환경이 자동 셋업되어 아래와 같이 보인다. 자세한 설치방법은 사이트를 참조한다.
$ ng serve --open
Monitor Web Components 개발 및 번들링
monitor 애플리케이션을 신규 생성한다. 모니터 애플리케이션을 Web Components로 만들어 app-container 애플리케이션에서 동적으로 로딩해 본다.
$ ng g app monitor
선택
? Which stylesheet format would you like to use? SASS(.scss) [ http://sass-lang.com ]
? Would you like to configure routing for this application? No
apps/monitor/src/app/app.component.html과 app.component.ts 를 변경한다.
// app.component.html
{{title}} Application
// app.component.ts
import { Component, Input } from '@angular/core';
@Component({
selector: 'micro-demo-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
})
export class AppComponent {
@Input() title = 'monitor';
}
apps/monitor/src/app/app.module.ts에서 Web Comopennts를 등록한다.
import { BrowserModule } from '@angular/platform-browser';
import { NgModule, Injector } from '@angular/core';
import { createCustomElement } from '@angular/elements';
import { AppComponent } from './app.component';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
providers: [],
// 동적으로 생성하므로 entryComponents에 등록
entryComponents: [AppComponent],
// 정적 bootstrap을 사용하지 않음
// bootstrap: [AppComponent],
})
export class AppModule {
constructor(private injector: Injector) {}
ngDoBootstrap() {
// createCustomElement를 통해 Web Components 스펙에 맞는 객체로 반환
const monitorApp = createCustomElement(AppComponent, { injector: this.injector });
// browser window객체에 잇는 customElements를 통해 Web Components 등록
customElements.define('monitor-app', monitorApp);
// 사용방법: @Input() title이 있으므로 attribute 설정가능
// <monitor-app title="Monitor Application"></monitor-app>
}
}
monitor 애플리케이션을 번들링하면 여러개의 파일로 나오는데 번들링 파일을 최소화한다. ngDoBootstrap() 은 정적 bootstrap이 아닌 실행타임에 외부 컴포넌트를 동적으로 로딩할 때 애플케이션 root를 결정할 수 있게 한다. ngDoBootstrap에 대한 설명을 참조하자.
$ ng build monitor --prod --output-hashing=none
수행할 경우 main, polyfill, runtime등의 파일이 생성된다. 파일 최소화를 위해 ngx-build-plus 패키지를 이용한다.
ng add 명령으로 ngx-build-plus를 설치하고 애플리케이션은 monitor를 지정한다.
$ ng add ngx-build-plus --project=monitor
ng add 로 수행을 하면 angular.json 파일의 설정을 자동으로 적용해 준다. builder의 명령어를 자동 수정함.
테스트를 위해 welcome.component.html 에 <monitor-app>태그를 설정해 보자.
<monitor-app title="Hi Monitor"></monitor-app>
여기까지하고 수행을 하면 <monitor-app> 태그를 해석할 수 없다고 Angular가 에러를 뱃는다. <monitor-app> 은 Angular가 해석하는 것이 아니라 Browser에서 해석되는 Web Components이므로 무시하도록 welcome.module.ts에 CUSTOM_ELEMENTS_SCHEMA를 설정한다.
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { WelcomeRoutingModule } from './welcome-routing.module';
import { WelcomeComponent } from './welcome.component';
@NgModule({
imports: [WelcomeRoutingModule],
declarations: [WelcomeComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
exports: [WelcomeComponent]
})
export class WelcomeModule { }
<monitor-app>태그를 설정하지 않고 Javascript를 이용하여 로딩해 본다.
apps/app-container/src/app/monitor.service.ts 파일을 생성한다.
monitor-es5.js 파일 동적 로딩
<monitor-app> DOM 동적 추가
import { Injectable } from '@angular/core';
@Injectable({providedIn: 'root'})
export class MonitorLoaderService {
loaded = false;
constructor() { }
// script 동적 로딩
loadMonitorScript(): void {
if (this.loaded) {
return;
}
const script = document.createElement('script');
script.src = 'assets/monitor-es5.js';
document.body.appendChild(script);
this.loaded = true;
}
// <monitor-app> 태그 추가
addMonitorApp(): void {
const tile = document.createElement('monitor-app');
// @Input() 내용은 setAttribute로 추가 가능
tile.setAttribute('title', 'Dynamic Load Monitor');
const content = document.getElementById('content');
content.appendChild(tile);
}
}
위의 경우 monitor-es5.js 파일을 별도로 다운로드받아 동적 로딩을 수행한다.
공통 파일 빼고 번들링하기
만일 app-container과 monitor 에서 사용하는 공통 패키지의 버전이 같다면, app-container 애플리케이션과 monitor 애플리케이션이 공통으로 사용하는 파일중, monitor 애플리케이션을 번들링할 때 공통파일을 제거하는 방법에 대해 알아보자. 제거를 통해 monitor 애플리케이션의 번들링 사이즈를 줄일 수 있다. 이는 Network payload time을 줄여주는 결과를 갖는다.
ngx-build-plus를 이용해서 @angular/cli의 webpack externals 을 자동 생성한다. (참조)
$ ng g ngx-build-plus:externals --project monitor
수행을 하면 angular.json 파일에 별도 환경이 추가되고, apps/monitor/webpack.externals.js 파일이 생성된다. angular.json 내용중
"node_modules/@angular/elements/bundles/elements.umd.js", 내용은 제거한다. elements.umd.js를 공통파일로 빼서 사용하는데 오류가 있다.
angular.json의 monitor 애플리케이션으 "scripts" 설정 내역 => scripts.js 파일에 설정한 *.umd.js 파일을 합친다.
buildSingle.sh 내용을 수정한다. scripts.js 파일은 window.ng.core 또는 window.ng.common과 같은 global 객체가 담겨있는 파일이다. 따라서 scripts.js는 app-container 애플리케이션에서 최초 한번만 로딩하면 되고, 이후 monitor 애플리케이션과 같은 web components는 번들 파일은 자신의 내용만을 포함한다.