반응형

최신 웹 생태계에서는 번들러가 필수적이다

typescript, scss를 파싱해야하며

코드의 압축, 난독화를 진행하기위해서도

번들러를 쓰게된다

 

그 중에서도 가장 인기있고

계속 업데이트 되고있는 Webpack에 대해 알아본다

 

핵심 4가지 요소

Webpack의 구성요소는 아래의 4개로 나눠볼 수 있다.

1. entry

2. output

3. loader

4. plugin

 

entry

entry는 webpack에서 웹 자원을 변환하기 위해

필요한 최초의 진입점이자, javascript 파일 경로다.

 

즉, entry에서 지정한 파일 경로를 대상으로

webpack이 빌드를 진행한다.

 

entry(진입점)가 되는 js에는

웹 어플리케이션의 전반적인 구조와 내용이 담겨있어야 한다.

 

SPA가 아닌 경우 object형태로 여러개의 진입점을

형성해두는것도 가능하다.

// 예시
module.exports = {
  entry: './src/index.ts',
}

 

output

output은 webpack이 빌드를 진행한 후

결과물들을 어디에 만들것인가, 즉 파일 경로를 의미한다.

 

output은 entry와 달리 object 구조를 갖는다.

(filename, path 등의 속성을 갖음)

 

output은 파일 경로를 의미하기 때문에 최소한

filename은 지정해주어야 한다.

 

filename을 지정함에 있어 4가지 옵션을 적용할 수 있다.

module.exports = {
  entry: './src/index.ts',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: [name].bundle.js,
    // filename: [id].bundle.js
    // filename: [name][hash].bundle.js
    // filename: [chunkhash].bundle.js
  }
}

1. name: entry 속성과 같은 이름을 적용

2. id: 웹팩 내부적으로 모듈 ID를 적용

3. name,hash: 매 빌드시 마다 고유 해시 값을 적용

4. chunkhash: 웹팩의 각 모듈 내욜을 기준으로 생성된 해시값을 붙임

 

위 내용들이 제법 중요하다.

실제로 프로덕트를 운영하다보면 새 코드를 배포후

새로고침 하였을때, 즉시 적용되지 않는 경우가 발생한다.

 

코드가 바뀌었음에도 파일명이 변하지않아

기존 브라우저 캐시로 인해 업데이트 사항을 인식하지 못하는 케이스다.

사용자가 강제 새로고침을 통해 해결할 수 있지만...

그런 사용자가 얼마나 있겠는가, 파일 버전관리를 잘해주어야한다.

 

loader

webpack이 웹 어플리케이션을 해석할 때,

js가 아닌 웹 자원들을 변환하려면 loader를 적용해주어야한다.

(웹 자원: html, css, image, font 등)

 

loader는 module이라는 속성명을 갖는다.

module 속성 내 rules에 배열 구조로

loader를 설정하게된다.

 

rule은 test, use의 속성을 갖는다.

test는 loader를 적용할 파일 유형이고,

use는 해당 파일에 적용할 loader의 이름이다.

module.exports = {
  entry: './src/index.ts',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: [name].bundle.js,
  },
  module: {
    rules: [
      {
        test: /\.scss$/,
        use: [
          { loader: 'style-loader' },
          {
            loader: 'css-loader',
            option: {
              module: true
            }
          },
          { loader: 'sass-loader' }
        ]
      },
      { 
        test: /\.ts$/, 
        use: 'ts-loader' 
      }
    ]
  }
}

주로 많이 사용하는 loader로는

babel-loader, sass-loader, file-loader, ts-loader 등이 있다.

 

위 예시에서 보는것 처럼 하나의 rule에

여러개의 loader를 설장할수도 있는데, 이 때 loader의 순서도 매우 중요하다.

loader는 코드 순서 상, 기본적으로 우 -> 좌 (아래 -> 위)로 적용한다.

예시로 보면 sass-loader > css-loader > style-loader 순으로 적용된 다는것이다.

 

plugin

웹팩의 기본적인 동작 외에,

추가적인 기능을 제공하기 위한 특성이다.

 

plugin 속성에 배열 구조로 값을 받는다.

plugin은 생성자 함수로 생성된 인스턴스 객체만을 추가할 수 있다.

 

주로 사용되는 plugin으로는

split-chunk-plugin, clean-webpack-plugin, image-webpack-plugin 등이 있다.

module.exports = {
  entry: './src/index.ts',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: [name].bundle.js,
  },
  module: {
    rules: [
      { 
        test: /\.ts$/, 
        use: 'ts-loader' 
      }
    ]
  },
  plugin: [
    new webpack.progressPlugin(),
    new htmlWebpackPlugin({ template: './public/index.html' })
  ]
}

 

 

webpack의 동작 방식

지금까지 webpack 설정을 위한 구성요소를 알아봤다면

마지막으로 동작방식에 대해 알아본다.

 

1. webpack이 entry에서 부터 해석을 시작

2. 해석에 있어 각 loader들을 적용한다.

3. loader를 적용한 결과물을 산출한다.

4. 산출된 결과물에 plugin을 적용한다.

5. 산출된 결과물이 output 경로에 생성된다.

반응형

'개발, 코딩' 카테고리의 다른 글

