Webpack과 모듈 번들러

jonyChoiGenius·2023년 1월 10일
0

CRA 없이 배우는 Webpack
모듈 번들러 톺아보기
JavaScript 표준을 위한 움직임: CommonJS와 AMD
web (2)
[JS] 모듈의 역사와 문법(CommonJS, AMD, ESM 등)

ESM과 CommonJS의 차이
[React] Babel, Webpack 동작 원리 간단히 알아보기
Create-React-App의 Webpack 기본 설정 살펴보기

모듈 번들러

모듈화

  1. 자바스크립트의 변수의 범위는 기본적으로 어플리케이션 전체의 범위(전역 스코프)를 갖는다. 따라서 여러 js 파일로 구성된 경우(특히 모듈별로 파일을 관리하는 경우), 네임 스페이스 문제는 물론 개발과정에서 동일한 변수를 여러 파일에 지정하는 등의 문제가 발생된다.
  2. 기본적으로 파일의 전송 혹은 압축은 파일이 여러개일수록 불리하다. (파일이 여러개인 경우 파일에 접근하기 위한 연산 혹은 메타데이터가 늘어나며, 파일의 압축의 경우 동일한 패턴을 제외하는 방식으로 일어나는 바, 파일의 갯수가 늘어날수록 압축 및 전송이 불리해짐.)

이에 따라 '하나의 js파일'로 '모듈별로 스코프를 나누어서' 관리하는 것이 요구된다.

클로저

하나의 파일에서 모듈을 관리하는 기본적인 방식은 클로저의 원리를 이용하는 것이다.

var wordIIFE = (function () {
  var word = 'hello';

  return {
    getWord: function () {
      return word;
    },
  };
})();

console.log(wordIIFE.getWord()); // hello
console.log(word); // ReferenceError

위와 같은 방식으로 각 모듈 내의 변수를 반환받으면서도, 외부에서 접근 및 수정하지 못하도록 모듈 패턴을 구현할 수 있다.

CommonJS

CommonJS는 구글이 공개한 V8 엔진의 성능에 고무받아 2009년 발표한 모듈화 라이브러리이다.

  1. Scope : 모든 모듈은(각각의 파일은) 각각의 독립적인 실행영역을 가진다.
  2. Definition: 모듈 정의는 exports 객체를 이용한다.
  3. Usage: 모듈 사용은 require 함수를 이용한다.

CommonJS가 적용된 환경(대표적으로 Node.js)에서 자바스크립트 파일은 각각의 Scope를 지니며, exports를 이용해 모듈을 공개하고, require() 함수를 이용해 모듈을 사용한다.

CommonJS는 모듈을 삽입하기 위해 blocking이 일어나기 때문에 실제 브라우저 환경에서 사용하기에는 느리다는 단점이 있으며, CommonJS의 대안으로 AMD(Asynchronous Module Definition)라는 non-blocking, async가 있다. 한편 ES6에서 공개된 ESM(ECMAScript Module)은 export - import구문으로 작동되며, 파일의 비동기 삽입을 제한하는 대신 파일의 최적화에 집중하고 있다.

Webpack

웹팩은 '모든' 웹 어플리케이션의 자원들을 모듈로 간주한다. 즉 자바스크립트 뿐만 아니라 HTML, CSS, 기타 font와 image와 같은 파일들을 포함한다.

웹팩은 1. 다양한 플러그인을 지원하여 확장성이 좋다. 2. 가장 대중적이다. 3. Hot Module Replacement(HRM)을 지원한다.(Dev Server)

웹팩을 적용하면 onClick.js, index.js 등 여러개의 자바스크립트 파일이 하나의 main.js로 변환된다. 이는 request 요청 횟수를 줄임을 의미하고, 이는 곧 패킷 유실과 네트워크 부하, 서버의 연산 감소 등을 의미한다.

loader

웹팩에서 가장 강력하고 자주 쓰이는 것이 loader이다.
bebel-loader를 통해 자바스크립트 파일을 ES5이하의 버전으로 컴파일 시킬 수 있다.
sass-loader는 node-sass패키지를 통해 sass를 css로 컴파일 시키며,
css-loader를 통해 문자열로 변환한 후 style-loader를 통해 <style>태그로 <head>에 삽입하는 자바스크립트코드를 만든다.

즉 웹팩을 사용하면 html파일 하나와 main.js파일 하나만이 만들어지게 된다. 그 밖에 js파일이나 css파일은 없다.

Webpack Config

