본문 바로가기

시리즈/돌아가보기

처음으로 돌아가기 | 애셋을 적용한 웹팩 번들링, 우리가 import './style.css ' 등이 가능했던 이유(애샛 파트 ① CSS, Image, Font)

반응형

이전 포스트 | 처음으로 돌아가기, 웹팩을 사용한 기초 번들링

 

 

처음으로 돌아가기, 웹팩을 사용한 기초 번들링

처음으로 돌아가기, 첫 번째 프로젝트 환경 설정현재에는 프론트엔드 개발을 하기 위한 환경을 구축하는 것이 매우 쉽습니다. Vite 를 이용하면 손쉽게 개발 환경이 구축되고, 리액트,뷰, 앵글러

duklook.tistory.com

 


들어가는 말, 이 포스트에서 해볼 것

이번 시간에는 CSS, 이미지, 폰트애셋을 통합하여 웹팩 번들링 시 포함시켜주는 설정에 대해서 정리해보는 시간을 가져볼 겁니다. 이 때 까지 편하게 사용했던 import 방식이 왜 쉽게 가능했는가에 대한 부분이 되겠습니다. 원래 라면 outside 등의 문제가 발생해서 모듈을 인식하지 못하는 문제가 일반적인데, 웹팩은 이 문제를 쉽게 처리할 수 있도록 해주고 있습니다. 왜 가능했던건지 하나하나 설정을 통해서 따라가 봅시다.

 

애셋 첫 번째 |  CSS

우선 제일 익숙한 CSS 에 대한 처리를 시도해보겠습니다.

 

 

CSS loader 설치 및 설정

자바스크립트 모듈 내에서 CSS 를 import 하기 위해서는 style-loader 와 css-loader 를 설치하고, 이를 module 설정에 추가해주어야 합니다. 즉, import style.css, import module.css 와 같이 JS 파일 최상단에서 import 되어 있는 모든 파일들을 하나의 리소스로 통합하는 작업을 웹팩이 수행할 수 있도록 환경을 구성하는 파트 입니다.

 

따라서 우선 패키지 부터 설치해봅시다.

npm install --save-dev style-loader css-loader

 

그러면 아래와 같이 두 개의 패키지가 설치된 것을 볼 수 있을 겁니다.

 

 

그 후 webpack.config.js 파일로 가셔서 module rule 속성으로 아래와 같이 추가해주어야 합니다.

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: ['style-loader', 'css-loader']
      }
    ]
  }
};

 

여기서 use: ['a', 'b' ] 형태로 적힌 부분이 앞서 설치된 로더의 실행 순서를 나타내는 배열입니다. 이 때 사용되는 로더의 순서는 배열의 역순이며, 리소스를 변환하는 작업에 사용됩니다.

 

즉, 우선 css-loader 를 통해 번들링된  CSS 소스를  style-loader 를 사용하기 전에 전달하고, style-loader 를 실행하게 되며, 최종적으로 html 파일의 head 의 style 태그 내부로 앞서 번들링된 리소스를 삽입합니다.

쉽게 말해 import style.css, import module.css 등등으로 JS 파일 내에 설정되어 있는 모든 css 파일을 하나의 리소스로 통합하여 이를 style 태그 내에 포함시키게 되는 겁니다.

 

앞서 rules : [{ test: '' }] 와 같이 적힌 부분이 보이는데요. 이는 테스트를 수행할 파일의 확장자를 정규 표현식을 사용하여 나타낸 것입니다. 즉, style.css, webpack.css 와 같이 다양한 이름을 가진 파일이라도 확장자가 .css 라면 use 에 등록된 로더의 적용 대상이 된다는 의미입니다.

 


 

여기 까지 오셨다면, 이제 CSS 파일을 JS 내에서 import 하더라도 번들링 된 이후에는 모든 CSS 파일이 하나의 리소스로 통합되어 index.html 파일의 head > style 태그 내 삽입되게 됩니다.

 

정상적으로 동작하는지 확인해보기(영상 + 구성파일)

그렇다면, 어떻게 동작하는지 한 번 영상으로 살펴보도록 하겠습니다.

 

 

