TypeScript 개발환경설정 1탄 (Webpack + Babel + ESLint + Prettier) - 웹팩 기본 설정하기

허상범·2022년 9월 13일
2
post-thumbnail

타입스크립트 보일러플레이트 바로가기
https://github.com/sangbeomheo/typescript-boilerplate


1탄: 웹팩의 기본적인 로더와 플러그인을 적용해 개발/배포 환경에 맞게 빌드해보기 (webpack5, loader, plugin, asset modules)


보일러플레이트를 만들게 된 이유

팀 단위 또는 개인 단위의 프로젝트들을 경험하다 보니 '보일러 플레이트'를 만들어야겠다고 결심했습니다.

지금까지 리액트 프로젝트는 CRA를 사용하거나 여러 블로그를 복붙해서 환경설정을 하는 경우가 대부분이었습니다. 그러다 보니 프로젝트가 점점 커질수록 확실하게 알지 못하는 환경설정들이 프로젝트의 확장과 변경에 어려움을 줬습니다. 더 이상 블로그에서 복사해 붙이는 거로 해결되지 않는 문제들도 생겼습니다.

그래서 이번엔 환경설정을 처음부터 직접 해보면서 모르는 부분을 학습하고 제가 직접 어느정도 통제할 수 있는 환경을 만들어보려 했습니다.



1. 웹팩의 역할

webpack은 모던 JavaScript 애플리케이션을 위한 정적 모듈 번들러 입니다. webpack이 애플리케이션을 처리할 때, 내부적으로는 프로젝트에 필요한 모든 모듈을 매핑하고 하나 이상의 번들을 생성하는 디펜던시 그래프를 만듭니다.

https://webpack.kr/concepts/

  • 웹팩은 애플리케이션에 필요한 모든 파일(모듈)을 병합하고 압축해서 하나의 결과물(번들)을 생성해주는 도구이다.
  • JavaScript 파일뿐만 아니라 스타일시트, 폰트, 이미지 등의 파일도 모듈로 작성할 수 있는 것이 큰 장점이다. 또 번들링을 하면서 파일들을 병합하고 압축해 파일 수와 크기가 줄어들어 로딩시간을 줄일 수 있다.


2. 타입스크립트, 웹팩 설치

  • 타입스크립트 기본 설정파일을 생성(자동생성) ./tsconfig.json
npm i -D typescript@4.8.3 // 타입스크립트
tsc --init // 타입스크립트 설정 초기화
// ***** ./tsconfig.json *****
{
  "compilerOptions": {
    "target": "es2016",
    "module": "commonjs",
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true
  }
}

  • webpack, webpack-cli 설치
  • 웹팩 설정 파일 생성 ./webpack.config.js
npm i -D webpack@5.74.0 // 웹팩
npm i -D webpack-cli@4.11.0 // 웹팩 터미널 도구
// ***** ./webpack.config.js *****
module.exports = {}

"-D" 를 붙이는 이유
D는 해당 패키지를 devDependencies에 설치한다는 의미이다.
devDependencies로컬 개발 및 테스트 단계까지만 필요한 패키지,
dependencies프로덕션 환경에서까지 필요한 패키지이다.

typescript, webpack 등은 로컬에서 개발할 때 필요한 패키지이다. 실제 배포할 때는 webpack을 이용해 번들링된 파일이 배포되기 떄문에 이 패키지들은 배포할 때 필요가 없다.(ts파일이 아닌 번들링된 js파일이 배포)
react, axios 같이 실제 배포한 이후에도 사용되는 것들은 dependencies에 설치한다.



3. Mode (모드)

development, production 또는 none으로 설정하면 webpack에 내장된 환경별 최적화를 활성화 할 수 있습니다. 기본값은 production 입니다.

https://webpack.kr/concepts/#mode

  • 특정 모드로 웹팩을 실행시켜 해당 환경에 맞게 빌드할 수 있다.
  • production : 배포모드(기본값)
  • development : 개발모드

  • 환경변수에 모드 값을 넣는다.
  • mode의 기본 값을 development로 설정
// ***** ./webpack.config.js *****