npm install webpack webpack-cli으로 webpack을 설치하고, webpack -w로 웹팩을 실행하면 웹팩은 프로젝트 루트 파일의 webpack.config.js를 바탕으로 번들링을 시작한다. 이 과정에서 웹팩은 파일 간의 의존성 문제도 해결한다.

CRA를 통해 만들어진 리액트 앱의 경우 npm run eject을 통해 숨겨져 있던 설정을 변경할 수 있다. 이 작업은 되돌릴 수 없으며, 이후 추가되는 라이브러리의 의존성 문제를 직업 해결해야 함을 의미한다.

entry

번들링이 시작하는 entry point를 지정한다. 해당 파일이 의존하는 모듈과 라이브러리들을 찾아낸다.

module.exports = {
	entry: paths.appIndexJs,
};
output

path : 번들링된 결과물의 위치를 설정한다.
filename : 번들링된 결과물의 이름을 설정한다.
그 밖에 개발 모드에서 사용되는 경로와 production 모드에서 사용하는 경로를 나눈다. production시에는 chunck파일(즉, 웹팩으로 만들어진 main.js를 다시 분해한 파일)에 고유한 hash가 붙어 파일을 구분하게 해준다.

module.exports = {
	output: {
	  // 빌드 폴더의 경로
	  path: paths.appBuild,
	  // 출력에서 생성된 require()에 /* filename */ 주석을 추가합니다.
	  pathinfo: isEnvDevelopment,
	  // 하나의 메인 번들과 비동기 청크당 하나의 파일이 있습니다.
	  // 개발 중에는 실제 파일을 생성하지 않습니다.
	  filename: isEnvProduction
	    ? 'static/js/[name].[contenthash:8].js'
	    : isEnvDevelopment && 'static/js/bundle.js',
	  // 코드 분할을 사용하는 경우 추가 JS 청크 파일도 있습니다.
	  chunkFilename: isEnvProduction
	    ? 'static/js/[name].[contenthash:8].chunk.js'
	    : isEnvDevelopment && 'static/js/[name].chunk.js',
	  assetModuleFilename: 'static/media/[name].[hash][ext]',
	  // webpack은 `publicPath`를 사용하여 앱이 제공되는 위치를 결정합니다.
	  // 후행(trailing) 슬래시가 필요합니다. 그렇지 않으면 파일 자산의 경로가 잘못됩니다.
	  // 홈페이지에서 "공개 경로"(예: / 또는 /my-project)를 추론했습니다.
	  publicPath: paths.publicUrlOrPath,
	  // sourcemap 항목을 원래 디스크 위치(original path)로 지정(Windows에서 URL 형식)
	  devtoolModuleFilenameTemplate: isEnvProduction
	    ? info =>
	        path
	          .relative(paths.appSrc, info.absoluteResourcePath)
	          .replace(/\\\\/g, '/')
	    : isEnvDevelopment &&
	      (info => path.resolve(info.absoluteResourcePath).replace(/\\\\/g, '/')),
	},

}
optimization

SplictChunkPlugin으로 청크를 만들 때의 옵션을 지정한다.

CRA의 기본값은 production 모드일 때에 청크를 실행하며, 다음의 플러그인을 사용하여 최적화를 진행한다.
TerserPlugin : 자바스크립트 코드 압축기이다.
OptimizeCSSAssetsPlugin: CSS 압축기이다.

resolve

모듈을 해석하는데 필요한 정보이다. 가령 node_modules의 경로 등이 이 곳에 명시되어야 한다.

module

규칙에서 test로 로더를 적용할 파일명 규칙을, exclude에서 로더에서 제외할 파일명을 정의한 후, 불러올 loader들과 각 loader들의 옵션을 정의한다.

plugins

plugins 객체들을 모아둔 곳이다. new Plugin()의 형태로 새로운 익명 객체를 만들어둔다. 가령 HtmlWebpackPlugin은 번들링된 main.js를 참조하는 html파일을 빌드 과정에서 생성한다.

"scripts"

pakage.json에는 "scripts"라는 설정이 있다. 해당 설정에서 실행되는 scrips 폴더의 js파일들이 웹팩 빌드 설정을 의미한다. 가령 start.js는 웹팩 빌드 설정을 develpoment로 하여 빌드 후 실행하고, build.js는 웹팩 설정을 production으로 적용하여 빌드한 후, 해당 파일이 exports된 새로운 build 폴더를 반환하고 실행한다.

profile
천재가 되어버린 박제를 아시오?

0개의 댓글