결과만 본다면, 성공적으로 css 파일들이 하나의 모듈 파일로 결합이 되었습니다.

 

 

아래는 앞서 영상에서 보여드린 설정 파일을 모두 정리한 것이니 참고하셔서 시도해보세요.

dist/index.html 파일 설정

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>D3</title>
</head>
<body>
    <div id="root"></div>
    <script src="main.js"></script>
</body>
</html>

 

src / index.js 파일 설정

/* src/index.js */

// 여기서 import 한 css 파일이 향후 loader 를 통해 하나로 합쳐집니다.
import './redbox.css'
import './index.css'

// 요소를 동적으로 생성하는 함수입니다.
function app() {

    const el = document.createElement('div')
    el.classList.add('red_box')

    return el
}

// 생성된 함수를 div#root 로 생성된 div 요소의 자식으로 추가합니다.
const root = document.getElementById('root')
root.appendChild(app())

 

src/ .css 파일 설정

/* src/redbox.css*/

.red_box {
    width:500px;
    height:500px;
    background: red;
}

/* src/index.css */

* {
    margin:0;
    padding:0;
    box-sizing: border-box;
}

body {
    width:100%;
    height:100vh;
    background: #333;
}

 

package.json 파일 설정

{
  "name": "d3",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack"
  },
  "private": true,
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "css-loader": "^7.1.2",
    "style-loader": "^4.0.0",
    "webpack": "^5.92.1",
    "webpack-cli": "^5.1.4"
  }
}

 

webpack.json.js  파일 설정

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: ['style-loader', 'css-loader']
      }
    ]
  }
};

 


애샛 두 번째 | image

이제 image 파일에 대한 부분을 번들링 해보겠습니다. 우리가 리액트에서 사용될 때 import ~ from './image.png' 형식으로 사용하고 있죠? 왜 이게 가능할까요 순수한 자바스크립트 내에서는 사실 불가능한 방식 입니다. 하지만 웹팩은 이것을 가능하게 해주고, 심지어 해당 import 된 파일들을 img src ="./image.png" 형식으로 정리해주기도 합니다(이는 내부적으로 사용되고 있는 html-loader 패키지 덕분입니다)

 

webpack.config.js 에서 이미지 애셋 테스트 추가하기

webpack v5 부터는 기본적으로 내장된 Asset Modules 를 사용하여 현재 시스템에 쉽게 통합할 수 있다고 합니다. 따라서 별도의 패키지 설치 없이 조금의 설정만 추가해주면 됩니다. 

 

앞서 css 로더를 설정했던, webpack.config.js 로 돌아가셔서 아래와 같이 testasset 속성을 modules의 rules 에 추가 해줍니다.

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: ['style-loader', 'css-loader']
      },
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: 'asset/resource',
      },
    ]
  }
};

 

 

이미지 파일 추가 후 번들링 해보기

src/이미지.png 등 추가

앞서 설정이 마무리 되었다면, src/ 경로에 아무 이미지 파일이나 첨부해봅시다. 저는 아래 이미지를 사용해보겠습니다. 저의 블로그 프로필로 되어 있는데, 디퓨전 AI 을 사용해서 만든 겁니다.

 

 

혹시 모르니 이미지 파일도 첨부해 봅니다. 

human.jpg
0.20MB

 

src/index.js 에서 이미지 import 하기

그리고 앞서 준비한 이미지를 import ~ from ~ 형식으로 가져와서 src/index.js 파일의 최상단에 입력해 주고, 해당 이미지 요소를 root 요소의 자식 요소로 추가해주는 로직을 별도로 작성해줍니다.

// 여기서 import 한 css 파일이 향후 loader 를 통해 하나로 합쳐집니다.
import './redbox.css'
import './index.css'
import humanImage from './human.jpg'

// 요소를 동적으로 생성하는 함수입니다.
function app() {

    // const el = document.createElement('div')
    // el.classList.add('red_box')

    const humanImgEl = new Image()
     humanImgEl.src = humanImage
     humanImgEl.width=300
     humanImgEl.height=300
     humanImgEl.alt="인간 이미지"

    // return el
    
    return humanImgEl
}

