client/web

[기록] Webpack 기본과 실습 - loader, plugin, ...

growww 2022. 3. 16. 21:17

inflearn - 프론트엔드 개발환경의 이해와 실습 (webpack, babel, eslint..) - 김정환 님

강의를 들으며 기록한 내용이다.

 

NodeJS

  • node js 를 배워야 하는 이유?
    • 브라우저에 맞게 개발 타입스크립트 같은 고사양 언어 빌드 자동화
    • 프로젝트 사용 라이브러리 다운 및 테스트 자동화
    • 개발환경 커스터마이징 제공
  • node js 버전관리
    • nodejs는 시맨틱 버전관리
    • 메이저.마이너.패치
    • ~ 틸트, ^캐럿 버전 표기

 

Webpack

  • 웹팩이란?
    • 웹팩은 모듈로 연결된 여러개의 파일을 합쳐주는 역할을 함
    • 그 결과 하나로 합쳐진 파일을 번들이라고 함
    • 웹팩이 번들을 만드는 번들러 역할을 함
    • 따라서 웹팩을 번들러라고도 함

 

실습준비

  • 기본 프로젝트 생성
    • mkdir basic_frontend
    • cd basic_frontend
    • npm init
      • 패키지명 수정 > sample 입력
  • 스크립트 작성
    • package.json 파일의 scripts 내용 확인
    • test 항목 수행을 위해 명령어 입력
    • npm test
  • 실행명령 추가하기
    • package.json 파일의 scripts에 추가 (예."build")
{
  "name": "sample",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "echo DO BUILD"
  },
  "author": "",
  "license": "ISC"
}
  •     npm run build 수행하여 확인

 

패키지 버전

  • 패키지 버전 의미
    • 버전 번호를 관리하기 위한 규칙이 필요하고 이 체계를 유의적 버전(sementic version)이라고 함
    • 주.부.수 (v16.12.0)
    • 부등호 규칙 이란 > 1.2.3 보다 더 높은 버전 (나머지 부등호도 사용가능)
    • 틸트(~)란 마이너 버전이 명시 되어 있으면 패치버전 변경을 의미함 (~1.2.3 이면 1.3.0 까지 포함)
    • 캐럿(^)이란 정식버전에서 마이너와 패치버전을 변경함(^1.2.3 이면 1.2.3부터 2.0.0 미만까지 포함), 하위 호환성 유지

 

실습

  • 기본 실습
  • 웹팩 이전 script 로딩은 src/app.js, src/math.js 를 index.html에서 <script src>로 로드하여 사용하여 전역스코프가 오염되는 문제가 있었음
  • index.html 안에서 html만 작성하면 VSCode의 emit으로 HTML5 쉽게 작성 가능
<!DOCTYPE html>
  <html lang="en">
  <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <title>Document</title>
  </head>
  <body>
      <script src="src/math.js"></script>
      <script src="src/app.js"></script>
  </body>
</html>
  • window.sum(1,2)로 실행하면 문제. 따라소 IIEF(즉시 실행 함수 표현)방식으로 생성하여 실행함.
// IIEF - math.js
var math = math || {};

(function(){
    function sum(a,b) {
        return a + b;
    }
    math.sum = sum;
})()

 

표준 모듈 시스템

  • CommonJS는 자바스크립트를 사용하는 모든 환경에서 모듈을 제공하는것을 목표로 한다
    • 브라우저 처럼 외부에서 자바 스크립트를 로딩하여 사용해야하는 경우 AMD(Asynchronous Module Definition)방식을 사용한다
    • UMD = AMD 기반으로 CommonJS 방식까지 지원하는 통합
    • 이렇게 각자 스펙을 제안하다 ES2015에서 표준 모듈 시스템을 내놓았다 (export, import)

 

실습

  • 모듈 시스템으로 실행 IE 등에서는 이 모듈 시스템을 사용하지 못한다
    • html의 <script>를 변경한다 <script type="module" src="src/app.js"></script>
    • npx lite-server 로 로컬에 서버를 띄운다 (로컬에서 읽다가 CORS 오류가 날 경우)
  • 웹팩 설치 npm install -D webpack webpack-cli (개발용 디펜던시로 설치)
    • package.json에 추가된 내용 확인
"devDependencies": {
    "webpack": "^5.70.0",
    "webpack-cli": "^4.9.2"
}

 

  • 웹팩 실습
    • 웹팩의 필수 3가지 옵션 : mode, entry, output(-o, --output-path)
    • mode 에는 development(개발), production(운영), none 설정가능
    • module이 시작되는 지점이 entry
    • 번들을 저장하는 경로 설정이 output(-o, --output-path)
    • node_modules/.bin/webpack --help 로 사용 가능한 명령어 확인
    • node_modules/.bin/webpack --mode development --entry ./src/app.js --output-path ./dist/. 명령어 실행하여 번들 확인
asset main.js 4.31 KiB [emitted] (name: main)
runtime modules 670 bytes 3 modules
cacheable modules 340 bytes
  ./src/app.js 97 bytes [built] [code generated]
  ./src/math.js 243 bytes [built] [code generated]
webpack 5.70.0 compiled successfully in 103 ms

 

  • dist 하위에 main.js 파일로 번들링 결과 확인 가능
  • html 파일에서 번들파일을 로드하게 수정 <script type="module" src="dist/main.js"></script>
  • npx lite-server 실행하여 결과 확인

 

  • package.json의 build script로 webpack 지정하여 npm을 사용하여 빌드해보자
// package.json 내용
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack" // webpack.config.js 파일을 자동으로 찾아서 빌드한다
  },

