프론트기술/Angular

Angular Material 과 TailwindCSS 의 만남

RevFactory 2021. 7. 17. 16:52

 

Angular 팀에서 직접 만들고 있는 Angular Material 은 심플하고, 다양한 컴포넌트를 제공하고 있지만 막상 사용하려고 하면 결과물이 기대에 미치지 못해서 잘 사용하지 못하고 있었다.  Material Design이 구글 서비스에서 전반적으로 사용되고 있어서 익숙해서일수도 있지만 전체적인 모양새가 생각보다 예쁘게 안나온다.

 

따라서 뭔가 보완적인게 필요했는데 Tailwindcss 가 그 역할을 해줄 것으로 기대가 된다. tailwindcss에서 제공하는 클래스들을 조합하여 사용하게 되므로, 매번 css 클래스명을 고민하지 않아도 되고, 일관된 디자인 스타일로 구현하기가 쉬워졌다. 다만 제공하는 클래스들이 raw 수준으로 제공되므로, 초반에는 익숙해지는데까지 시간이 다소 걸리며, 다소 과도한 클래스명 나열이 필요한 상황이 많아 이러한 점은 단점으로 꼽히고 있다.

 

Fuse Angular Template

Angular 프레임워크 기반이면서 꽤나 괜찮은 퀄리티를 보여주고 있는 Fuse Angular Template 역시 Angular Material 컴포넌트와 TailwindCSS 조합으로 구성이 되어 있는 것을 확인할 수 있다.

 

TailwindCSS 사이트를 방문해보면 기본적으로 HTML, React, Vue 기반의 템플릿을 제공해주고 있다. Angular 기반의 템플릿은 현재 공식적으로 제공하고 있지 않다. 이에 Angular 에서도 최근 v11.2.x 부터 적극적으로 TailwindCSS에 대한 지원을 추가하기 시작했다 (지난 포스팅 참조). 비록 TailwindCSS 의 Angular용 공식적인 템플릿 제공을 받을 수는 없지만, 간단한 설정만으로 Angular Framework 에서 TailwindCSS 사용이 가능하다.

 

 

다만 주의해야 할 점은 TailwindCSS 에서 제공하는 대다수의 완성된 UI 컴포넌트가 Tailwind UI라는 별도의 제품으로 유료로 제공된다는 점이다. 따라서 구매없이 사용하려면 결국 TailwindCSS 를 이용해서 직접 레이아웃을 구성하고, 컴포넌트를 제작해야 한다. Tailwind UI 에는 Figma 키트도 포함되어 있으며, 1회 구매로 계속 업데이트를 받을 수 있다고 한다. 팀 라이선스는 좀 더 높은 가격으로 제공하고 있다. Tailwind UI 로 만든 템플릿, 테마는 재판매할 수 없도록 라이선스를 규정하고 있다. Github에 Tailwind UI 컴포넌트를 포함한 소스코드를 공개해서도 안된다. 그밖에도 여러 제약이 있으니 Tailwind UI 를 사용하고자 한다면 잘 살펴보아야 할 것 같다. 개인적으로 Bootstrap 처럼 컴포넌트들은 제공하고, 완성된 사이트를 판매하는 형태로 갔었으면 하는 아쉬움이 남는다.

 

 

Angular Material + Tailwind CSS

자, 그럼 이제 Angular Material + Tailwind CSS 을 설정해보자.

 

 

1. Angular 프로젝트 생성

Angular CLI 가 설치되어 있지 않다면 먼저 아래 명령어를 이용하여 CLI를 설치한다.

$ npm install -g @angular/cli

 

Angular 프로젝트 생성

$ ng new material-with-tailwindcss --routing --style scss

 

* 현재 (angular 12.1.1 기준) 아래와 같은 의존성 에러가 난다면 jasmin의 version을 변경해준다.

⠼ Installing packages (npm)...npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR!
npm ERR! While resolving: material-with-tailwindcss@0.0.0
npm ERR! Found: jasmine-core@3.7.1
npm ERR! node_modules/jasmine-core
npm ERR!   dev jasmine-core@"~3.7.0" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer jasmine-core@">=3.8" from karma-jasmine-html-reporter@1.7.0
npm ERR! node_modules/karma-jasmine-html-reporter
npm ERR!   dev karma-jasmine-html-reporter@"^1.5.0" from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR!
npm ERR! See C:\Users\Robin\AppData\Local\npm-cache\eresolve-report.txt for a full report.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\Robin\AppData\Local\npm-cache\_logs\2021-07-17T02_48_53_675Z-debug.log
✖ Package install failed, see above.
The Schematic workflow failed. See above.