// 생성된 함수를 div#root 로 생성된 div 요소의 자식으로 추가합니다.
const root = document.getElementById('root')
root.appendChild(app())

 

결과 보기

npm run build 를 수행하고 나면, 정상적으로 이미지가 로드된 것을 볼 수 있어야 합니다.

 

 

번들링이 완료되면 앞서 첨부했던 이미지가 dist 폴더에 추가되고, main.js 에도 추가되어 있는 것을 볼 수 있습니다.

 


세 번째 애샛, fonts

이번에는 폰트입니다. 사실 애셋 부분은 웹팩에서 모두 유사한 과정을 거쳐서 이루어지기 때문에, 앞서 설정방식과 동일합니다. 

 

font 설정 추가 후 번들링 해보기

webpack.config.js 파일에 폰트 애샛 테스트 추가하기

webpack.config.js 로 오셔서 testtype 설정을 아래와 같이 추가해주면 됩니다.

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: ['style-loader', 'css-loader']
      },
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: 'asset/resource',
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/i,
        type: 'asset/resource',
      },
    ]
  }
};

 

번들링할 폰트 추가 및 CSS 설정하기

폰트의 경우에는 .woff 와 같은 확장자를 가질 수 있습니다.  이는 CSS 파일에서 @font-face 를 추가하여 로컬에 있는 폰트 파일을 사용할 수 있게 할 수 있습니다.  src:url('./my-font.woff') 와 같은 형식일 때, 프로젝트에서 해당 폰트를 인식할 수 있는 이유가 우리가 사용하는 웹팩과 같은 번들링 도구 덕분입니다.

 

따라서 우선적으로 사용할 폰트를 src 경로에 추가해주고, 이를 css 파일에서 가져오는 로직을 추가해주도록 하겠습니다. 저는 ttf 파일을 사용하도록 하겠습니다. 아래 폰트 파일은 네이버에서 제공해주는 무료 폰트입니다.

MaruBuri-ExtraLight.ttf
7.41MB

 

CSS 파일에서 font-face 설정 시 url 과 format 은 파일의 확장자와 경로에 맞게 잘 입력해주셔야 합니다. url('') 에 입력된 주소는 CSS-loader 를 통해 인식되고, font 애샛에 의해 번들링 시 처리하게 됩니다.

/* src/index.css */

@font-face {
    font-family: 'MyFont';
    src: url('./MaruBuri-ExtraLight.ttf') format('ttf'),
      url('./MaruBuri-ExtraLight.ttf') format('ttf');
    font-weight: 600;
    font-style: normal;
  }


* {
    margin:0;
    padding:0;
    box-sizing: border-box;
}

body {
    width:100%;
    height:100vh;
    background: #333;
}

 

전체적으로 이런 아래 이미지와 같은 구조가 될겁니다.

 

 

여기 까지 하셨으면, npm run build 하여 번들링을 시도해봅시다. 아래와 같이 output 경로인 dist 폴더 내에 .ttf 파일이 생성되었다면 성공입니다.

 

 


나가는 말 

현재 까지 CSS, Image, Font 에 대한 애샛을 어떻게 처리하는지 설정해보는 시간을 가져보았습니다. 다음 시간에는 동일한 애샛으로 관리되는 대망의 json, csv 를 번들링하는 설정하는 시간을 가져볼 것입니다. 원래라면 하나의 포스트에 정리할까 했지만, 아직 갈 길이 멀기 때문에 파트를 나눠서 진행하도록 하겠습니다. 다들 고생 많으셨습니다.

 

다음 포스트 | 처음으로 돌아가기, 애샛 데이터 

 

처음으로 돌아가기 | 애샛 설정을 통한 웹팩 번들링, 그 두 번째 json/xml/csv

참고한 자료는 webpack 공식 문서를 사용하였습니다. 애샛 설정 두 번째, 데이터프로젝트 환경에서 NodeJS 의 경우에는 JSON 지원을 기본적으로 해줍니다. 따라서 import data from './data.json' 형태로 불러

duklook.tistory.com

 

 

 

 

 

 

 

 

 

반응형