git 기본기_백과사전 (1)  (0) 2022.10.24
git 협업하기 - 실무편  (0) 2022.10.23
Rest API 정리  (0) 2022.09.29
java zulu jdk11 설치  (0) 2022.07.31
M1 Mac, homebrew install (Warning: /opt/homebrew/bin is not in your PATH.)  (0) 2022.07.31
반응형

올바른 개발자가 개발을 하다보면

자기의 입맛, 혹은 팀의 입맛에 맞게

개발에 도움이 되는 환경을 세팅해나가게 된다.

 

그러다보면 로컬에서는 적용되는데 서버에서는 뭔가 적용이 안되거나하는

경우가 종종 발생한다.

이번엔 그중에서 font 적용에 대해서 알아본다.

 

/MyApp
  /public
    /fonts
      honey-Bold.ttf
      honey-Bold.eot
      honey-Regular.ttf
      honey-Regular.eot
    /images
    index.html
  /src
    app.js
    index.css

 

자, 주어진 프로젝트 환경의 파일트리가 위와 같은 상황이다.

index.css에서 프로젝트 내 모든 텍스트의 폰트를 잡아주려고한다.

어떻게 하면될까?

 

// index.css

@font-face {
    font-family: 'honey';
    src: url('/public/fonts/honey-Bold.eot');
    src: url('/public/fonts/honey-Bold.eot') format('embedded-opentype'), url('/public/fonts/honey-Bold.ttf') format('truetype');
    font-weight: 600;
    font-style: normal;
}

@font-face {
    font-family: 'honey';
    src: url('/public/fonts/honey-Regular.eot');
    src: url('/public/fonts/honey-Regular.eot') format('embedded-opentype'), url('/public/fonts/honey-Regular.ttf') format('truetype');
    font-weight: 400;
    font-style: normal;
}

* {
    font-family: 'honey', sans-serif;
}

 

honey라는 폰트는 없겠지만 예를들면 이렇다.

woff 까지 이와 같은 방식으로 설정해주면 된다.

 

eject한 CRA 프로젝트라면 빌드 했을때,

dist폴더가 자동으로 생성되며

dist/ 폴더아래로 빌드된 파일이 들어가게되는데

여기서 부터 문제가 발생한다.

 

빌드해 서버에 업로드했더니 폰트가 먹지않는 이슈

 

왜그럴까?

dist/ 폴더에는 public/fonts/ 가 존재하지 않는다.

간단한 webpack 설정을 통해 경로를 맞춰주어야한다.

 

npm install file-loader --save-dev
npm install copy-webpack-plugin --save-dev

 

준비물은 위 두가지이다.

 

const CopyWebpackPlugin = require('copy-webpack-plugin');

...

module: {
  rules: [
    {
      test: /\.(woff|woff2|eot|ttf|otf)$/,
      use: [
        {
          loader: 'file-loader',
          options: {
            name: '[name].[ext]',
            outputPath: 'fonts/',
            publicPath: '/public',
          }
        }
      ]
    }
  ]
},

...

plugins: [
  new CopyWebpackPlugin({
    patterns: [
      {
        from: 'public/fonts',
        to: 'publi/fonts',
      }
    ]
  })
],

핵심은 CopyWebpackPlugin 부분이다.

여기서 무슨 일이 일어나냐면

public/fonts/ 경로의 파일들은

dist 아래에도 똑같이 만들어주는것이다.

 

그러면 빌드후에도 css설정이 당연하게도 잘 들어맞는다.

 

반응형
반응형

구글에서 제공해주는 도구들을 이용해 체크해보니 운영중인 웹사이트 로딩속도가 어마어마하게 느렸다

모바일 기준으로 19.7

 

경악스러웠다.

당장 손볼수 있는것들을 손봤고 약 2배정도 빠른 속도를 얻어 방법을 공유한다.

 

이미 되어있던 퍼포먼스 관련 설정들

1. 서버 로드밸런스

2. 부분적으로 적용한 이미지 cloud front

 

 

추가한 퍼포먼스 관련 설정들

1. Nginx - gzip

2. Webpack - compression

3. Code spliting

4. 전체 이미지 cloud front 적용

 

이 중에서 가장 쉽고 큰 효과를 얻은것은 gzip이 아닌가싶다

주의할점은 클라이언트와 웹서의 서버가 분리되어있다면 양쪽 모두에 설정해주어야 한다는 점이다.

 

코드는 간결하다. nginx.conf 파일에 아래의 내용을 설정한다.

http {
...

gzip  on;

gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/x-javascript application/javascript text/xml application/xml application/xml+rss text/javascript;

...
}

 

코드 스플리팅은 react의 lazy/suspense를 이용해서 간단히 설정해주었다.

코드를 너무 작은단위로 나눠도 호출하는 시간에서 손해가 발생하기 때문에 webpack plugin 설정에 아래와같이

최소 크기를 설정해주었다

...,
plugins: [
  ...,
  new webpack.optimize.MinChunkSizePlugin({
    minChunkSize: 512000, // 50kb
  }),
  ...          
]

compression은 역시 plugin 에서 간단히 추가했다.

[
  new CompressionPlugin({
    filename: '[path][base].gz',
    algorithm: 'gzip',
    test: /\.js$|\.css$|\.html$/,
    threshold: 10240, // 10kb
    minRatio: 0.8,
  }),
]

 

반응형