const mode = process.env.NODE_ENV || 'development';

module.exports = {
  mode, 
}

  • packege.json 에 각 모드별로 빌드하는 스크립트를 작성
  • --progress : 실행할 때 빌드 진행율을 보여준다.
...
"scripts": {
  "build:dev": "NODE_ENV=development webpack --progress", // 개발모드
  "build:prod": "NODE_ENV=production webpack --progress" // 배포모드
},
...


4. Entry, Output (엔트리, 아웃풋)

4.1 Entry, Output (엔트리, 아웃풋)

  • entry : 어플리케이션 진입점이다. entry에서 시작해 의존하는 모듈을 합쳐서 하나의 파일로 번들링한다.
  • output : 번들링 결과물을 생성할 경로
    • clean : 번들링하기 전에 빌드 이전 결과물이 있으면 제거하는 옵션. (Webpack4의 clean-webpack-plugin을 대체
    • assetModuleFilename : asset 파일들을 생성할 때 경로와 파일이름 설정 (Asset Modules와 같이 사용, Webpack4에서 url-loader, file-loader, raw-loader를 대체)
// ***** ./webpack.config.js *****

const path = require("path")
const mode = process.env.NODE_ENV || 'development';

module.exports = {
  mode, 
  entry: {
    main: './src/app.ts', // 엔트리 경로
  },
  output: {
    filename: '[name].js', // name으로 entry의 키 값을 받음
    path: path.resolve('./dist'), // 빌드 결과물을 생성할 경로(절대경로)
    assetModuleFilename: 'assets/[name][ext]', // asset 파일을 기존 이름으로 "assets" 폴더에 생성
    clean: true, // 빌드 이전 결과물 제거
  },
}

4.2 잘 동작하는지 확인해보자!

  • app.ts를 엔트리로. import한 app2.ts가 합쳐져 하나의 번들된 파일이 생성되야 함


빌드 결과

  • dist/main.js 번들된 파일 생성
  • app.ts, app2.ts 파일 합쳐짐



5. Loaders

5.1 Loader의 역할

  • 파일을 하나하나 해석하고 변환하는 역할
  • 웹팩은 모든 파일을 모듈로 취급
  • 엔트리부터 시작해서 파일 하나하나를 확인하고 그 과정에서 로더를 이용해 파일을 변환

5.2 css-loader

css 파일을 모듈로 변환

The css-loader interprets @import and url() like import/require() and will resolve them.

https://webpack.js.org/loaders/css-loader/


5.3 sass-loader

sass/scss 파일을 css로 변환

Loads a Sass/SCSS file and compiles it to CSS.

https://webpack.js.org/loaders/sass-loader/


5.4 style-loader

자바스크립트로 변경된 스타일을 동적으로 돔에 추가

Inject CSS into the DOM.
It's recommended to combine style-loader with the css-loader

https://webpack.kr/loaders/style-loader/


5.5 style-loader, css-loader, sass, sass-loader 설치

npm i -D style-loader@3.3.1 css-loader@6.7.1 sass@1.54.9 sass-loader@13.0.2

./webpack.config.js

// ***** ./webpack.config.js *****

module.exports = {
  ...
  module: {
    rules: [
      {
        test: /\.(scss|css)$/, // 확장자가 scss, css인 모든 파일
        use: [
          'style-loader',
          'css-loader',
          'sass-loader',
        ], // 배열의 역순으로 로더가 동작. scss파일을 css파일로 컴파일 -> css-loader를 적용해 모듈화 -> 동적으로 돔에 추가
      },
    ],
  },
  ...
}

5.6 잘 동작하는지 확인해보자!

  • main.scss에서 sub.scss를 import하고 있고 둘 다 div태그의 스타일을 정의
  • 엔트리 파일인 app.ts에서 main.scss를 import

빌드 결과

  • 번들링된 main.js에서 main.scss, sub.scss 에서 작성한 내용을 확인할 수 있다.



6. Asset Modules

6.1 Asset Modules

Asset Modules is a type of module that allows one to use asset files (fonts, icons, etc) without configuring additional loaders.

https://webpack.js.org/guides/asset-modules/

  • loader를 사용하지 않아도 폰트, 아이콘 등의 에셋 파일들을 사용할 수 있게 해주는 모듈
  • webpack5 이전에는 raw-loader, url-loader, file-loader 를 사용
  • type: 'asset/resource' : 파일을 출력 (file-loader 대체)
  • type: 'asset/inline' : data URI로 번들에 삽입 (url-loader 대체)
module.exports = {
  ...
    module: {
    rules: [
      ...
      {
        test: /\.(png|jpg|svg|gif)$/,
        type: 'asset', // resource와 inline 중에서 자동으로 선택
        parser: {
          dataUrlCondition: {
            maxSize: 4 * 1024, // 크기가 4kb 미만인 파일은 inline 모듈로 처리되고 그렇지 않으면 resource 모듈로 처리
          },
        },
      },
      ...
    ]
  }
  ...
}

6.2 잘 동작하는지 확인해보자!

  • 각각 6KB, 680B 크기의 이미지 파일이 있다.
  • assetModule이 제대로 동작한다면
    • 4KB보다 작은 icon_user.svginline date-url
    • 4KB보다 큰 icon.pngpng파일로 변환될 것이다.

빌드 결과

  • dist/assets/icon.png 파일 생성
  • icon_user.svg는 파일이 생성되지 않고 inline으로 들어감



7. Plugins

7.1 Plugin의 역할

  • 번들링된 결과물를 변환하는 역할
  • 예) 주석제거, 파일상단에 빌드 정보 입력, 난독화, 줄바꿈 제거 등