package.json

"devDependencies": {
	// ... 
	"jasmine-core": "~3.8.0",	// 3.7.0 -> 3.8.0 으로 변경
	"karma-jasmine-html-reporter": "^1.7.0",	// 1.5.0 -> 1.7.0 으로 변경
}

 

$ cd material-with-tailwindcss
$ npm install

 

 

2. Angular Material 추가

아래와 같이 Angular Meterial 을 추가한다.

$ ng add @angular/material

i Using package manager: npm
√ Found compatible package version: @angular/material@12.1.2.
√ Package information loaded.

The package @angular/material@12.1.2 will be installed and executed.
Would you like to proceed? Yes
√ Package successfully installed.
? Choose a prebuilt theme name, or "custom" for a custom theme: Purple/Green       [ Preview: https://material.angular.io?theme=purple-green ]
? Set up global Angular Material typography styles? Yes
? Set up browser animations for Angular Material? Yes
UPDATE package.json (1153 bytes)
√ Packages installed successfully.
UPDATE src/app/app.module.ts (502 bytes)
UPDATE angular.json (3487 bytes)
UPDATE src/index.html (591 bytes)
UPDATE src/styles.scss (181 bytes)

 

테마 색상을 선택하는 옵션이 나오는데 기본적으로 제공하는 테마 색상은 아래 스크린샷을 참고하여 선택한다.

좀 더 자세한 내용은 테마 문서를 참고한다.

Angular Material Typography 스타일과 Browser Animation 설정도 옵션으로 제공되는데, 일단 모두 Yes 를 선택했다.

 

Angular Meterial 을 설치하고 나면 아래 파일들이 업데이트 된다.

- package.json : Angular Material 의존성 추가됨

- app.module.ts :  Import에 BrowserAnimationModule 추가됨

- angular.json : 선택한 테마가 styles 에 추가됨

- index.html : Angular Typography 와 Icons 링크 추가 및 mat-typography 요소가 추가됨

- styles.scss : Angular Material 과 관련된 스타일이 추가됨

 

이제 사용하고자 하는 Angular Material 컴포넌트가 잘 나오는지 확인해보자

아래와 같이 버튼 모듈을 AppModule 에 추가하고, HTML 페이지에 추가해본다

//app.module.ts
import { MatButtonModule } from '@angular/material/button';
@NgModule({
  ...,
  imports: [
    ...,
    BrowserAnimationsModule,
    MatButtonModule
  ],
  ...
})
export class AppModule { }

app.component.html 파일에는 프로젝트 생성시 자동으로 추가된 코드가 제공되는데 전부 삭제하고 아래와 같이 추가한다.

<!-- app.component.html -->
<div style="padding: 10px; background-color: lightgrey;">
  <button mat-raised-button color="primary" style="margin: 0 5px;">Primary Button</button>
  <button mat-raised-button color="accent" style="margin: 0 5px;">Accent Button</button>
  <button mat-raised-button color="warn" style="margin: 0 5px;">Warn Button</button>
</div>

Angular 를 실행하고 http://localhost:4200 을 접속하여 확인한다.

$ ng serve

http://localhost:4200

3. TailwindCSS 추가

아래와 같은 npm 명령어로 tailwindcss 를 추가한다.

$ npm install tailwindcss -D

 package.json 에 tailwindcss 의존성이 추가된 것을 확인할 수 있다.

"devDependencies": {
	// ... 
	"tailwindcss": "^2.2.4"
}

 

npx 명령어로 tailwindcss 를 초기화하게 되면 tailwindcss 설정 파일이 추가된다.

* npx 는 npm 5.2.0 버전에 추가된 CLI 도구로 npm 을 좀 더 편하게 사용할 수 있게 해주는 도구이며, npm 이 패키지를 관리한다면, npx는 패키지를 실행하는 역할을 하고 있다.

$ npx tailwindcss init

추가된 tailwind.config.js 에서 tailwind 의 각종 옵션을 설정할 수 있다.

// tailwind.config.js
module.exports = {
  purge: [],
  darkMode: false, // or 'media' or 'class'
  theme: {
    extend: {},
  },
  variants: {
    extend: {},
  },
  plugins: [],
}

 

PostCSS 를 사용하기 위해 custom-webpack 과 postcss 를 추가한다. (복잡하다면 일단 이 부분은 스킵해도 된다.)

* PostCSS 는 JS플러그인을 사용하여 CSS 를 자동으로 변환하는 개발도구이다.

$ npm install @angular-builders/custom-webpack postcss-scss postcss-import postcss-loader -D

그리고 webpack.config.js 파일을 프로젝트 루트에 추가하고 아래와 같이 설정한다.

// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.scss$/,
        use: [
          {
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                plugins: [
                  'postcss-import',
                  'tailwindcss',
                  'autoprefixer',
                ]
              }
            }
          }
        ],
      }
    ]
  }
};