// webpack.config.js 내용
const path = require('path');
module.exports = {
    mode: 'development',
    entry: {
        main: './src/app.js'
    },
    output: {
        path: path.resolve('./dist/.'),
        filename: '[name].js'
    }
}

 

  • npm run build 해주면 된다

 

  • css 웹팩으로 번들링 (app.js에 로딩하기)
    • style-loader, css-loader 두가지 필요
    • module > rules 안에 style-loader, css-loader 선언하기
  • 파일을 로드하기
    • file-loader 필요 위와 동일하게 선언하고 options에 파일명 규칙 작성
  • 이미지를 base64로 인코딩하기
    • url-loader 를 설치
    • file-loader 대체하여 선언하고, limit을 10000(10kb)로 정의
  • 커스텀 플러그인
    • plugins라는 배열에 추가한다
    • 만든 커스텀 플러그인 클래스에서 module.exports 로 해당 클래스 명을 쓴다
  • 플러그인 핸들링
    • compilation.assets로 컴파일하는 파일에 접근가능
    • 웹팩의 로더는 모듈로 연결된 파일을 처리한다
    • 그 직전에 플러그인이라는 애가 개입하여 아웃풋으로 만들어질 결과물에 대한 후처리를 해준다
    • 실제로 플러그인을 직접 만들 일은 거의 없다
  • 자주 사용하는 플러그인 
    • 번들이 잘 배포 되었는지 확인을 위해 BannerPlugin을 사용
plugins: [
        new webpack.BannerPlugin({
            banner: 'Build Date: '+ new Date().toLocaleString()+''
        })
    ]

 

  •     DefinePlugin 플러그인
plugins: [
        ...,
        new webpack.DefinePlugin({
            TWO:'1+1',
            TWO_STRING: JSON.stringify('1+1'),
            'api.domain': JSON.stringify('http://dev.api.domain.com')
        })
    ]
// app.js에서 아래 로그 찍어 볼 수 있음
console.log(process.env.NODE_ENV);
console.log(TWO);
console.log(TWO_STRING);
console.log(api.domain);

 

  •     html도 src 내에서 웹팩으로 관리 하는 법
    • npm install html-webpack-plugin
    • index.html을 src 하위로 이동하고 html 내의 <script>를 지움
//webpack.plugin.js 에서 아래 내용 작성함
const HtmlWebpackPlugin = require('html-webpack-plugin');

plugins: [
        ...,
        new HtmlWebpackPlugin({
            template: './src/index.html' // http://localhost:3000/dist/index.html 빌드 후에 이 경로로 접근 가능함
        })
    ]
  •     이때, 미리 작성해둔 경로들 확인 (index.html이 src 하위로 이동하며 경로 수정 필요할 수 있음)
  • 프로젝트의 dist 폴더 하위에 생성된 index.html 파일을 확인하면 <script defer src="main.js"></script> 가 자동으로 추가된 것을 확인할 수 있다
  • html-webpack-plugin을 사용하여 html까지 관리하면 좀 더 유연한 html 작성이 가능하다

 

  • 환경변수에 따라 html 내용변경 적용하기
    • index.html 내에 <title>Document<%= env%></title> 작성
// webpack.config.js 내에 templateParameters로 env 작성
plugins: [
        ...,
        new HtmlWebpackPlugin({
            template: './src/index.html', // http://localhost:3000/dist/index.html 빌드 후에 이 경로로 접근 가능함
            templateParameters: {
                env: process.env.NODE_ENV === 'development' ? '(개발용)' : ''
            },
            minify:{
                collapseWhitespace: true, // html 내 빈칸 생략
                removeComments: true // html 내 주석 생략
            }
        })
]
  • NODE_ENV=development npm run build 로 빌드하면 dist/index.html 의 타이틀이 Document(개발용)로 적용된 것을 확인 할 수 있다
plugins: [
        ...,
        new HtmlWebpackPlugin({
            template: './src/index.html', // http://localhost:3000/dist/index.html 빌드 후에 이 경로로 접근 가능함
            templateParameters: {
                env: process.env.NODE_ENV === 'development' ? '(개발용)' : ''
            },
            minify: process.env.NODE_ENV === 'production' ? {
                collapseWhitespace: true,
                removeComments: true
            } : false
        })
    ]
  • NODE_ENV=production npm run build 로 빌드하면 축약, 주석생략 등 된 파일을 확인할 수 있다

 

  • dist 하위 clean 후 새로운 빌드내용으로 저장되게 하는 플러그인 적용
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

plugins: [
        ...,
        new CleanWebpackPlugin()
    ]

 

  • 스타일시트만 따로 뽑아서 파일 분리하기
    • 페이지 로딩 성능 향상을 위해 스타일시트용 파일만 따로 뽑아서 파일을 분리한다
    • 브라우저에서 하나의 큰 파일을 다운로드 받기 보다는 역할 별로 나누어 받도록 개선하는 작업이다
    • npm install mini-css-extract-plugin 를 실행한다
// webpack.config.js 에 아래 설정을 작성한다
plugins: [
    ... ,
    // 1. 환경변수에 따라 변경이 아닌 기본적용 방법
    // new MiniCssExtractPlugin({
    //     filename: "[name].css"
    //   })

    // 2. 환경변수에 따라 변경하는 방법
    // 나머지 연산자 활용
    // (intermediate value) is not iterable 에러는 [ ] 대괄호를 안쳐서남
    ...(process.env.NODE_ENV === "production"
      ? [new MiniCssExtractPlugin({ filename: `[name].css` })]
      : [])
  ]
  • NODE_ENV=production npm run build 를 실행하여 css 추출을 확인하자

 

 

 

https://www.inflearn.com/course/%ED%94%84%EB%A1%A0%ED%8A%B8%EC%97%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%ED%99%98%EA%B2%BD/dashboard