7.2 BannerPlugin

생성된 청크의 상단에 배너 추가

Adds a banner to the top of each generated chunk.

https://webpack.js.org/plugins/banner-plugin

  • webpack 내장 플러그인
  • 빌드 정보나 작성자 등을 삽입
  • 생성자 함수로 불러옴
  • 옵션 객체의 banner 속성에 문자열을 전달
  • 빌드 시간이나 커밋정보를 전달하기위해 함수로 전달 가능

// ***** ./webpack.config.js *****
const webpack = require('webpack');
const childProcess = require("child_process")

module.exports = {
  ...
  module: {},
  plugins: [
    new webpack.BannerPlugin({ // 플러그인 생성자 함수
      banner: `
        Build Date :: ${new Date().toLocaleString()} // 빌드시간
        Author :: ${childProcess.execSync('git config user.name')}`, // 작성자
    }),
  ],
  ...
}

7.3 잘 동작하는지 확인해보자!

빌드 결과

  • 위의 코드와 같이 작성한 후 빌드를 하게되면 아래와 같이 번들파일 상단에 내용이 삽입된다.


7.4 HtmlWebpackPlugin

번들을 제공하기 위한 HTML 파일을 쉽게 생성

The HtmlWebpackPlugin simplifies creation of HTML files to serve your webpack bundles.

https://webpack.js.org/plugins/html-webpack-plugin

  • 써드 파티 패키지
  • HTML 코드를 동적으로 생성
  • 빌드 시 값을 넣거나 코드를 압축할 수 있음
  • ejs 문법으로 env 변수값을 출력할 수 있음
  • HTML 코드를 압축하고 불필요한 주석을 제거할 수 있음(배포모드 시 사용)

  • template : html 코드를 만들 템플릿 파일의 경로
  • templateParmeters : 빌드 시 템플릿에 넣을 변수 설정 변수명: 값
  • hash : 정적 파일을 불러올 때 쿼리문자열에 해쉬값을 추가. 캐쉬문제보호
  • minify : html 코드 압축 설정
    • collapseWhitespace : 줄바꿈 없애기
    • removeComments : 주석 제거

npm i -D html-webpack-plugin@5.5.0 // 플러그인 설치
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports {
  ...
  module: {},
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html', // 템플릿 경로를 지정
      templateParameters: { // 템플릿에 주입할 파라매터 변수 지정
        env: process.env.NODE_ENV === 'development' ? '(개발용)' : '', // env변수 설정
      },
      hash: true, // 해쉬값을 추가
      minify:
        process.env.NODE_ENV === 'production' // 배포모드만
          ? {
              collapseWhitespace: true, // 줄바꿈 없애기
              removeComments: true, // 주석 제거
            }
          : false, // 개발모드일 때는 x
      },
    })
  ]
  ...
}