이제 custom-webpack 설정이 제대로 동작할 수 있도록 Angular 설정파일을 아래 명령어를 통해 수정한다.

// ng config projects.<your-project>.architect.build.builder @angular-builders/custom-webpack:browser
// ng config projects.<your-project>.architect.build.options.customWebpackConfig.path webpack.config.js
// ng config projects.<your-project>.architect.serve.builder @angular-builders/custom-webpack:dev-server

$ ng config projects.material-with-tailwindcss.architect.build.builder @angular-builders/custom-webpack:browser
$ ng config projects.material-with-tailwindcss.architect.build.options.customWebpackConfig.path webpack.config.js
$ ng config projects.material-with-tailwindcss.architect.serve.builder @angular-builders/custom-webpack:dev-server

 

(OPTION) TailwindCSS important 적용

Angular Material 테마를 설정하게 되면 style 이 재정의 되면서 tailwindCSS 클래스를 지정하더라도 제대로 적용이 안되는 이슈가 있다. 이 경우, tailwindCSS 설정 중 important 를 true 처리해서 style 이 제대로 적용되게 설정할 수 있다.

// tailwind.config.js
module.exports = {
  important: true,
  ...
}

 

TailwindCSS 스타일을 적용하기 위해서는 style 파일에 TailwindCSS를 import 해줘야 한다.

/* You can add global styles to this file, and also import other style files */

@import 'tailwindcss/base';
@import 'tailwindcss/components';
@import 'tailwindcss/utilities';

html, body { height: 100%; }
body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }

 

TailwindCSS 를 추가하게 되면, 빌드 사이즈가 크게 증가하게 된다.

Initial Chunk Files   | Names         |      Size
vendor.js             | vendor        |   2.97 MB
polyfills.js          | polyfills     | 508.85 kB
styles.css, styles.js | styles        | 461.99 kB
main.js               | main          |  10.83 kB
runtime.js            | runtime       |   6.60 kB

                      | Initial Total |   3.94 MB


// TailwindCSS Import시

Initial Chunk Files   | Names         |      Size
styles.css, styles.js | styles        |   4.89 MB	// 0.46MB -> 4.89MB
vendor.js             | vendor        |   2.97 MB
polyfills.js          | polyfills     | 508.85 kB
main.js               | main          |  10.83 kB
runtime.js            | runtime       |   6.60 kB

                      | Initial Total |   8.38 MB

 

따라서 미리 Style 클래스가 많이 선언되어 있는 TailwindCSS 를 사용할때는 사용하지 않는 클래스를 제거하고 사용하는 것이 좋다. 이 경우, dotenv 를 이용하여 사용하지 않는 클래스 제거가 가능하다. 

 

npm 명령어를 이용하여 dotenv 를 설치한다.

npm install dotenv -D

 

TailwindCSS 설정파일에서 dotenv를 이용한 purge 옵션을 추가한다.

// tailwind.config.js
require('dotenv').config();
const enablePurge = process.env.ENABLE_PURGE || false;
module.exports = {
  // REMOVE THIS FLAG IF YOU ARE NOT USING A PREBUILT ANGULAR THEME
  // LIKE THE ONE THIS PROJECT IS USING - INDIGO PINK
  important: true,
  purge: {
    enabled: enablePurge,
    content: [
      './src/**/*.html',
      './src/**/*.scss'
    ]
  },
  theme: {
    extend: {},
  },
  variants: {},
  plugins: [],
}

 

개발단계에서는 클래스 제거를 안해도 되므로, ENABLE_PURGE 값은 false 를 기본값으로 설정했다.

production 에서 배포시에는 .env 파일을 통해 ENABLE_PURGE=true 값으로 설정하자.

 

 

4. TailwindCSS 적용 확인 

기존에 CSS Style 을 적용했던 부분을 TailwindCSS 에 정의된 클래스로 대체하여 TailwindCSS 가 제대로 적용되었는지 최종적으로 확인한다.

 

TailwindCSS 의 자세한 스펙은 문서를 참고할 수 있다.

 

Angular Material 테마가 적용되어, TailwindCSS 를 important 옵션으로 강제 사용시에 페이지 refresh 할때 깜빡임 현상이 있어서 이 부분은 좀 더 살펴봐야 할 것 같다.