7.5 잘 동작하는지 확인해보자!

  • html 템플릿 파일

빌드 결과

  • 개발모드 : 타이블에 '(개발용)' 문자열 삽입, hash값 추가


  • 배포모드 : 줄바꿈 없애기, 주석 제거, hash값 추가

7.6 MiniCssExtractPlugin

CSS파일을 필요로하는 JS파일만 CSS파일을 생성

This plugin extracts CSS into separate files. It creates a CSS file per JS file which contains CSS. It supports On-Demand-Loading of CSS and SourceMaps.

https://webpack.kr/plugins/mini-css-extract-plugin

  • 써드 파티 패키지
  • 스타일시트의 크기가 커지면 자바스크립트 파일 하나로 번들링하는 것에 부담이 된다.
  • 그래서 css 코드만 분리해 별도의 css파일로 분리하는 것이 성능에 좋다.
  • 개발환경에서는 크게 상관없다.배포환경에서 사용.

npm i -D mini-css-extract-plugin@2.6.1 // 플러그인 설치
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports {
  ...
  module: {
  	rules: [
      {
        test: /\.(scss|css)$/,
        use: [
          process.env.NODE_ENV === 'production'
            ? MiniCssExtractPlugin.loader
            : 'style-loader',
          'css-loader',
          'sass-loader',
          // 배포모드에서는 스타일시트를 자바스크립트로 모듈화하지 않고 css파일로 변환해야하기 때문에 다른 로더 사용
        ],
      },
    ],
  },
  plugins: [
    ...(process.env.NODE_ENV === 'production' // 배포모드만
      ? [new MiniCssExtractPlugin({ filename: `[name].css` })] // output 경로에 CSS파일 생성
      : []),
  ]
  ...
}

7.6 잘 동작하는지 확인해보자!

  • main.scss파일에 body {background: red;} 스타일을 작성하고 개발, 배포 모드로 빌드해보았다.

빌드 결과

  • 개발모드

  • 배포모드 : css파일을 따로 만듬


8. 최종 파일 ./webpack.config.js

const path = require('path');
const webpack = require('webpack');
const childProcess = require('child_process');

const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

const mode = process.env.NODE_ENV || 'development';

module.exports = {
  mode,
  entry: {
    main: './src/app.ts',
  },
  output: {
    filename: '[name].js',
    path: path.resolve('./dist'),
    assetModuleFilename: 'assets/[name][ext]',
    clean: true,
  },
  module: {
    rules: [
      {
        test: /\.(scss|css)$/,
        use: [
          process.env.NODE_ENV === 'production'
            ? MiniCssExtractPlugin.loader
            : 'style-loader',
          'css-loader',
          'sass-loader',
        ],
      },
      {
        test: /\.(png|jpg|svg|gif)$/,
        type: 'asset',
        parser: {
          dataUrlCondition: {
            maxSize: 4 * 1024,
          },
        },
      },
    ],
  },
  plugins: [
    new webpack.BannerPlugin({
      banner: `
        Build Date :: ${new Date().toLocaleString()}
        Author :: ${childProcess.execSync('git config user.name')}`,
    }),
    new HtmlWebpackPlugin({
      template: './src/index.html',
      templateParameters: {
        env: process.env.NODE_ENV === 'development' ? '(개발용)' : '',
      },
      hash: true,
      minify:
        process.env.NODE_ENV === 'production'
          ? {
              collapseWhitespace: true,
              removeComments: true,
            }
          : false,
    }),
    ...(process.env.NODE_ENV === 'production'
      ? [new MiniCssExtractPlugin({ filename: `[name].css` })]
      : []),
  ],
};


참고자료

https://webpack.js.org/concepts/
https://jeonghwan-kim.github.io/series/2019/12/10/frontend-dev-env-webpack-basic.html

0개의 댓글